Chaste Release::3.1
|
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_*/