GenericEventHandler.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 
00030 #ifndef GENERICEVENTHANDLER_HPP_
00031 #define GENERICEVENTHANDLER_HPP_
00032 
00033 #include <cassert>
00034 #include <ctime>
00035 #include <iostream>
00036 
00037 #include "Exception.hpp"
00038 #include "PetscTools.hpp"
00039 
00051 template <unsigned NUM_EVENTS, class CONCRETE>
00052 class GenericEventHandler
00053 {
00054     friend class TestGenericEventHandler;
00055 private:
00056     static std::vector<double> mCpuTime; 
00057     static std::vector<bool> mHasBegun; 
00058     static bool mEnabled; 
00059     static bool mInitialised; 
00060     static bool mInUse; 
00062     inline static double GetCpuTime()
00063     {
00064         return clock();
00065     }
00066 
00072     inline static double ConvertTicksToMilliseconds(double clockTicks)
00073     {
00074         return clockTicks/(CLOCKS_PER_SEC/1000.0);
00075     }
00076 
00082     inline static double ConvertTicksToSeconds(double clockTicks)
00083     {
00084         return clockTicks/(CLOCKS_PER_SEC);
00085     }
00086 
00088     inline static void CheckVectorSizes()
00089     {
00090         if (!mInitialised)
00091         {
00092             mCpuTime.resize(NUM_EVENTS, 0.0);
00093             mHasBegun.resize(NUM_EVENTS, false);
00094             mInitialised = true;
00095         }
00096     }
00097 
00098 public:
00099 
00103     static void Reset()
00104     {
00105         CheckVectorSizes();
00106         for (unsigned event=0; event<NUM_EVENTS; event++)
00107         {
00108             mCpuTime[event] = 0.0;
00109             mHasBegun[event] = false;
00110         }
00111         Enable();
00112         mInUse=false;
00113     }
00114 
00120     static void BeginEvent(unsigned event) throw (Exception)
00121     {
00122         if (!mEnabled)
00123         {
00124             return;
00125         }
00126         mInUse = true;
00127         assert(event<NUM_EVENTS);
00128         CheckVectorSizes();
00129         //Check that we are recording the total
00130         if (event<NUM_EVENTS-1)
00131         {
00132             if (!mHasBegun[NUM_EVENTS-1])
00133             {
00134                 //Silently open the "total" event
00135                 BeginEvent(NUM_EVENTS-1);
00136             }
00137         }
00138         if (mHasBegun[event])
00139         {
00140             std::string msg;
00141             msg += "The event associated with the counter for '";
00142             msg += CONCRETE::EventName[event];
00143             msg += "' had already begun when BeginEvent was called.";
00144             std::cerr << msg << std::endl << std::flush;
00145             Disable();
00146             return;
00147         }
00148         mCpuTime[event] -= GetCpuTime();
00149         mHasBegun[event] = true;
00150         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00151     }
00152 
00158     static void EndEvent(unsigned event)
00159     {
00160         assert(event<NUM_EVENTS);
00161         if (!mEnabled)
00162         {
00163             return;
00164         }
00165         CheckVectorSizes();
00166         if (!mHasBegun[event])
00167         {
00168             std::string msg;
00169             msg += "Error: The event associated with the counter for '";
00170             msg += CONCRETE::EventName[event];
00171             msg += "' had not begun when EndEvent was called.";
00172             EXCEPTION(msg);
00173         }
00174         mCpuTime[event] += GetCpuTime();
00175         mHasBegun[event] = false;
00176         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00177     }
00178 
00186     static double GetElapsedTime(unsigned event)
00187     {
00188         assert(event<NUM_EVENTS);
00189         if (!mEnabled)
00190         {
00191             return 0.0;
00192         }
00193         CheckVectorSizes();
00194         double ticks;
00195         if (mHasBegun[event])
00196         {
00197             ticks =  mCpuTime[event] + GetCpuTime();
00198         }
00199         else
00200         {
00201             ticks = mCpuTime[event];
00202         }
00203         return ConvertTicksToMilliseconds(ticks);
00204     }
00205 
00214     static void Report()
00215     {
00216         CheckVectorSizes();
00217 
00218         if (!mEnabled)
00219         {
00220             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00221         }
00222         if (!mInUse)
00223         {
00224             EXCEPTION("Asked to report on an event handler which is set to zero.");
00225         }
00226         //Check that all events are finished
00227         for (unsigned event=0; event<NUM_EVENTS; event++)
00228         {
00229             if (mHasBegun[event])
00230             {
00231                 //Silently close event
00232                 EndEvent(event);
00233             }
00234         }
00235         const unsigned top_event = NUM_EVENTS-1;
00236         double total = ConvertTicksToSeconds(mCpuTime[top_event]);
00237 
00238         // Make the output precision depend on total run time
00239         const char* format;
00240         if (total > 999999.0)      // 11.5 days
00241         {
00242             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00243         }
00244         else if (total > 9999.0)   // 2.7 hours
00245         {
00246             format = "%8.1f ";
00247         }
00248         else
00249         {
00250             format = "%8.3f ";
00251         }
00252 
00253         for (unsigned turn=0; turn<PetscTools::GetNumProcs(); turn++)
00254         {
00255             std::cout.flush();
00256             PetscTools::Barrier();
00257             if (turn == PetscTools::GetMyRank())
00258             {
00259                 if (!PetscTools::IsSequential())
00260                 {
00261                     // Report the process number at the beginning of the line
00262                     printf("%3i: ", turn); //5 chars
00263                 }
00264                 for (unsigned event=0; event<NUM_EVENTS; event++)
00265                 {
00266                     const double secs = ConvertTicksToSeconds(mCpuTime[event]);
00267                     printf(format, secs);
00268                     printf("(%3.0f%%)  ", secs/total*100.0);
00269                 }
00270                 std::cout << "(seconds) \n";
00271             }
00272         }
00273 
00274         // If there is a collection of processes then report an average
00275         if (!PetscTools::IsSequential())
00276         {
00277             double total_cpu_time[NUM_EVENTS];
00278             MPI_Reduce(&mCpuTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00279                        MPI_SUM, 0, PETSC_COMM_WORLD);
00280             if (PetscTools::AmMaster())
00281             {
00282                 total = ConvertTicksToSeconds(total_cpu_time[top_event]);
00283                 printf("avg: "); //5 chars
00284                 for (unsigned event=0; event<NUM_EVENTS; event++)
00285                 {
00286                     const double secs = ConvertTicksToSeconds(total_cpu_time[event]);
00287                     printf(format, secs/PetscTools::GetNumProcs());
00288                     printf("(%3.0f%%)  ", secs/total*100.0);
00289                 }
00290                 std::cout << "(seconds) \n";
00291             }
00292 
00293             double max_cpu_time[NUM_EVENTS];
00294             MPI_Reduce(&mCpuTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00295                        MPI_MAX, 0, PETSC_COMM_WORLD);
00296             if (PetscTools::AmMaster())
00297             {
00298                 total = ConvertTicksToSeconds(max_cpu_time[top_event]);
00299                 printf("max: "); //5 chars
00300                 for (unsigned event=0; event<NUM_EVENTS; event++)
00301                 {
00302                     const double secs = ConvertTicksToSeconds(max_cpu_time[event]);
00303                     printf(format, secs);
00304                     printf("(%3.0f%%)  ", secs/total*100.0);
00305                 }
00306                 std::cout << "(seconds) \n";
00307             }
00308         }
00309         std::cout.flush();
00310         PetscTools::Barrier();
00311         std::cout.flush();
00312 
00313         Reset();
00314     }
00315 
00319     static void Headings()
00320     {
00321         CheckVectorSizes();
00322         // Make sure that all output (on all processes) is flushed
00323         std::cout.flush();
00324         PetscTools::Barrier();
00325         std::cout.flush();
00326         if (PetscTools::AmMaster())
00327         {
00328             if (!PetscTools::IsSequential())
00329             {
00330                 // Report the process number at the beginning of the line
00331                 printf("Proc "); //5 chars
00332             }
00333             for (unsigned event=0; event<NUM_EVENTS; event++)
00334             {
00335                 printf("%15s%2s", CONCRETE::EventName[event], "");
00336             }
00337             std::cout << "\n";
00338             std::cout.flush();
00339         }
00340     }
00341 
00345     static void Enable()
00346     {
00347         CheckVectorSizes();
00348         mEnabled = true;
00349     }
00350 
00352     static void Disable()
00353     {
00354         CheckVectorSizes();
00355         mEnabled = false;
00356     }
00357 
00359     static bool IsEnabled()
00360     {
00361         return mEnabled;
00362     }
00363 };
00364 
00365 template<unsigned NUM_EVENTS, class CONCRETE>
00366 std::vector<double> GenericEventHandler<NUM_EVENTS, CONCRETE>::mCpuTime;
00367 
00368 template<unsigned NUM_EVENTS, class CONCRETE>
00369 std::vector<bool> GenericEventHandler<NUM_EVENTS, CONCRETE>::mHasBegun;
00370 
00371 template<unsigned NUM_EVENTS, class CONCRETE>
00372 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mEnabled = true;
00373 
00374 template<unsigned NUM_EVENTS, class CONCRETE>
00375 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInitialised = false;
00376 
00377 template<unsigned NUM_EVENTS, class CONCRETE>
00378 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInUse = false;
00379 
00380 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated on Tue Aug 4 16:10:21 2009 for Chaste by  doxygen 1.5.5