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 #ifndef GENERICEVENTHANDLER_HPP_
00030 #define GENERICEVENTHANDLER_HPP_
00031 
00032 #include <cassert>
00033 #include <ctime>
00034 #include <iostream>
00035 
00036 #include "Exception.hpp"
00037 #include "PetscTools.hpp"
00038 
00050 template <unsigned NUM_EVENTS, class CONCRETE>
00051 class GenericEventHandler
00052 {
00053     friend class TestGenericEventHandler;
00054     friend class TestCellBasedEventHandler;
00055     friend class TestHeartEventHandler;
00056 
00057 private:
00058 
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:
00108 
00112     static GenericEventHandler<NUM_EVENTS, CONCRETE>* Instance()
00113     {
00114         static CONCRETE inst;
00115         return &inst;
00116     }
00117 
00121     static void Reset()
00122     {
00123         Instance()->ResetImpl();
00124     }
00125 
00131     static void BeginEvent(unsigned event) throw (Exception)
00132     {
00133         Instance()->BeginEventImpl(event);
00134     }
00135 
00141     static void EndEvent(unsigned event)
00142     {
00143         Instance()->EndEventImpl(event);
00144     }
00145 
00153     static double GetElapsedTime(unsigned event)
00154     {
00155         return Instance()->GetElapsedTimeImpl(event);
00156     }
00157 
00166     static void Report()
00167     {
00168         Instance()->ReportImpl();
00169     }
00170 
00174     static void Headings()
00175     {
00176         Instance()->HeadingsImpl();
00177     }
00178 
00182     static void Enable()
00183     {
00184         Instance()->EnableImpl();
00185     }
00186 
00188     static void Disable()
00189     {
00190         Instance()->DisableImpl();
00191     }
00192 
00194     static bool IsEnabled()
00195     {
00196         return Instance()->IsEnabledImpl();
00197     }
00198 
00199 protected:
00200 
00204     GenericEventHandler()
00205     {
00206         mEnabled = true;
00207         mInUse = false;
00208         mWallTime.resize(NUM_EVENTS, 0.0);
00209         mHasBegun.resize(NUM_EVENTS, false);
00210     }
00211 
00212 private:
00213 
00217     void ResetImpl()
00218     {
00219         for (unsigned event=0; event<NUM_EVENTS; event++)
00220         {
00221             mWallTime[event] = 0.0;
00222             mHasBegun[event] = false;
00223         }
00224         Enable();
00225         mInUse = false;
00226     }
00227 
00233     void BeginEventImpl(unsigned event) throw (Exception)
00234     {
00235         if (!mEnabled)
00236         {
00237             return;
00238         }
00239 #ifdef CHASTE_EVENT_BARRIERS
00240         PetscTools::Barrier("BeginEvent");
00241 #endif
00242         mInUse = true;
00243         assert(event<NUM_EVENTS);
00244         // Check that we are recording the total
00245         if (event != NUM_EVENTS-1) // If use <, Intel complains when NUM_EVENTS==1
00246         {
00247             if (!mHasBegun[NUM_EVENTS-1])
00248             {
00249                 // Silently open the "total" event
00250                 BeginEvent(NUM_EVENTS-1);
00251             }
00252         }
00253         if (mHasBegun[event])
00254         {
00255             std::string msg;
00256             msg += "The event associated with the counter for '";
00257             msg += CONCRETE::EventName[event];
00258             msg += "' had already begun when BeginEvent was called.";
00259             std::cerr << msg << std::endl << std::flush;
00260             Disable();
00261             return;
00262         }
00263         mWallTime[event] -= GetWallTime();
00264         mHasBegun[event] = true;
00265         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00266     }
00267 
00273     void EndEventImpl(unsigned event)
00274     {
00275         assert(event<NUM_EVENTS);
00276         if (!mEnabled)
00277         {
00278             return;
00279         }
00280 #ifdef CHASTE_EVENT_BARRIERS
00281         PetscTools::Barrier("EndEvent");
00282 #endif
00283         if (!mHasBegun[event])
00284         {
00285             std::string msg;
00286             msg += "Error: The event associated with the counter for '";
00287             msg += CONCRETE::EventName[event];
00288             msg += "' had not begun when EndEvent was called.";
00289             EXCEPTION(msg);
00290         }
00291         mWallTime[event] += GetWallTime();
00292         mHasBegun[event] = false;
00293         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00294     }
00295 
00303     double GetElapsedTimeImpl(unsigned event)
00304     {
00305         assert(event<NUM_EVENTS);
00306         if (!mEnabled)
00307         {
00308             return 0.0;
00309         }
00310         double time;
00311         if (mHasBegun[event])
00312         {
00313             time =  mWallTime[event] + GetWallTime();
00314         }
00315         else
00316         {
00317             time = mWallTime[event];
00318         }
00319         return ConvertWallTimeToMilliseconds(time);
00320     }
00321 
00330     void ReportImpl()
00331     {
00332         if (!mEnabled)
00333         {
00334             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00335         }
00336         if (!mInUse)
00337         {
00338             EXCEPTION("Asked to report on an event handler which is set to zero.");
00339         }
00340         // Check that all events are finished
00341         for (unsigned event=0; event<NUM_EVENTS; event++)
00342         {
00343             if (mHasBegun[event])
00344             {
00345                 // Silently close event
00346                 EndEvent(event);
00347             }
00348         }
00349         const unsigned top_event = NUM_EVENTS-1;
00350         double total = ConvertWallTimeToSeconds(mWallTime[top_event]);
00351 
00352         // Make the output precision depend on total run time
00353         const char* format;
00354         if (total > 999999.0)      // 11.5 days
00355         {
00356             format = "%8.0f ";     // will allow up to 115 days before columns unaligned
00357         }
00358         else if (total > 9999.0)   // 2.7 hours
00359         {
00360             format = "%8.1f ";
00361         }
00362         else
00363         {
00364             format = "%8.3f ";
00365         }
00366 
00367         PetscTools::BeginRoundRobin();
00368         {
00369             std::cout.flush();
00370             if (PetscTools::IsParallel())
00371             {
00372                 // Report the process number at the beginning of the line
00373                 printf("%3i: ", PetscTools::GetMyRank()); //5 chars
00374             }
00375             for (unsigned event=0; event<NUM_EVENTS; event++)
00376             {
00377                 const double secs = ConvertWallTimeToSeconds(mWallTime[event]);
00378                 printf(format, secs);
00379                 printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00380             }
00381             std::cout << "(seconds) \n";
00382         }
00383         PetscTools::EndRoundRobin();
00384 
00385         // If there is a collection of processes then report an average
00386         if (PetscTools::IsParallel())
00387         {
00388             double total_cpu_time[NUM_EVENTS];
00389             MPI_Reduce(&mWallTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_SUM, 0, PETSC_COMM_WORLD);
00390             if (PetscTools::AmMaster())
00391             {
00392                 total = ConvertWallTimeToSeconds(total_cpu_time[top_event]);
00393                 printf("avg: "); //5 chars
00394                 for (unsigned event=0; event<NUM_EVENTS; event++)
00395                 {
00396                     const double secs = ConvertWallTimeToSeconds(total_cpu_time[event]);
00397                     printf(format, secs/PetscTools::GetNumProcs());
00398                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00399                 }
00400                 std::cout << "(seconds) \n";
00401             }
00402 
00403             double max_cpu_time[NUM_EVENTS];
00404             MPI_Reduce(&mWallTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_MAX, 0, PETSC_COMM_WORLD);
00405             if (PetscTools::AmMaster())
00406             {
00407                 total = ConvertWallTimeToSeconds(max_cpu_time[top_event]);
00408                 printf("max: "); //5 chars
00409                 for (unsigned event=0; event<NUM_EVENTS; event++)
00410                 {
00411                     const double secs = ConvertWallTimeToSeconds(max_cpu_time[event]);
00412                     printf(format, secs);
00413                     printf("(%3.0f%%)  ", total == 0.0 ? 0.0 : (secs/total*100.0));
00414                 }
00415                 std::cout << "(seconds) \n";
00416             }
00417         }
00418         std::cout.flush();
00419         PetscTools::Barrier();
00420         std::cout.flush();
00421 
00422         Reset();
00423     }
00424 
00428     void HeadingsImpl()
00429     {
00430         // Make sure that all output (on all processes) is flushed
00431         std::cout.flush();
00432         PetscTools::Barrier();
00433         std::cout.flush();
00434         if (PetscTools::AmMaster())
00435         {
00436             if (PetscTools::IsParallel())
00437             {
00438                 // Report the process number at the beginning of the line
00439                 printf("Proc "); //5 chars
00440             }
00441             for (unsigned event=0; event<NUM_EVENTS; event++)
00442             {
00443                 printf("%15s%2s", CONCRETE::EventName[event], "");
00444             }
00445             std::cout << "\n";
00446             std::cout.flush();
00447         }
00448     }
00449 
00451     void EnableImpl()
00452     {
00453         mEnabled = true;
00454     }
00455 
00457     void DisableImpl()
00458     {
00459         mEnabled = false;
00460     }
00461 
00463     bool IsEnabledImpl()
00464     {
00465         return mEnabled;
00466     }
00467 };
00468 
00469 #endif /*GENERICEVENTHANDLER_HPP_*/
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3