GenericEventHandler.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 <iostream>
00041 
00042 #include "Exception.hpp"
00043 #include "PetscTools.hpp"
00044 #include "Timer.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 min_Wtime = milliseconds/1000.0 + Timer::GetElapsedTime();
00081         while (Timer::GetElapsedTime() < min_Wtime)
00082         {
00083             //pause;
00084         }
00085     }
00086 
00093     inline double ConvertWallTimeToMilliseconds(double wallTime)
00094     {
00095         return wallTime*1000.0;
00096     }
00097 
00104     inline double ConvertWallTimeToSeconds(double wallTime)
00105     {
00106         return wallTime;
00107     }
00108 
00109 public:
00110 
00114     static GenericEventHandler<NUM_EVENTS, CONCRETE>* Instance()
00115     {
00116         static CONCRETE inst;
00117         return &inst;
00118     }
00119 
00123     static void Reset()
00124     {
00125         Instance()->ResetImpl();
00126     }
00127 
00133     static void BeginEvent(unsigned event) throw (Exception)
00134     {
00135         Instance()->BeginEventImpl(event);
00136     }
00137 
00143     static void EndEvent(unsigned event)
00144     {
00145         Instance()->EndEventImpl(event);
00146     }
00147 
00155     static double GetElapsedTime(unsigned event)
00156     {
00157         return Instance()->GetElapsedTimeImpl(event);
00158     }
00159 
00168     static void Report()
00169     {
00170         Instance()->ReportImpl();
00171     }
00172 
00176     static void Headings()
00177     {
00178         Instance()->HeadingsImpl();
00179     }
00180 
00184     static void Enable()
00185     {
00186         Instance()->EnableImpl();
00187     }
00188 
00190     static void Disable()
00191     {
00192         Instance()->DisableImpl();
00193     }
00194 
00198     static bool IsEnabled()
00199     {
00200         return Instance()->IsEnabledImpl();
00201     }
00202 
00203 protected:
00204 
00208     GenericEventHandler()
00209     {
00210         mEnabled = true;
00211         mInUse = false;
00212         mWallTime.resize(NUM_EVENTS, 0.0);
00213         mHasBegun.resize(NUM_EVENTS, false);
00214     }
00215 
00216 private:
00217 
00221     void ResetImpl()
00222     {
00223         for (unsigned event=0; event<NUM_EVENTS; event++)
00224         {
00225             mWallTime[event] = 0.0;
00226             mHasBegun[event] = false;
00227         }
00228         Enable();
00229         mInUse = false;
00230     }
00231 
00237     void BeginEventImpl(unsigned event) throw (Exception)
00238     {
00239         if (!mEnabled)
00240         {
00241             return;
00242         }
00243 #ifdef CHASTE_EVENT_BARRIERS
00244         PetscTools::Barrier("BeginEvent");
00245 #endif
00246         mInUse = true;
00247         assert(event<NUM_EVENTS);
00248         // Check that we are recording the total
00249         if (event != NUM_EVENTS-1) // If use <, Intel complains when NUM_EVENTS==1
00250         {
00251             if (!mHasBegun[NUM_EVENTS-1])
00252             {
00253                 // Silently open the "total" event
00254                 BeginEvent(NUM_EVENTS-1);
00255             }
00256         }
00257         if (mHasBegun[event])
00258         {
00259             std::string msg;
00260             msg += "The event associated with the counter for '";
00261             msg += CONCRETE::EventName[event];
00262             msg += "' had already begun when BeginEvent was called.";
00263             std::cerr << msg << std::endl << std::flush;
00264             Disable();
00265             return;
00266         }
00267         mWallTime[event] -= Timer::GetWallTime();
00268         mHasBegun[event] = true;
00269         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00270     }
00271 
00277     void EndEventImpl(unsigned event)
00278     {
00279         assert(event<NUM_EVENTS);
00280         if (!mEnabled)
00281         {
00282             return;
00283         }
00284 #ifdef CHASTE_EVENT_BARRIERS
00285         PetscTools::Barrier("EndEvent");
00286 #endif
00287         if (!mHasBegun[event])
00288         {
00289             std::string msg;
00290             msg += "Error: The event associated with the counter for '";
00291             msg += CONCRETE::EventName[event];
00292             msg += "' had not begun when EndEvent was called.";
00293             EXCEPTION(msg);
00294         }
00295         mWallTime[event] += Timer::GetWallTime();
00296         mHasBegun[event] = false;
00297         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00298     }
00299 
00307     double GetElapsedTimeImpl(unsigned event)
00308     {
00309         assert(event<NUM_EVENTS);
00310         if (!mEnabled)
00311         {
00312             return 0.0;
00313         }
00314         double time;
00315         if (mHasBegun[event])
00316         {
00317             time =  mWallTime[event] + Timer::GetWallTime();
00318         }
00319         else
00320         {
00321             time = mWallTime[event];
00322         }
00323         return ConvertWallTimeToMilliseconds(time);
00324     }
00325 
00334     void ReportImpl()
00335     {
00336         if (!mEnabled)
00337         {
00338             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00339         }
00340         if (!mInUse)
00341         {
00342             EXCEPTION("Asked to report on an event handler which is set to zero.");
00343         }
00344         // Check that all events are finished
00345         for (unsigned event=0; event<NUM_EVENTS; event++)
00346         {
00347             if (mHasBegun[event])
00348             {
00349                 // Silently close event
00350                 EndEvent(event);
00351             }
00352         }
00353         const unsigned top_event = NUM_EVENTS-1;
00354         double total = ConvertWallTimeToSeconds(mWallTime[top_event]);
00355 
00356         // Make the output precision depend on total run time
00357         const char* format;
00358         if (total > 999999.0)      // 11.5 days
00359         {
00360             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00361         }
00362         else if (total > 9999.0)   // 2.7 hours
00363         {
00364             format = "%8.1f ";
00365         }
00366         else
00367         {
00368             format = "%8.3f ";
00369         }
00370 
00371         PetscTools::BeginRoundRobin();
00372         {
00373             std::cout.flush();
00374             if (PetscTools::IsParallel())
00375             {
00376                 // Report the process number at the beginning of the line
00377                 printf("%3u: ", PetscTools::GetMyRank()); //5 chars
00378             }
00379             for (unsigned event=0; event<NUM_EVENTS; event++)
00380             {
00381                 const double secs = ConvertWallTimeToSeconds(mWallTime[event]);
00382                 printf(format, secs);
00383                 printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00384             }
00385             std::cout << "(seconds) \n";
00386         }
00387         PetscTools::EndRoundRobin();
00388 
00389         // If there is a collection of processes then report an average
00390         if (PetscTools::IsParallel() && !PetscTools::IsIsolated())
00391         {
00392             double total_cpu_time[NUM_EVENTS];
00393             MPI_Reduce(&mWallTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_SUM, 0, PetscTools::GetWorld());
00394             if (PetscTools::AmMaster())
00395             {
00396                 total = ConvertWallTimeToSeconds(total_cpu_time[top_event]);
00397                 printf("avg: "); //5 chars
00398                 for (unsigned event=0; event<NUM_EVENTS; event++)
00399                 {
00400                     const double secs = ConvertWallTimeToSeconds(total_cpu_time[event]);
00401                     printf(format, secs/PetscTools::GetNumProcs());
00402                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00403                 }
00404                 std::cout << "(seconds) \n";
00405             }
00406 
00407             double max_cpu_time[NUM_EVENTS];
00408             MPI_Reduce(&mWallTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_MAX, 0, PetscTools::GetWorld());
00409             if (PetscTools::AmMaster())
00410             {
00411                 total = ConvertWallTimeToSeconds(max_cpu_time[top_event]);
00412                 printf("max: "); //5 chars
00413                 for (unsigned event=0; event<NUM_EVENTS; event++)
00414                 {
00415                     const double secs = ConvertWallTimeToSeconds(max_cpu_time[event]);
00416                     printf(format, secs);
00417                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00418                 }
00419                 std::cout << "(seconds) \n";
00420             }
00421         }
00422         std::cout.flush();
00423         PetscTools::Barrier();
00424         std::cout.flush();
00425 
00426         Reset();
00427     }
00428 
00432     void HeadingsImpl()
00433     {
00434         // Make sure that all output (on all processes) is flushed
00435         std::cout.flush();
00436         PetscTools::Barrier();
00437         std::cout.flush();
00438         if (PetscTools::AmMaster())
00439         {
00440             if (PetscTools::IsParallel())
00441             {
00442                 // Report the process number at the beginning of the line
00443                 printf("Proc "); //5 chars
00444             }
00445             for (unsigned event=0; event<NUM_EVENTS; event++)
00446             {
00447                 printf("%15s%2s", CONCRETE::EventName[event], "");
00448             }
00449             std::cout << "\n";
00450             std::cout.flush();
00451         }
00452     }
00453 
00455     void EnableImpl()
00456     {
00457         mEnabled = true;
00458     }
00459 
00461     void DisableImpl()
00462     {
00463         mEnabled = false;
00464     }
00465 
00469     bool IsEnabledImpl()
00470     {
00471         return mEnabled;
00472     }
00473 };
00474 
00475 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated by  doxygen 1.6.2