GenericEventHandler.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
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     std::vector<double> mWallTime; 
00060     std::vector<bool> mHasBegun; 
00061     bool mEnabled; 
00062     bool mInUse; 
00071     static inline void MilliSleep(unsigned milliseconds)
00072     {
00073         double start = MPI_Wtime();
00074         double min_Wtime = milliseconds/1000.0 + start;
00075         while (MPI_Wtime() < min_Wtime)
00076         {
00077             //pause;
00078         }
00079     }
00080 
00082     inline double GetWallTime()
00083     {
00084         return MPI_Wtime();
00085     }
00086 
00092     inline double ConvertWallTimeToMilliseconds(double wallTime)
00093     {
00094         return wallTime*1000.0;
00095     }
00096 
00102     inline double ConvertWallTimeToSeconds(double wallTime)
00103     {
00104         return wallTime;
00105     }
00106 
00107 public:
00111     static GenericEventHandler<NUM_EVENTS, CONCRETE>* Instance()
00112     {
00113         static CONCRETE inst;
00114         return &inst;
00115     }
00116 
00120     static void Reset()
00121     {
00122         Instance()->ResetImpl();
00123     }
00124 
00130     static void BeginEvent(unsigned event) throw (Exception)
00131     {
00132         Instance()->BeginEventImpl(event);
00133     }
00134 
00140     static void EndEvent(unsigned event)
00141     {
00142         Instance()->EndEventImpl(event);
00143     }
00144 
00152     static double GetElapsedTime(unsigned event)
00153     {
00154         return Instance()->GetElapsedTimeImpl(event);
00155     }
00156 
00165     static void Report()
00166     {
00167         Instance()->ReportImpl();
00168     }
00169 
00173     static void Headings()
00174     {
00175         Instance()->HeadingsImpl();
00176     }
00177 
00181     static void Enable()
00182     {
00183         Instance()->EnableImpl();
00184     }
00185 
00187     static void Disable()
00188     {
00189         Instance()->DisableImpl();
00190     }
00191 
00193     static bool IsEnabled()
00194     {
00195         return Instance()->IsEnabledImpl();
00196     }
00197 
00198 protected:
00202     GenericEventHandler()
00203     {
00204         mEnabled = true;
00205         mInUse = false;
00206         mWallTime.resize(NUM_EVENTS, 0.0);
00207         mHasBegun.resize(NUM_EVENTS, false);
00208     }
00209 
00210 private:
00214     void ResetImpl()
00215     {
00216         for (unsigned event=0; event<NUM_EVENTS; event++)
00217         {
00218             mWallTime[event] = 0.0;
00219             mHasBegun[event] = false;
00220         }
00221         Enable();
00222         mInUse=false;
00223     }
00224 
00230     void BeginEventImpl(unsigned event) throw (Exception)
00231     {
00232         if (!mEnabled)
00233         {
00234             return;
00235         }
00236 #ifdef CHASTE_EVENT_BARRIERS
00237         PetscTools::Barrier("BeginEvent");
00238 #endif
00239         mInUse = true;
00240         assert(event<NUM_EVENTS);
00241         //Check that we are recording the total
00242         if (event != NUM_EVENTS-1) // If use <, Intel complains when NUM_EVENTS==1
00243         {
00244             if (!mHasBegun[NUM_EVENTS-1])
00245             {
00246                 //Silently open the "total" event
00247                 BeginEvent(NUM_EVENTS-1);
00248             }
00249         }
00250         if (mHasBegun[event])
00251         {
00252             std::string msg;
00253             msg += "The event associated with the counter for '";
00254             msg += CONCRETE::EventName[event];
00255             msg += "' had already begun when BeginEvent was called.";
00256             std::cerr << msg << std::endl << std::flush;
00257             Disable();
00258             return;
00259         }
00260         mWallTime[event] -= GetWallTime();
00261         mHasBegun[event] = true;
00262         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00263     }
00264 
00270     void EndEventImpl(unsigned event)
00271     {
00272         assert(event<NUM_EVENTS);
00273         if (!mEnabled)
00274         {
00275             return;
00276         }
00277 #ifdef CHASTE_EVENT_BARRIERS
00278         PetscTools::Barrier("EndEvent");
00279 #endif
00280         if (!mHasBegun[event])
00281         {
00282             std::string msg;
00283             msg += "Error: The event associated with the counter for '";
00284             msg += CONCRETE::EventName[event];
00285             msg += "' had not begun when EndEvent was called.";
00286             EXCEPTION(msg);
00287         }
00288         mWallTime[event] += GetWallTime();
00289         mHasBegun[event] = false;
00290         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00291     }
00292 
00300     double GetElapsedTimeImpl(unsigned event)
00301     {
00302         assert(event<NUM_EVENTS);
00303         if (!mEnabled)
00304         {
00305             return 0.0;
00306         }
00307         double time;
00308         if (mHasBegun[event])
00309         {
00310             time =  mWallTime[event] + GetWallTime();
00311         }
00312         else
00313         {
00314             time = mWallTime[event];
00315         }
00316         return ConvertWallTimeToMilliseconds(time);
00317     }
00318 
00327     void ReportImpl()
00328     {
00329         if (!mEnabled)
00330         {
00331             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00332         }
00333         if (!mInUse)
00334         {
00335             EXCEPTION("Asked to report on an event handler which is set to zero.");
00336         }
00337         //Check that all events are finished
00338         for (unsigned event=0; event<NUM_EVENTS; event++)
00339         {
00340             if (mHasBegun[event])
00341             {
00342                 //Silently close event
00343                 EndEvent(event);
00344             }
00345         }
00346         const unsigned top_event = NUM_EVENTS-1;
00347         double total = ConvertWallTimeToSeconds(mWallTime[top_event]);
00348 
00349         // Make the output precision depend on total run time
00350         const char* format;
00351         if (total > 999999.0)      // 11.5 days
00352         {
00353             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00354         }
00355         else if (total > 9999.0)   // 2.7 hours
00356         {
00357             format = "%8.1f ";
00358         }
00359         else
00360         {
00361             format = "%8.3f ";
00362         }
00363 
00364         PetscTools::BeginRoundRobin();
00365         {
00366             std::cout.flush();
00367             if (PetscTools::IsParallel())
00368             {
00369                 // Report the process number at the beginning of the line
00370                 printf("%3i: ", PetscTools::GetMyRank()); //5 chars
00371             }
00372             for (unsigned event=0; event<NUM_EVENTS; event++)
00373             {
00374                 const double secs = ConvertWallTimeToSeconds(mWallTime[event]);
00375                 printf(format, secs);
00376                 printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00377             }
00378             std::cout << "(seconds) \n";
00379         }
00380         PetscTools::EndRoundRobin();
00381 
00382         // If there is a collection of processes then report an average
00383         if (PetscTools::IsParallel())
00384         {
00385             double total_cpu_time[NUM_EVENTS];
00386             MPI_Reduce(&mWallTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00387                        MPI_SUM, 0, PETSC_COMM_WORLD);
00388             if (PetscTools::AmMaster())
00389             {
00390                 total = ConvertWallTimeToSeconds(total_cpu_time[top_event]);
00391                 printf("avg: "); //5 chars
00392                 for (unsigned event=0; event<NUM_EVENTS; event++)
00393                 {
00394                     const double secs = ConvertWallTimeToSeconds(total_cpu_time[event]);
00395                     printf(format, secs/PetscTools::GetNumProcs());
00396                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00397                 }
00398                 std::cout << "(seconds) \n";
00399             }
00400 
00401             double max_cpu_time[NUM_EVENTS];
00402             MPI_Reduce(&mWallTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00403                        MPI_MAX, 0, PETSC_COMM_WORLD);
00404             if (PetscTools::AmMaster())
00405             {
00406                 total = ConvertWallTimeToSeconds(max_cpu_time[top_event]);
00407                 printf("max: "); //5 chars
00408                 for (unsigned event=0; event<NUM_EVENTS; event++)
00409                 {
00410                     const double secs = ConvertWallTimeToSeconds(max_cpu_time[event]);
00411                     printf(format, secs);
00412                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00413                 }
00414                 std::cout << "(seconds) \n";
00415             }
00416         }
00417         std::cout.flush();
00418         PetscTools::Barrier();
00419         std::cout.flush();
00420 
00421         Reset();
00422     }
00423 
00427     void HeadingsImpl()
00428     {
00429         // Make sure that all output (on all processes) is flushed
00430         std::cout.flush();
00431         PetscTools::Barrier();
00432         std::cout.flush();
00433         if (PetscTools::AmMaster())
00434         {
00435             if (PetscTools::IsParallel())
00436             {
00437                 // Report the process number at the beginning of the line
00438                 printf("Proc "); //5 chars
00439             }
00440             for (unsigned event=0; event<NUM_EVENTS; event++)
00441             {
00442                 printf("%15s%2s", CONCRETE::EventName[event], "");
00443             }
00444             std::cout << "\n";
00445             std::cout.flush();
00446         }
00447     }
00448 
00452     void EnableImpl()
00453     {
00454         mEnabled = true;
00455     }
00456 
00458     void DisableImpl()
00459     {
00460         mEnabled = false;
00461     }
00462 
00464     bool IsEnabledImpl()
00465     {
00466         return mEnabled;
00467     }
00468 };
00469 
00470 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated on Tue May 31 14:31:41 2011 for Chaste by  doxygen 1.5.5