Chaste Release::3.1
GenericEventHandler.hpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #ifndef GENERICEVENTHANDLER_HPP_
00037 #define GENERICEVENTHANDLER_HPP_
00038 
00039 #include <cassert>
00040 #include <ctime>
00041 #include <iostream>
00042 
00043 #include "Exception.hpp"
00044 #include "PetscTools.hpp"
00045 
00057 template <unsigned NUM_EVENTS, class CONCRETE>
00058 class GenericEventHandler
00059 {
00060     friend class TestGenericEventHandler;
00061     friend class TestCellBasedEventHandler;
00062     friend class TestHeartEventHandler;
00063 
00064 private:
00065 
00066     std::vector<double> mWallTime; 
00067     std::vector<bool> mHasBegun; 
00068     bool mEnabled; 
00069     bool mInUse; 
00078     static inline void MilliSleep(unsigned milliseconds)
00079     {
00080         double start = MPI_Wtime();
00081         double min_Wtime = milliseconds/1000.0 + start;
00082         while (MPI_Wtime() < min_Wtime)
00083         {
00084             //pause;
00085         }
00086     }
00087 
00089     inline double GetWallTime()
00090     {
00091         return MPI_Wtime();
00092     }
00093 
00099     inline double ConvertWallTimeToMilliseconds(double wallTime)
00100     {
00101         return wallTime*1000.0;
00102     }
00103 
00109     inline double ConvertWallTimeToSeconds(double wallTime)
00110     {
00111         return wallTime;
00112     }
00113 
00114 public:
00115 
00119     static GenericEventHandler<NUM_EVENTS, CONCRETE>* Instance()
00120     {
00121         static CONCRETE inst;
00122         return &inst;
00123     }
00124 
00128     static void Reset()
00129     {
00130         Instance()->ResetImpl();
00131     }
00132 
00138     static void BeginEvent(unsigned event) throw (Exception)
00139     {
00140         Instance()->BeginEventImpl(event);
00141     }
00142 
00148     static void EndEvent(unsigned event)
00149     {
00150         Instance()->EndEventImpl(event);
00151     }
00152 
00160     static double GetElapsedTime(unsigned event)
00161     {
00162         return Instance()->GetElapsedTimeImpl(event);
00163     }
00164 
00173     static void Report()
00174     {
00175         Instance()->ReportImpl();
00176     }
00177 
00181     static void Headings()
00182     {
00183         Instance()->HeadingsImpl();
00184     }
00185 
00189     static void Enable()
00190     {
00191         Instance()->EnableImpl();
00192     }
00193 
00195     static void Disable()
00196     {
00197         Instance()->DisableImpl();
00198     }
00199 
00201     static bool IsEnabled()
00202     {
00203         return Instance()->IsEnabledImpl();
00204     }
00205 
00206 protected:
00207 
00211     GenericEventHandler()
00212     {
00213         mEnabled = true;
00214         mInUse = false;
00215         mWallTime.resize(NUM_EVENTS, 0.0);
00216         mHasBegun.resize(NUM_EVENTS, false);
00217     }
00218 
00219 private:
00220 
00224     void ResetImpl()
00225     {
00226         for (unsigned event=0; event<NUM_EVENTS; event++)
00227         {
00228             mWallTime[event] = 0.0;
00229             mHasBegun[event] = false;
00230         }
00231         Enable();
00232         mInUse = false;
00233     }
00234 
00240     void BeginEventImpl(unsigned event) throw (Exception)
00241     {
00242         if (!mEnabled)
00243         {
00244             return;
00245         }
00246 #ifdef CHASTE_EVENT_BARRIERS
00247         PetscTools::Barrier("BeginEvent");
00248 #endif
00249         mInUse = true;
00250         assert(event<NUM_EVENTS);
00251         // Check that we are recording the total
00252         if (event != NUM_EVENTS-1) // If use <, Intel complains when NUM_EVENTS==1
00253         {
00254             if (!mHasBegun[NUM_EVENTS-1])
00255             {
00256                 // Silently open the "total" event
00257                 BeginEvent(NUM_EVENTS-1);
00258             }
00259         }
00260         if (mHasBegun[event])
00261         {
00262             std::string msg;
00263             msg += "The event associated with the counter for '";
00264             msg += CONCRETE::EventName[event];
00265             msg += "' had already begun when BeginEvent was called.";
00266             std::cerr << msg << std::endl << std::flush;
00267             Disable();
00268             return;
00269         }
00270         mWallTime[event] -= GetWallTime();
00271         mHasBegun[event] = true;
00272         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00273     }
00274 
00280     void EndEventImpl(unsigned event)
00281     {
00282         assert(event<NUM_EVENTS);
00283         if (!mEnabled)
00284         {
00285             return;
00286         }
00287 #ifdef CHASTE_EVENT_BARRIERS
00288         PetscTools::Barrier("EndEvent");
00289 #endif
00290         if (!mHasBegun[event])
00291         {
00292             std::string msg;
00293             msg += "Error: The event associated with the counter for '";
00294             msg += CONCRETE::EventName[event];
00295             msg += "' had not begun when EndEvent was called.";
00296             EXCEPTION(msg);
00297         }
00298         mWallTime[event] += GetWallTime();
00299         mHasBegun[event] = false;
00300         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00301     }
00302 
00310     double GetElapsedTimeImpl(unsigned event)
00311     {
00312         assert(event<NUM_EVENTS);
00313         if (!mEnabled)
00314         {
00315             return 0.0;
00316         }
00317         double time;
00318         if (mHasBegun[event])
00319         {
00320             time =  mWallTime[event] + GetWallTime();
00321         }
00322         else
00323         {
00324             time = mWallTime[event];
00325         }
00326         return ConvertWallTimeToMilliseconds(time);
00327     }
00328 
00337     void ReportImpl()
00338     {
00339         if (!mEnabled)
00340         {
00341             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00342         }
00343         if (!mInUse)
00344         {
00345             EXCEPTION("Asked to report on an event handler which is set to zero.");
00346         }
00347         // Check that all events are finished
00348         for (unsigned event=0; event<NUM_EVENTS; event++)
00349         {
00350             if (mHasBegun[event])
00351             {
00352                 // Silently close event
00353                 EndEvent(event);
00354             }
00355         }
00356         const unsigned top_event = NUM_EVENTS-1;
00357         double total = ConvertWallTimeToSeconds(mWallTime[top_event]);
00358 
00359         // Make the output precision depend on total run time
00360         const char* format;
00361         if (total > 999999.0)      // 11.5 days
00362         {
00363             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00364         }
00365         else if (total > 9999.0)   // 2.7 hours
00366         {
00367             format = "%8.1f ";
00368         }
00369         else
00370         {
00371             format = "%8.3f ";
00372         }
00373 
00374         PetscTools::BeginRoundRobin();
00375         {
00376             std::cout.flush();
00377             if (PetscTools::IsParallel())
00378             {
00379                 // Report the process number at the beginning of the line
00380                 printf("%3i: ", PetscTools::GetMyRank()); //5 chars
00381             }
00382             for (unsigned event=0; event<NUM_EVENTS; event++)
00383             {
00384                 const double secs = ConvertWallTimeToSeconds(mWallTime[event]);
00385                 printf(format, secs);
00386                 printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00387             }
00388             std::cout << "(seconds) \n";
00389         }
00390         PetscTools::EndRoundRobin();
00391 
00392         // If there is a collection of processes then report an average
00393         if (PetscTools::IsParallel())
00394         {
00395             double total_cpu_time[NUM_EVENTS];
00396             MPI_Reduce(&mWallTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_SUM, 0, PETSC_COMM_WORLD);
00397             if (PetscTools::AmMaster())
00398             {
00399                 total = ConvertWallTimeToSeconds(total_cpu_time[top_event]);
00400                 printf("avg: "); //5 chars
00401                 for (unsigned event=0; event<NUM_EVENTS; event++)
00402                 {
00403                     const double secs = ConvertWallTimeToSeconds(total_cpu_time[event]);
00404                     printf(format, secs/PetscTools::GetNumProcs());
00405                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00406                 }
00407                 std::cout << "(seconds) \n";
00408             }
00409 
00410             double max_cpu_time[NUM_EVENTS];
00411             MPI_Reduce(&mWallTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_MAX, 0, PETSC_COMM_WORLD);
00412             if (PetscTools::AmMaster())
00413             {
00414                 total = ConvertWallTimeToSeconds(max_cpu_time[top_event]);
00415                 printf("max: "); //5 chars
00416                 for (unsigned event=0; event<NUM_EVENTS; event++)
00417                 {
00418                     const double secs = ConvertWallTimeToSeconds(max_cpu_time[event]);
00419                     printf(format, secs);
00420                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00421                 }
00422                 std::cout << "(seconds) \n";
00423             }
00424         }
00425         std::cout.flush();
00426         PetscTools::Barrier();
00427         std::cout.flush();
00428 
00429         Reset();
00430     }
00431 
00435     void HeadingsImpl()
00436     {
00437         // Make sure that all output (on all processes) is flushed
00438         std::cout.flush();
00439         PetscTools::Barrier();
00440         std::cout.flush();
00441         if (PetscTools::AmMaster())
00442         {
00443             if (PetscTools::IsParallel())
00444             {
00445                 // Report the process number at the beginning of the line
00446                 printf("Proc "); //5 chars
00447             }
00448             for (unsigned event=0; event<NUM_EVENTS; event++)
00449             {
00450                 printf("%15s%2s", CONCRETE::EventName[event], "");
00451             }
00452             std::cout << "\n";
00453             std::cout.flush();
00454         }
00455     }
00456 
00458     void EnableImpl()
00459     {
00460         mEnabled = true;
00461     }
00462 
00464     void DisableImpl()
00465     {
00466         mEnabled = false;
00467     }
00468 
00470     bool IsEnabledImpl()
00471     {
00472         return mEnabled;
00473     }
00474 };
00475 
00476 #endif /*GENERICEVENTHANDLER_HPP_*/