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 #ifdef CHASTE_EVENT_BARRIERS
00148         PetscTools::Barrier("BeginEvent");
00149 #endif
00150         mInUse = true;
00151         assert(event<NUM_EVENTS);
00152         CheckVectorSizes();
00153         //Check that we are recording the total
00154         if (event<NUM_EVENTS-1)
00155         {
00156             if (!mHasBegun[NUM_EVENTS-1])
00157             {
00158                 //Silently open the "total" event
00159                 BeginEvent(NUM_EVENTS-1);
00160             }
00161         }
00162         if (mHasBegun[event])
00163         {
00164             std::string msg;
00165             msg += "The event associated with the counter for '";
00166             msg += CONCRETE::EventName[event];
00167             msg += "' had already begun when BeginEvent was called.";
00168             std::cerr << msg << std::endl << std::flush;
00169             Disable();
00170             return;
00171         }
00172         mCpuTime[event] -= GetCpuTime();
00173         mHasBegun[event] = true;
00174         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00175     }
00176 
00182     static void EndEvent(unsigned event)
00183     {
00184         assert(event<NUM_EVENTS);
00185         if (!mEnabled)
00186         {
00187             return;
00188         }
00189 #ifdef CHASTE_EVENT_BARRIERS
00190         PetscTools::Barrier("EndEvent");        
00191 #endif
00192         CheckVectorSizes();
00193         if (!mHasBegun[event])
00194         {
00195             std::string msg;
00196             msg += "Error: The event associated with the counter for '";
00197             msg += CONCRETE::EventName[event];
00198             msg += "' had not begun when EndEvent was called.";
00199             EXCEPTION(msg);
00200         }
00201         mCpuTime[event] += GetCpuTime();
00202         mHasBegun[event] = false;
00203         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00204     }
00205 
00213     static double GetElapsedTime(unsigned event)
00214     {
00215         assert(event<NUM_EVENTS);
00216         if (!mEnabled)
00217         {
00218             return 0.0;
00219         }
00220         CheckVectorSizes();
00221         double ticks;
00222         if (mHasBegun[event])
00223         {
00224             ticks =  mCpuTime[event] + GetCpuTime();
00225         }
00226         else
00227         {
00228             ticks = mCpuTime[event];
00229         }
00230         return ConvertTicksToMilliseconds(ticks);
00231     }
00232 
00241     static void Report()
00242     {
00243         CheckVectorSizes();
00244 
00245         if (!mEnabled)
00246         {
00247             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00248         }
00249         if (!mInUse)
00250         {
00251             EXCEPTION("Asked to report on an event handler which is set to zero.");
00252         }
00253         //Check that all events are finished
00254         for (unsigned event=0; event<NUM_EVENTS; event++)
00255         {
00256             if (mHasBegun[event])
00257             {
00258                 //Silently close event
00259                 EndEvent(event);
00260             }
00261         }
00262         const unsigned top_event = NUM_EVENTS-1;
00263         double total = ConvertTicksToSeconds(mCpuTime[top_event]);
00264 
00265         // Make the output precision depend on total run time
00266         const char* format;
00267         if (total > 999999.0)      // 11.5 days
00268         {
00269             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00270         }
00271         else if (total > 9999.0)   // 2.7 hours
00272         {
00273             format = "%8.1f ";
00274         }
00275         else
00276         {
00277             format = "%8.3f ";
00278         }
00279 
00280         for (unsigned turn=0; turn<PetscTools::GetNumProcs(); turn++)
00281         {
00282             std::cout.flush();
00283             PetscTools::Barrier();
00284             if (turn == PetscTools::GetMyRank())
00285             {
00286                 if (!PetscTools::IsSequential())
00287                 {
00288                     // Report the process number at the beginning of the line
00289                     printf("%3i: ", turn); //5 chars
00290                 }
00291                 for (unsigned event=0; event<NUM_EVENTS; event++)
00292                 {
00293                     const double secs = ConvertTicksToSeconds(mCpuTime[event]);
00294                     printf(format, secs);
00295                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00296                 }
00297                 std::cout << "(seconds) \n";
00298             }
00299         }
00300 
00301         // If there is a collection of processes then report an average
00302         if (!PetscTools::IsSequential())
00303         {
00304             double total_cpu_time[NUM_EVENTS];
00305             MPI_Reduce(&mCpuTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00306                        MPI_SUM, 0, PETSC_COMM_WORLD);
00307             if (PetscTools::AmMaster())
00308             {
00309                 total = ConvertTicksToSeconds(total_cpu_time[top_event]);
00310                 printf("avg: "); //5 chars
00311                 for (unsigned event=0; event<NUM_EVENTS; event++)
00312                 {
00313                     const double secs = ConvertTicksToSeconds(total_cpu_time[event]);
00314                     printf(format, secs/PetscTools::GetNumProcs());
00315                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00316                 }
00317                 std::cout << "(seconds) \n";
00318             }
00319 
00320             double max_cpu_time[NUM_EVENTS];
00321             MPI_Reduce(&mCpuTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00322                        MPI_MAX, 0, PETSC_COMM_WORLD);
00323             if (PetscTools::AmMaster())
00324             {
00325                 total = ConvertTicksToSeconds(max_cpu_time[top_event]);
00326                 printf("max: "); //5 chars
00327                 for (unsigned event=0; event<NUM_EVENTS; event++)
00328                 {
00329                     const double secs = ConvertTicksToSeconds(max_cpu_time[event]);
00330                     printf(format, secs);
00331                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00332                 }
00333                 std::cout << "(seconds) \n";
00334             }
00335         }
00336         std::cout.flush();
00337         PetscTools::Barrier();
00338         std::cout.flush();
00339 
00340         Reset();
00341     }
00342 
00346     static void Headings()
00347     {
00348         CheckVectorSizes();
00349         // Make sure that all output (on all processes) is flushed
00350         std::cout.flush();
00351         PetscTools::Barrier();
00352         std::cout.flush();
00353         if (PetscTools::AmMaster())
00354         {
00355             if (!PetscTools::IsSequential())
00356             {
00357                 // Report the process number at the beginning of the line
00358                 printf("Proc "); //5 chars
00359             }
00360             for (unsigned event=0; event<NUM_EVENTS; event++)
00361             {
00362                 printf("%15s%2s", CONCRETE::EventName[event], "");
00363             }
00364             std::cout << "\n";
00365             std::cout.flush();
00366         }
00367     }
00368 
00372     static void Enable()
00373     {
00374         CheckVectorSizes();
00375         mEnabled = true;
00376     }
00377 
00379     static void Disable()
00380     {
00381         CheckVectorSizes();
00382         mEnabled = false;
00383     }
00384 
00386     static bool IsEnabled()
00387     {
00388         return mEnabled;
00389     }
00390 };
00391 
00392 template<unsigned NUM_EVENTS, class CONCRETE>
00393 std::vector<double> GenericEventHandler<NUM_EVENTS, CONCRETE>::mCpuTime;
00394 
00395 template<unsigned NUM_EVENTS, class CONCRETE>
00396 std::vector<bool> GenericEventHandler<NUM_EVENTS, CONCRETE>::mHasBegun;
00397 
00398 template<unsigned NUM_EVENTS, class CONCRETE>
00399 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mEnabled = true;
00400 
00401 template<unsigned NUM_EVENTS, class CONCRETE>
00402 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInitialised = false;
00403 
00404 template<unsigned NUM_EVENTS, class CONCRETE>
00405 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInUse = false;
00406 
00407 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5