GenericEventHandler.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2014, 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 
00100     inline double ConvertWallTimeToMilliseconds(double wallTime)
00101     {
00102         return wallTime*1000.0;
00103     }
00104 
00111     inline double ConvertWallTimeToSeconds(double wallTime)
00112     {
00113         return wallTime;
00114     }
00115 
00116 public:
00117 
00121     static GenericEventHandler<NUM_EVENTS, CONCRETE>* Instance()
00122     {
00123         static CONCRETE inst;
00124         return &inst;
00125     }
00126 
00130     static void Reset()
00131     {
00132         Instance()->ResetImpl();
00133     }
00134 
00140     static void BeginEvent(unsigned event) throw (Exception)
00141     {
00142         Instance()->BeginEventImpl(event);
00143     }
00144 
00150     static void EndEvent(unsigned event)
00151     {
00152         Instance()->EndEventImpl(event);
00153     }
00154 
00162     static double GetElapsedTime(unsigned event)
00163     {
00164         return Instance()->GetElapsedTimeImpl(event);
00165     }
00166 
00175     static void Report()
00176     {
00177         Instance()->ReportImpl();
00178     }
00179 
00183     static void Headings()
00184     {
00185         Instance()->HeadingsImpl();
00186     }
00187 
00191     static void Enable()
00192     {
00193         Instance()->EnableImpl();
00194     }
00195 
00197     static void Disable()
00198     {
00199         Instance()->DisableImpl();
00200     }
00201 
00205     static bool IsEnabled()
00206     {
00207         return Instance()->IsEnabledImpl();
00208     }
00209 
00210 protected:
00211 
00215     GenericEventHandler()
00216     {
00217         mEnabled = true;
00218         mInUse = false;
00219         mWallTime.resize(NUM_EVENTS, 0.0);
00220         mHasBegun.resize(NUM_EVENTS, false);
00221     }
00222 
00223 private:
00224 
00228     void ResetImpl()
00229     {
00230         for (unsigned event=0; event<NUM_EVENTS; event++)
00231         {
00232             mWallTime[event] = 0.0;
00233             mHasBegun[event] = false;
00234         }
00235         Enable();
00236         mInUse = false;
00237     }
00238 
00244     void BeginEventImpl(unsigned event) throw (Exception)
00245     {
00246         if (!mEnabled)
00247         {
00248             return;
00249         }
00250 #ifdef CHASTE_EVENT_BARRIERS
00251         PetscTools::Barrier("BeginEvent");
00252 #endif
00253         mInUse = true;
00254         assert(event<NUM_EVENTS);
00255         // Check that we are recording the total
00256         if (event != NUM_EVENTS-1) // If use <, Intel complains when NUM_EVENTS==1
00257         {
00258             if (!mHasBegun[NUM_EVENTS-1])
00259             {
00260                 // Silently open the "total" event
00261                 BeginEvent(NUM_EVENTS-1);
00262             }
00263         }
00264         if (mHasBegun[event])
00265         {
00266             std::string msg;
00267             msg += "The event associated with the counter for '";
00268             msg += CONCRETE::EventName[event];
00269             msg += "' had already begun when BeginEvent was called.";
00270             std::cerr << msg << std::endl << std::flush;
00271             Disable();
00272             return;
00273         }
00274         mWallTime[event] -= GetWallTime();
00275         mHasBegun[event] = true;
00276         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00277     }
00278 
00284     void EndEventImpl(unsigned event)
00285     {
00286         assert(event<NUM_EVENTS);
00287         if (!mEnabled)
00288         {
00289             return;
00290         }
00291 #ifdef CHASTE_EVENT_BARRIERS
00292         PetscTools::Barrier("EndEvent");
00293 #endif
00294         if (!mHasBegun[event])
00295         {
00296             std::string msg;
00297             msg += "Error: The event associated with the counter for '";
00298             msg += CONCRETE::EventName[event];
00299             msg += "' had not begun when EndEvent was called.";
00300             EXCEPTION(msg);
00301         }
00302         mWallTime[event] += GetWallTime();
00303         mHasBegun[event] = false;
00304         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00305     }
00306 
00314     double GetElapsedTimeImpl(unsigned event)
00315     {
00316         assert(event<NUM_EVENTS);
00317         if (!mEnabled)
00318         {
00319             return 0.0;
00320         }
00321         double time;
00322         if (mHasBegun[event])
00323         {
00324             time =  mWallTime[event] + GetWallTime();
00325         }
00326         else
00327         {
00328             time = mWallTime[event];
00329         }
00330         return ConvertWallTimeToMilliseconds(time);
00331     }
00332 
00341     void ReportImpl()
00342     {
00343         if (!mEnabled)
00344         {
00345             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00346         }
00347         if (!mInUse)
00348         {
00349             EXCEPTION("Asked to report on an event handler which is set to zero.");
00350         }
00351         // Check that all events are finished
00352         for (unsigned event=0; event<NUM_EVENTS; event++)
00353         {
00354             if (mHasBegun[event])
00355             {
00356                 // Silently close event
00357                 EndEvent(event);
00358             }
00359         }
00360         const unsigned top_event = NUM_EVENTS-1;
00361         double total = ConvertWallTimeToSeconds(mWallTime[top_event]);
00362 
00363         // Make the output precision depend on total run time
00364         const char* format;
00365         if (total > 999999.0)      // 11.5 days
00366         {
00367             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00368         }
00369         else if (total > 9999.0)   // 2.7 hours
00370         {
00371             format = "%8.1f ";
00372         }
00373         else
00374         {
00375             format = "%8.3f ";
00376         }
00377 
00378         PetscTools::BeginRoundRobin();
00379         {
00380             std::cout.flush();
00381             if (PetscTools::IsParallel())
00382             {
00383                 // Report the process number at the beginning of the line
00384                 printf("%3u: ", PetscTools::GetMyRank()); //5 chars
00385             }
00386             for (unsigned event=0; event<NUM_EVENTS; event++)
00387             {
00388                 const double secs = ConvertWallTimeToSeconds(mWallTime[event]);
00389                 printf(format, secs);
00390                 printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00391             }
00392             std::cout << "(seconds) \n";
00393         }
00394         PetscTools::EndRoundRobin();
00395 
00396         // If there is a collection of processes then report an average
00397         if (PetscTools::IsParallel() && !PetscTools::IsIsolated())
00398         {
00399             double total_cpu_time[NUM_EVENTS];
00400             MPI_Reduce(&mWallTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_SUM, 0, PetscTools::GetWorld());
00401             if (PetscTools::AmMaster())
00402             {
00403                 total = ConvertWallTimeToSeconds(total_cpu_time[top_event]);
00404                 printf("avg: "); //5 chars
00405                 for (unsigned event=0; event<NUM_EVENTS; event++)
00406                 {
00407                     const double secs = ConvertWallTimeToSeconds(total_cpu_time[event]);
00408                     printf(format, secs/PetscTools::GetNumProcs());
00409                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00410                 }
00411                 std::cout << "(seconds) \n";
00412             }
00413 
00414             double max_cpu_time[NUM_EVENTS];
00415             MPI_Reduce(&mWallTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_MAX, 0, PetscTools::GetWorld());
00416             if (PetscTools::AmMaster())
00417             {
00418                 total = ConvertWallTimeToSeconds(max_cpu_time[top_event]);
00419                 printf("max: "); //5 chars
00420                 for (unsigned event=0; event<NUM_EVENTS; event++)
00421                 {
00422                     const double secs = ConvertWallTimeToSeconds(max_cpu_time[event]);
00423                     printf(format, secs);
00424                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00425                 }
00426                 std::cout << "(seconds) \n";
00427             }
00428         }
00429         std::cout.flush();
00430         PetscTools::Barrier();
00431         std::cout.flush();
00432 
00433         Reset();
00434     }
00435 
00439     void HeadingsImpl()
00440     {
00441         // Make sure that all output (on all processes) is flushed
00442         std::cout.flush();
00443         PetscTools::Barrier();
00444         std::cout.flush();
00445         if (PetscTools::AmMaster())
00446         {
00447             if (PetscTools::IsParallel())
00448             {
00449                 // Report the process number at the beginning of the line
00450                 printf("Proc "); //5 chars
00451             }
00452             for (unsigned event=0; event<NUM_EVENTS; event++)
00453             {
00454                 printf("%15s%2s", CONCRETE::EventName[event], "");
00455             }
00456             std::cout << "\n";
00457             std::cout.flush();
00458         }
00459     }
00460 
00462     void EnableImpl()
00463     {
00464         mEnabled = true;
00465     }
00466 
00468     void DisableImpl()
00469     {
00470         mEnabled = false;
00471     }
00472 
00476     bool IsEnabledImpl()
00477     {
00478         return mEnabled;
00479     }
00480 };
00481 
00482 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated by  doxygen 1.6.2