Chaste Commit::baa90ac2819b962188b7562f2326be23c47859a7
GenericEventHandler.hpp
1/*
2
3Copyright (c) 2005-2024, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#ifndef GENERICEVENTHANDLER_HPP_
37#define GENERICEVENTHANDLER_HPP_
38
39#include <cassert>
40#include <iostream>
41
42#include "Exception.hpp"
43#include "PetscTools.hpp"
44#include "Timer.hpp"
45
57template <unsigned NUM_EVENTS, class CONCRETE>
59{
60 friend class TestGenericEventHandler;
61 friend class TestCellBasedEventHandler;
62 friend class TestHeartEventHandler;
63
64private:
65
66 std::vector<double> mWallTime;
67 std::vector<bool> mHasBegun;
68 bool mEnabled;
69 bool mInUse;
78 static inline void MilliSleep(unsigned milliseconds)
79 {
80 double min_Wtime = milliseconds/1000.0 + Timer::GetElapsedTime();
81 while (Timer::GetElapsedTime() < min_Wtime)
82 {
83 //pause;
84 }
85 }
86
93 inline double ConvertWallTimeToMilliseconds(double wallTime)
94 {
95 return wallTime*1000.0;
96 }
97
104 inline double ConvertWallTimeToSeconds(double wallTime)
105 {
106 return wallTime;
107 }
108
109public:
110
115 {
116 static CONCRETE inst;
117 return &inst;
118 }
119
123 static void Reset()
124 {
125 Instance()->ResetImpl();
126 }
127
133 static void BeginEvent(unsigned event)
134 {
135 Instance()->BeginEventImpl(event);
136 }
137
143 static void EndEvent(unsigned event)
144 {
145 Instance()->EndEventImpl(event);
146 }
147
155 static double GetElapsedTime(unsigned event)
156 {
157 return Instance()->GetElapsedTimeImpl(event);
158 }
159
168 static void Report()
169 {
170 Instance()->ReportImpl();
171 }
172
176 static void Headings()
177 {
178 Instance()->HeadingsImpl();
179 }
180
184 static void Enable()
185 {
186 Instance()->EnableImpl();
187 }
188
190 static void Disable()
191 {
192 Instance()->DisableImpl();
193 }
194
198 static bool IsEnabled()
199 {
200 return Instance()->IsEnabledImpl();
201 }
202
203protected:
204
209 {
210 mEnabled = true;
211 mInUse = false;
212 mWallTime.resize(NUM_EVENTS, 0.0);
213 mHasBegun.resize(NUM_EVENTS, false);
214 }
215
216private:
217
222 {
223 for (unsigned event=0; event<NUM_EVENTS; event++)
224 {
225 mWallTime[event] = 0.0;
226 mHasBegun[event] = false;
227 }
228 Enable();
229 mInUse = false;
230 }
231
237 void BeginEventImpl(unsigned event)
238 {
239 if (!mEnabled)
240 {
241 return;
242 }
243#ifdef CHASTE_EVENT_BARRIERS
244 PetscTools::Barrier("BeginEvent");
245#endif
246 mInUse = true;
247 assert(event<NUM_EVENTS);
248 // Check that we are recording the total
249 if (event != NUM_EVENTS-1) // If use <, Intel complains when NUM_EVENTS==1
250 {
251 if (!mHasBegun[NUM_EVENTS-1])
252 {
253 // Silently open the "total" event
254 BeginEvent(NUM_EVENTS-1);
255 }
256 }
257 if (mHasBegun[event])
258 {
259 std::string msg;
260 msg += "The event associated with the counter for '";
261 msg += CONCRETE::EventName[event];
262 msg += "' had already begun when BeginEvent was called.";
263 std::cerr << msg << std::endl << std::flush;
264 Disable();
265 return;
266 }
268 mHasBegun[event] = true;
269 //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
270 }
271
277 void EndEventImpl(unsigned event)
278 {
279 assert(event<NUM_EVENTS);
280 if (!mEnabled)
281 {
282 return;
283 }
284#ifdef CHASTE_EVENT_BARRIERS
285 PetscTools::Barrier("EndEvent");
286#endif
287 if (!mHasBegun[event])
288 {
289 std::string msg;
290 msg += "Error: The event associated with the counter for '";
291 msg += CONCRETE::EventName[event];
292 msg += "' had not begun when EndEvent was called.";
293 EXCEPTION(msg);
294 }
296 mHasBegun[event] = false;
297 //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
298 }
299
307 double GetElapsedTimeImpl(unsigned event)
308 {
309 assert(event<NUM_EVENTS);
310 if (!mEnabled)
311 {
312 EXCEPTION("Asked to report on a disabled event handler. Check for contributory errors above.");
313 }
314 double time;
315 if (mHasBegun[event])
316 {
318 }
319 else
320 {
321 time = mWallTime[event];
322 }
324 }
325
335 {
336 if (!mEnabled)
337 {
338 EXCEPTION("Asked to report on a disabled event handler. Check for contributory errors above.");
339 }
340 if (!mInUse)
341 {
342 EXCEPTION("Asked to report on an event handler which is set to zero.");
343 }
344 // Check that all events are finished
345 for (unsigned event=0; event<NUM_EVENTS; event++)
346 {
347 if (mHasBegun[event])
348 {
349 // Silently close event
351 }
352 }
353 const unsigned top_event = NUM_EVENTS-1;
354 double total = ConvertWallTimeToSeconds(mWallTime[top_event]);
355
356 // Make the output precision depend on total run time
357 const char* format;
358 if (total > 999999.0) // 11.5 days
359 {
360 format = "%8.0f "; // will allow up to 115 days before columns unaligned
361 }
362 else if (total > 9999.0) // 2.7 hours
363 {
364 format = "%8.1f ";
365 }
366 else
367 {
368 format = "%8.3f ";
369 }
370
372 {
373 std::cout.flush();
375 {
376 // Report the process number at the beginning of the line
377 printf("%3u: ", PetscTools::GetMyRank()); //5 chars
378 }
379 for (unsigned event=0; event<NUM_EVENTS; event++)
380 {
381 const double secs = ConvertWallTimeToSeconds(mWallTime[event]);
382 printf(format, secs);
383 printf("(%3.0f%%) ", total == 0.0 ? 0.0 : (secs/total*100.0));
384 }
385 std::cout << "(seconds) \n";
386 }
388
389 // If there is a collection of processes then report an average
391 {
392 double total_cpu_time[NUM_EVENTS];
393 MPI_Reduce(&mWallTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_SUM, 0, PetscTools::GetWorld());
395 {
396 total = ConvertWallTimeToSeconds(total_cpu_time[top_event]);
397 printf("avg: "); //5 chars
398 for (unsigned event=0; event<NUM_EVENTS; event++)
399 {
400 const double secs = ConvertWallTimeToSeconds(total_cpu_time[event]);
401 printf(format, secs/PetscTools::GetNumProcs());
402 printf("(%3.0f%%) ", total == 0.0 ? 0.0 : (secs/total*100.0));
403 }
404 std::cout << "(seconds) \n";
405 }
406
407 double max_cpu_time[NUM_EVENTS];
408 MPI_Reduce(&mWallTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE, MPI_MAX, 0, PetscTools::GetWorld());
410 {
411 total = ConvertWallTimeToSeconds(max_cpu_time[top_event]);
412 printf("max: "); //5 chars
413 for (unsigned event=0; event<NUM_EVENTS; event++)
414 {
415 const double secs = ConvertWallTimeToSeconds(max_cpu_time[event]);
416 printf(format, secs);
417 printf("(%3.0f%%) ", total == 0.0 ? 0.0 : (secs/total*100.0));
418 }
419 std::cout << "(seconds) \n";
420 }
421 }
422 std::cout.flush();
424 std::cout.flush();
425
426 Reset();
427 }
428
433 {
434 // Make sure that all output (on all processes) is flushed
435 std::cout.flush();
437 std::cout.flush();
439 {
441 {
442 // Report the process number at the beginning of the line
443 printf("Proc "); //5 chars
444 }
445 for (unsigned event=0; event<NUM_EVENTS; event++)
446 {
447 printf("%15s%2s", CONCRETE::EventName[event], "");
448 }
449 std::cout << "\n";
450 std::cout.flush();
451 }
452 }
453
456 {
457 mEnabled = true;
458 }
459
462 {
463 mEnabled = false;
464 }
465
470 {
471 return mEnabled;
472 }
473};
474
475#endif /*GENERICEVENTHANDLER_HPP_*/
#define EXCEPTION(message)
static double GetElapsedTime(unsigned event)
void BeginEventImpl(unsigned event)
double ConvertWallTimeToMilliseconds(double wallTime)
static void BeginEvent(unsigned event)
std::vector< bool > mHasBegun
static void MilliSleep(unsigned milliseconds)
double GetElapsedTimeImpl(unsigned event)
void EndEventImpl(unsigned event)
std::vector< double > mWallTime
double ConvertWallTimeToSeconds(double wallTime)
static GenericEventHandler< NUM_EVENTS, CONCRETE > * Instance()
static void EndEvent(unsigned event)
static MPI_Comm GetWorld()
static bool AmMaster()
static void Barrier(const std::string callerId="")
static bool IsParallel()
static void EndRoundRobin()
static bool IsIsolated()
static unsigned GetMyRank()
static void BeginRoundRobin()
static unsigned GetNumProcs()
static double GetWallTime()
Definition Timer.cpp:49
static double GetElapsedTime()
Definition Timer.cpp:54