GenericEventHandler.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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     friend class TestCellBasedEventHandler;
00056     friend class TestHeartEventHandler;
00057 
00058 private:
00059     static std::vector<double> mCpuTime; 
00060     static std::vector<bool> mHasBegun; 
00061     static bool mEnabled; 
00062     static bool mInitialised; 
00063     static bool mInUse; 
00072     inline static void MilliSleep(unsigned milliseconds)
00073     {
00074         double start = clock();
00075         double min_ticks = milliseconds*(CLOCKS_PER_SEC/1000.0) + start;
00076         while (clock() < min_ticks)
00077         {
00078             //pause;
00079         }
00080     }
00081 
00083     inline static double GetCpuTime()
00084     {
00085         return clock();
00086     }
00087 
00093     inline static double ConvertTicksToMilliseconds(double clockTicks)
00094     {
00095         return clockTicks/(CLOCKS_PER_SEC/1000.0);
00096     }
00097 
00103     inline static double ConvertTicksToSeconds(double clockTicks)
00104     {
00105         return clockTicks/(CLOCKS_PER_SEC);
00106     }
00107 
00109     inline static void CheckVectorSizes()
00110     {
00111         if (!mInitialised)
00112         {
00113             mCpuTime.resize(NUM_EVENTS, 0.0);
00114             mHasBegun.resize(NUM_EVENTS, false);
00115             mInitialised = true;
00116         }
00117     }
00118 
00119 public:
00120 
00124     static void Reset()
00125     {
00126         CheckVectorSizes();
00127         for (unsigned event=0; event<NUM_EVENTS; event++)
00128         {
00129             mCpuTime[event] = 0.0;
00130             mHasBegun[event] = false;
00131         }
00132         Enable();
00133         mInUse=false;
00134     }
00135 
00141     static void BeginEvent(unsigned event) throw (Exception)
00142     {
00143         if (!mEnabled)
00144         {
00145             return;
00146         }
00147         mInUse = true;
00148         assert(event<NUM_EVENTS);
00149         CheckVectorSizes();
00150         //Check that we are recording the total
00151         if (event<NUM_EVENTS-1)
00152         {
00153             if (!mHasBegun[NUM_EVENTS-1])
00154             {
00155                 //Silently open the "total" event
00156                 BeginEvent(NUM_EVENTS-1);
00157             }
00158         }
00159         if (mHasBegun[event])
00160         {
00161             std::string msg;
00162             msg += "The event associated with the counter for '";
00163             msg += CONCRETE::EventName[event];
00164             msg += "' had already begun when BeginEvent was called.";
00165             std::cerr << msg << std::endl << std::flush;
00166             Disable();
00167             return;
00168         }
00169         mCpuTime[event] -= GetCpuTime();
00170         mHasBegun[event] = true;
00171         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00172     }
00173 
00179     static void EndEvent(unsigned event)
00180     {
00181         assert(event<NUM_EVENTS);
00182         if (!mEnabled)
00183         {
00184             return;
00185         }
00186         CheckVectorSizes();
00187         if (!mHasBegun[event])
00188         {
00189             std::string msg;
00190             msg += "Error: The event associated with the counter for '";
00191             msg += CONCRETE::EventName[event];
00192             msg += "' had not begun when EndEvent was called.";
00193             EXCEPTION(msg);
00194         }
00195         mCpuTime[event] += GetCpuTime();
00196         mHasBegun[event] = false;
00197         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00198     }
00199 
00207     static double GetElapsedTime(unsigned event)
00208     {
00209         assert(event<NUM_EVENTS);
00210         if (!mEnabled)
00211         {
00212             return 0.0;
00213         }
00214         CheckVectorSizes();
00215         double ticks;
00216         if (mHasBegun[event])
00217         {
00218             ticks =  mCpuTime[event] + GetCpuTime();
00219         }
00220         else
00221         {
00222             ticks = mCpuTime[event];
00223         }
00224         return ConvertTicksToMilliseconds(ticks);
00225     }
00226 
00235     static void Report()
00236     {
00237         CheckVectorSizes();
00238 
00239         if (!mEnabled)
00240         {
00241             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00242         }
00243         if (!mInUse)
00244         {
00245             EXCEPTION("Asked to report on an event handler which is set to zero.");
00246         }
00247         //Check that all events are finished
00248         for (unsigned event=0; event<NUM_EVENTS; event++)
00249         {
00250             if (mHasBegun[event])
00251             {
00252                 //Silently close event
00253                 EndEvent(event);
00254             }
00255         }
00256         const unsigned top_event = NUM_EVENTS-1;
00257         double total = ConvertTicksToSeconds(mCpuTime[top_event]);
00258 
00259         // Make the output precision depend on total run time
00260         const char* format;
00261         if (total > 999999.0)      // 11.5 days
00262         {
00263             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00264         }
00265         else if (total > 9999.0)   // 2.7 hours
00266         {
00267             format = "%8.1f ";
00268         }
00269         else
00270         {
00271             format = "%8.3f ";
00272         }
00273 
00274         for (unsigned turn=0; turn<PetscTools::GetNumProcs(); turn++)
00275         {
00276             std::cout.flush();
00277             PetscTools::Barrier();
00278             if (turn == PetscTools::GetMyRank())
00279             {
00280                 if (!PetscTools::IsSequential())
00281                 {
00282                     // Report the process number at the beginning of the line
00283                     printf("%3i: ", turn); //5 chars
00284                 }
00285                 for (unsigned event=0; event<NUM_EVENTS; event++)
00286                 {
00287                     const double secs = ConvertTicksToSeconds(mCpuTime[event]);
00288                     printf(format, secs);
00289                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00290                 }
00291                 std::cout << "(seconds) \n";
00292             }
00293         }
00294 
00295         // If there is a collection of processes then report an average
00296         if (!PetscTools::IsSequential())
00297         {
00298             double total_cpu_time[NUM_EVENTS];
00299             MPI_Reduce(&mCpuTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00300                        MPI_SUM, 0, PETSC_COMM_WORLD);
00301             if (PetscTools::AmMaster())
00302             {
00303                 total = ConvertTicksToSeconds(total_cpu_time[top_event]);
00304                 printf("avg: "); //5 chars
00305                 for (unsigned event=0; event<NUM_EVENTS; event++)
00306                 {
00307                     const double secs = ConvertTicksToSeconds(total_cpu_time[event]);
00308                     printf(format, secs/PetscTools::GetNumProcs());
00309                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00310                 }
00311                 std::cout << "(seconds) \n";
00312             }
00313 
00314             double max_cpu_time[NUM_EVENTS];
00315             MPI_Reduce(&mCpuTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00316                        MPI_MAX, 0, PETSC_COMM_WORLD);
00317             if (PetscTools::AmMaster())
00318             {
00319                 total = ConvertTicksToSeconds(max_cpu_time[top_event]);
00320                 printf("max: "); //5 chars
00321                 for (unsigned event=0; event<NUM_EVENTS; event++)
00322                 {
00323                     const double secs = ConvertTicksToSeconds(max_cpu_time[event]);
00324                     printf(format, secs);
00325                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00326                 }
00327                 std::cout << "(seconds) \n";
00328             }
00329         }
00330         std::cout.flush();
00331         PetscTools::Barrier();
00332         std::cout.flush();
00333 
00334         Reset();
00335     }
00336 
00340     static void Headings()
00341     {
00342         CheckVectorSizes();
00343         // Make sure that all output (on all processes) is flushed
00344         std::cout.flush();
00345         PetscTools::Barrier();
00346         std::cout.flush();
00347         if (PetscTools::AmMaster())
00348         {
00349             if (!PetscTools::IsSequential())
00350             {
00351                 // Report the process number at the beginning of the line
00352                 printf("Proc "); //5 chars
00353             }
00354             for (unsigned event=0; event<NUM_EVENTS; event++)
00355             {
00356                 printf("%15s%2s", CONCRETE::EventName[event], "");
00357             }
00358             std::cout << "\n";
00359             std::cout.flush();
00360         }
00361     }
00362 
00366     static void Enable()
00367     {
00368         CheckVectorSizes();
00369         mEnabled = true;
00370     }
00371 
00373     static void Disable()
00374     {
00375         CheckVectorSizes();
00376         mEnabled = false;
00377     }
00378 
00380     static bool IsEnabled()
00381     {
00382         return mEnabled;
00383     }
00384 };
00385 
00386 template<unsigned NUM_EVENTS, class CONCRETE>
00387 std::vector<double> GenericEventHandler<NUM_EVENTS, CONCRETE>::mCpuTime;
00388 
00389 template<unsigned NUM_EVENTS, class CONCRETE>
00390 std::vector<bool> GenericEventHandler<NUM_EVENTS, CONCRETE>::mHasBegun;
00391 
00392 template<unsigned NUM_EVENTS, class CONCRETE>
00393 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mEnabled = true;
00394 
00395 template<unsigned NUM_EVENTS, class CONCRETE>
00396 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInitialised = false;
00397 
00398 template<unsigned NUM_EVENTS, class CONCRETE>
00399 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInUse = false;
00400 
00401 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated by  doxygen 1.6.2