Chaste  Release::2018.1
GenericEventHandler.hpp
1 /*
2 
3 Copyright (c) 2005-2018, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, 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 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF 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 
57 template <unsigned NUM_EVENTS, class CONCRETE>
59 {
60  friend class TestGenericEventHandler;
61  friend class TestCellBasedEventHandler;
62  friend class TestHeartEventHandler;
63 
64 private:
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 
109 public:
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 
203 protected:
204 
209  {
210  mEnabled = true;
211  mInUse = false;
212  mWallTime.resize(NUM_EVENTS, 0.0);
213  mHasBegun.resize(NUM_EVENTS, false);
214  }
215 
216 private:
217 
221  void ResetImpl()
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  }
267  mWallTime[event] -= Timer::GetWallTime();
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  }
295  mWallTime[event] += Timer::GetWallTime();
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  {
317  time = mWallTime[event] + Timer::GetWallTime();
318  }
319  else
320  {
321  time = mWallTime[event];
322  }
323  return ConvertWallTimeToMilliseconds(time);
324  }
325 
334  void ReportImpl()
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
350  EndEvent(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());
394  if (PetscTools::AmMaster())
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());
409  if (PetscTools::AmMaster())
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();
438  if (PetscTools::AmMaster())
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 
455  void EnableImpl()
456  {
457  mEnabled = true;
458  }
459 
461  void DisableImpl()
462  {
463  mEnabled = false;
464  }
465 
470  {
471  return mEnabled;
472  }
473 };
474 
475 #endif /*GENERICEVENTHANDLER_HPP_*/
double GetElapsedTimeImpl(unsigned event)
static double GetWallTime()
Definition: Timer.cpp:49
static void Barrier(const std::string callerId="")
Definition: PetscTools.cpp:134
std::vector< double > mWallTime
#define EXCEPTION(message)
Definition: Exception.hpp:143
static void BeginEvent(unsigned event)
static bool AmMaster()
Definition: PetscTools.cpp:120
static MPI_Comm GetWorld()
Definition: PetscTools.cpp:174
static double GetElapsedTime()
Definition: Timer.cpp:54
static GenericEventHandler< NUM_EVENTS, CONCRETE > * Instance()
static void EndRoundRobin()
Definition: PetscTools.cpp:160
double ConvertWallTimeToSeconds(double wallTime)
static void BeginRoundRobin()
Definition: PetscTools.cpp:150
void EndEventImpl(unsigned event)
static bool IsParallel()
Definition: PetscTools.cpp:97
static double GetElapsedTime(unsigned event)
static bool IsIsolated()
Definition: PetscTools.cpp:103
double ConvertWallTimeToMilliseconds(double wallTime)
static void MilliSleep(unsigned milliseconds)
static unsigned GetNumProcs()
Definition: PetscTools.cpp:108
static void EndEvent(unsigned event)
static unsigned GetMyRank()
Definition: PetscTools.cpp:114
void BeginEventImpl(unsigned event)
std::vector< bool > mHasBegun