Reference documentation for deal.II version 8.5.1
timer.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/timer.h>
17 #include <deal.II/base/exceptions.h>
18 #include <deal.II/base/mpi.h>
19 #include <deal.II/base/utilities.h>
20 #include <deal.II/base/signaling_nan.h>
21 #include <sstream>
22 #include <iostream>
23 #include <iomanip>
24 #include <algorithm>
25 #include <stddef.h>
26 
27 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
28 # include <sys/time.h>
29 # include <sys/resource.h>
30 #endif
31 
32 #ifdef DEAL_II_MSVC
33 # include <windows.h>
34 #endif
35 
36 
37 
38 DEAL_II_NAMESPACE_OPEN
39 
40 // in case we use an MPI compiler, need
41 // to create a communicator just for the
42 // current process
44  :
45  start_time (0.),
46  start_time_children (0.),
47  start_wall_time (0.),
48  cumulative_time (0.),
49  cumulative_wall_time (0.),
50  last_lap_time (0.),
51  running (false)
52 #ifdef DEAL_II_WITH_MPI
53  ,
54  mpi_communicator (MPI_COMM_SELF),
55  sync_wall_time (false)
56 #endif
57 {
58 #ifdef DEAL_II_WITH_MPI
59  mpi_data.sum = mpi_data.min = mpi_data.max = mpi_data.avg = numbers::signaling_nan<double>();
60  mpi_data.min_index = mpi_data.max_index = numbers::invalid_unsigned_int;
61 #endif
62 
63  start();
64 }
65 
66 
67 
68 // in case we use an MPI compiler, use
69 // the communicator given from input
70 #ifdef DEAL_II_WITH_MPI
71 Timer::Timer(MPI_Comm mpi_communicator,
72  const bool sync_wall_time_)
73  :
74  start_time (0.),
75  start_time_children (0.),
76  start_wall_time (0.),
77  cumulative_time (0.),
78  cumulative_wall_time (0.),
79  last_lap_time (0.),
80  running (false),
81  mpi_communicator (mpi_communicator),
82  sync_wall_time(sync_wall_time_)
83 {
84 #ifdef DEAL_II_WITH_MPI
85  mpi_data.sum = mpi_data.min = mpi_data.max = mpi_data.avg = numbers::signaling_nan<double>();
86  mpi_data.min_index = mpi_data.max_index = numbers::invalid_unsigned_int;
87 #endif
88 
89  start();
90 }
91 #endif
92 
93 
94 
95 #ifdef DEAL_II_MSVC
96 
97 namespace
98 {
99  namespace windows
100  {
101  double wall_clock()
102  {
103  LARGE_INTEGER freq, time;
104  QueryPerformanceFrequency(&freq);
105  QueryPerformanceCounter(&time);
106  return (double) time.QuadPart / freq.QuadPart;
107  }
108 
109 
110  double cpu_clock()
111  {
112  FILETIME cpuTime, sysTime, createTime, exitTime;
113  if (GetProcessTimes(GetCurrentProcess(), &createTime,
114  &exitTime, &sysTime, &cpuTime))
115  {
116  return (double)(((unsigned long long)cpuTime.dwHighDateTime << 32)
117  | cpuTime.dwLowDateTime) / 1e6;
118  }
119  return 0;
120  }
121  }
122 }
123 
124 #endif
125 
126 
128 {
129  running = true;
130 
131 #ifdef DEAL_II_WITH_MPI
132  if (sync_wall_time)
133  {
134  const int ierr = MPI_Barrier(mpi_communicator);
135  AssertThrowMPI(ierr);
136  }
137 #endif
138 
139 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
140 
141 //TODO: Break this out into a function like the functions in
142 //namespace windows above
143  struct timeval wall_timer;
144  gettimeofday(&wall_timer, NULL);
145  start_wall_time = wall_timer.tv_sec + 1.e-6 * wall_timer.tv_usec;
146 
147  rusage usage;
148  getrusage (RUSAGE_SELF, &usage);
149  start_time = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
150 
151  rusage usage_children;
152  getrusage (RUSAGE_CHILDREN, &usage_children);
153  start_time_children = usage_children.ru_utime.tv_sec + 1.e-6 * usage_children.ru_utime.tv_usec;
154 
155 #elif defined(DEAL_II_MSVC)
156  start_wall_time = windows::wall_clock();
157  start_time = windows::cpu_clock();
159 #else
160 # error Unsupported platform. Porting not finished.
161 #endif
162 }
163 
164 
165 
166 double Timer::stop ()
167 {
168  if (running)
169  {
170  running = false;
171 
172 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
173 //TODO: Break this out into a function like the functions in
174 //namespace windows above
175  rusage usage;
176  getrusage (RUSAGE_SELF, &usage);
177  const double dtime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
178  cumulative_time += dtime - start_time;
179 
180  rusage usage_children;
181  getrusage (RUSAGE_CHILDREN, &usage_children);
182  const double dtime_children =
183  usage_children.ru_utime.tv_sec + 1.e-6 * usage_children.ru_utime.tv_usec;
184  cumulative_time += dtime_children - start_time_children;
185 
186  struct timeval wall_timer;
187  gettimeofday(&wall_timer, NULL);
188  last_lap_time = wall_timer.tv_sec + 1.e-6 * wall_timer.tv_usec
189  - start_wall_time;
190 #elif defined(DEAL_II_MSVC)
191  last_lap_time = windows::wall_clock() - start_wall_time;
192  cumulative_time += windows::cpu_clock() - start_time;
193 #else
194 # error Unsupported platform. Porting not finished.
195 #endif
196 
197 #ifdef DEAL_II_WITH_MPI
199  {
200  this->mpi_data
202  last_lap_time = this->mpi_data.max;
204  }
205  else
206 #endif
208  }
209  return cumulative_time;
210 }
211 
212 
213 
214 double Timer::get_lap_time() const
215 {
216  // time already has the difference between the last start()/stop() cycle.
218 }
219 
220 
221 
222 double Timer::operator() () const
223 {
224  if (running)
225  {
226 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
227  rusage usage;
228  getrusage (RUSAGE_SELF, &usage);
229  const double dtime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
230 
231  rusage usage_children;
232  getrusage (RUSAGE_CHILDREN, &usage_children);
233  const double dtime_children =
234  usage_children.ru_utime.tv_sec + 1.e-6 * usage_children.ru_utime.tv_usec;
235 
236  const double running_time = dtime - start_time + dtime_children
238 
239  // in case of MPI, need to get the time passed by summing the time over
240  // all processes in the network. works also in case we just want to have
241  // the time of a single thread, since then the communicator is
242  // MPI_COMM_SELF
243  return Utilities::MPI::sum (running_time, mpi_communicator);
244 
245 #elif defined(DEAL_II_MSVC)
246  const double running_time = windows::cpu_clock() - start_time + cumulative_time;
247  return running_time;
248 #else
249 # error Unsupported platform. Porting not finished.
250 #endif
251  }
252  else
253  {
255  }
256 }
257 
258 
259 
260 double Timer::wall_time () const
261 {
262  if (running)
263  {
264 #if defined(DEAL_II_HAVE_SYS_TIME_H) && defined(DEAL_II_HAVE_SYS_RESOURCE_H)
265  struct timeval wall_timer;
266  gettimeofday(&wall_timer, NULL);
267  return (wall_timer.tv_sec
268  + 1.e-6 * wall_timer.tv_usec
271 #else
272 //TODO[BG]: Do something useful here
273  return 0;
274 #endif
275  }
276  else
277  return cumulative_wall_time;
278 }
279 
280 
281 
283 {
284  last_lap_time = 0.;
285  cumulative_time = 0.;
287  running = false;
288 }
289 
290 
291 
292 /* ---------------------------- TimerOutput -------------------------- */
293 
294 TimerOutput::TimerOutput (std::ostream &stream,
295  const enum OutputFrequency output_frequency,
296  const enum OutputType output_type)
297  :
298  output_frequency (output_frequency),
299  output_type (output_type),
300  out_stream (stream, true),
301  output_is_enabled (true)
302 #ifdef DEAL_II_WITH_MPI
303  , mpi_communicator (MPI_COMM_SELF)
304 #endif
305 {}
306 
307 
308 
310  const enum OutputFrequency output_frequency,
311  const enum OutputType output_type)
312  :
313  output_frequency (output_frequency),
314  output_type (output_type),
315  out_stream (stream),
316  output_is_enabled (true)
317 #ifdef DEAL_II_WITH_MPI
318  , mpi_communicator (MPI_COMM_SELF)
319 #endif
320 {}
321 
322 
323 #ifdef DEAL_II_WITH_MPI
324 
325 TimerOutput::TimerOutput (MPI_Comm mpi_communicator,
326  std::ostream &stream,
327  const enum OutputFrequency output_frequency,
328  const enum OutputType output_type)
329  :
330  output_frequency (output_frequency),
331  output_type (output_type),
332  out_stream (stream, true),
333  output_is_enabled (true),
334  mpi_communicator (mpi_communicator)
335 {}
336 
337 
338 
339 TimerOutput::TimerOutput (MPI_Comm mpi_communicator,
340  ConditionalOStream &stream,
341  const enum OutputFrequency output_frequency,
342  const enum OutputType output_type)
343  :
344  output_frequency (output_frequency),
345  output_type (output_type),
346  out_stream (stream),
347  output_is_enabled (true),
348  mpi_communicator (mpi_communicator)
349 {}
350 
351 #endif
352 
353 
355 {
356  try
357  {
358  while (active_sections.size() > 0)
360  }
361  catch (...)
362  {}
363 
365  && output_is_enabled == true)
366  print_summary();
367 }
368 
369 
370 
371 void
372 TimerOutput::enter_subsection (const std::string &section_name)
373 {
375 
376  Assert (section_name.empty() == false,
377  ExcMessage ("Section string is empty."));
378 
379  Assert (std::find (active_sections.begin(), active_sections.end(),
380  section_name) == active_sections.end(),
381  ExcMessage (std::string("Cannot enter the already active section <")
382  + section_name + ">."));
383 
384  if (sections.find (section_name) == sections.end())
385  {
386 #ifdef DEAL_II_WITH_MPI
387  if (mpi_communicator != MPI_COMM_SELF)
388  {
389  // create a new timer for this section. the second argument
390  // will ensure that we have an MPI barrier before starting
391  // and stopping a timer, and this ensures that we get the
392  // maximum run time for this section over all processors.
393  // The mpi_communicator from TimerOutput is passed to the
394  // Timer here, so this Timer will collect timing information
395  // among all processes inside mpi_communicator.
396  sections[section_name].timer = Timer(mpi_communicator, true);
397  }
398 #endif
399 
400 
401  sections[section_name].total_cpu_time = 0;
402  sections[section_name].total_wall_time = 0;
403  sections[section_name].n_calls = 0;
404  }
405 
406  sections[section_name].timer.reset();
407  sections[section_name].timer.start();
408  sections[section_name].n_calls++;
409 
410  active_sections.push_back (section_name);
411 }
412 
413 
414 
415 void
416 TimerOutput::leave_subsection (const std::string &section_name)
417 {
418  Assert (!active_sections.empty(),
419  ExcMessage("Cannot exit any section because none has been entered!"));
420 
422 
423  if (section_name != "")
424  {
425  Assert (sections.find (section_name) != sections.end(),
426  ExcMessage ("Cannot delete a section that was never created."));
427  Assert (std::find (active_sections.begin(), active_sections.end(),
428  section_name) != active_sections.end(),
429  ExcMessage ("Cannot delete a section that has not been entered."));
430  }
431 
432  // if no string is given, exit the last
433  // active section.
434  const std::string actual_section_name = (section_name == "" ?
435  active_sections.back () :
436  section_name);
437 
438  sections[actual_section_name].timer.stop();
439  sections[actual_section_name].total_wall_time
440  += sections[actual_section_name].timer.wall_time();
441 
442  // Get cpu time. On MPI systems, if constructed with an mpi_communicator
443  // like MPI_COMM_WORLD, then the Timer will sum up the CPU time between
444  // processors among the provided mpi_communicator. Therefore, no
445  // communication is needed here.
446  const double cpu_time = sections[actual_section_name].timer();
447  sections[actual_section_name].total_cpu_time += cpu_time;
448 
449  // in case we have to print out something, do that here...
451  && output_is_enabled == true)
452  {
453  std::string output_time;
454  std::ostringstream cpu;
455  cpu << cpu_time << "s";
456  std::ostringstream wall;
457  wall << sections[actual_section_name].timer.wall_time() << "s";
458  if (output_type == cpu_times)
459  output_time = ", CPU time: " + cpu.str();
460  else if (output_type == wall_times)
461  output_time = ", wall time: " + wall.str() + ".";
462  else
463  output_time = ", CPU/wall time: " + cpu.str() + " / " + wall.str() + ".";
464 
465  out_stream << actual_section_name << output_time
466  << std::endl;
467  }
468 
469  // delete the index from the list of
470  // active ones
471  active_sections.erase (std::find (active_sections.begin(), active_sections.end(),
472  actual_section_name));
473 }
474 
475 
476 
477 void
479 {
480  // we are going to change the
481  // precision and width of output
482  // below. store the old values so we
483  // can restore it later on
484  const std::istream::fmtflags old_flags = out_stream.get_stream().flags();
485  const std::streamsize old_precision = out_stream.get_stream().precision ();
486  const std::streamsize old_width = out_stream.get_stream().width ();
487 
488  // in case we want to write CPU times
489  if (output_type != wall_times)
490  {
491  double total_cpu_time = Utilities::MPI::sum(timer_all(), mpi_communicator);
492 
493  // check that the sum of all times is
494  // less or equal than the total
495  // time. otherwise, we might have
496  // generated a lot of overhead in this
497  // function.
498  double check_time = 0.;
499  for (std::map<std::string, Section>::const_iterator
500  i = sections.begin(); i!=sections.end(); ++i)
501  check_time += i->second.total_cpu_time;
502 
503  const double time_gap = check_time-total_cpu_time;
504  if (time_gap > 0.0)
505  total_cpu_time = check_time;
506 
507  // generate a nice table
508  out_stream << "\n\n"
509  << "+---------------------------------------------+------------"
510  << "+------------+\n"
511  << "| Total CPU time elapsed since start |";
512  out_stream << std::setw(10) << std::setprecision(3) << std::right;
513  out_stream << total_cpu_time << "s | |\n";
514  out_stream << "| | "
515  << "| |\n";
516  out_stream << "| Section | no. calls |";
517  out_stream << std::setw(10);
518  out_stream << std::setprecision(3);
519  out_stream << " CPU time " << " | % of total |\n";
520  out_stream << "+---------------------------------+-----------+------------"
521  << "+------------+";
522  for (std::map<std::string, Section>::const_iterator
523  i = sections.begin(); i!=sections.end(); ++i)
524  {
525  std::string name_out = i->first;
526 
527  // resize the array so that it is always
528  // of the same size
529  unsigned int pos_non_space = name_out.find_first_not_of (" ");
530  name_out.erase(0, pos_non_space);
531  name_out.resize (32, ' ');
532  out_stream << std::endl;
533  out_stream << "| " << name_out;
534  out_stream << "| ";
535  out_stream << std::setw(9);
536  out_stream << i->second.n_calls << " |";
537  out_stream << std::setw(10);
538  out_stream << std::setprecision(3);
539  out_stream << i->second.total_cpu_time << "s |";
540  out_stream << std::setw(10);
541  if (total_cpu_time != 0)
542  {
543  // if run time was less than 0.1%, just print a zero to avoid
544  // printing silly things such as "2.45e-6%". otherwise print
545  // the actual percentage
546  const double fraction = i->second.total_cpu_time/total_cpu_time;
547  if (fraction > 0.001)
548  {
549  out_stream << std::setprecision(2);
550  out_stream << fraction * 100;
551  }
552  else
553  out_stream << 0.0;
554 
555  out_stream << "% |";
556  }
557  else
558  out_stream << 0.0 << "% |";
559  }
560  out_stream << std::endl
561  << "+---------------------------------+-----------+"
562  << "------------+------------+\n"
563  << std::endl;
564 
565  if (time_gap > 0.0)
566  out_stream << std::endl
567  << "Note: The sum of counted times is " << time_gap
568  << " seconds larger than the total time.\n"
569  << "(Timer function may have introduced too much overhead, or different\n"
570  << "section timers may have run at the same time.)" << std::endl;
571  }
572 
573  // in case we want to write out wallclock times
574  if (output_type != cpu_times)
575  {
576  double total_wall_time = timer_all.wall_time();
577 
578  // now generate a nice table
579  out_stream << "\n\n"
580  << "+---------------------------------------------+------------"
581  << "+------------+\n"
582  << "| Total wallclock time elapsed since start |";
583  out_stream << std::setw(10) << std::setprecision(3) << std::right;
584  out_stream << total_wall_time << "s | |\n";
585  out_stream << "| | "
586  << "| |\n";
587  out_stream << "| Section | no. calls |";
588  out_stream << std::setw(10);
589  out_stream << std::setprecision(3);
590  out_stream << " wall time | % of total |\n";
591  out_stream << "+---------------------------------+-----------+------------"
592  << "+------------+";
593  for (std::map<std::string, Section>::const_iterator
594  i = sections.begin(); i!=sections.end(); ++i)
595  {
596  std::string name_out = i->first;
597 
598  // resize the array so that it is always
599  // of the same size
600  unsigned int pos_non_space = name_out.find_first_not_of (" ");
601  name_out.erase(0, pos_non_space);
602  name_out.resize (32, ' ');
603  out_stream << std::endl;
604  out_stream << "| " << name_out;
605  out_stream << "| ";
606  out_stream << std::setw(9);
607  out_stream << i->second.n_calls << " |";
608  out_stream << std::setw(10);
609  out_stream << std::setprecision(3);
610  out_stream << i->second.total_wall_time << "s |";
611  out_stream << std::setw(10);
612 
613  if (total_wall_time != 0)
614  {
615  // if run time was less than 0.1%, just print a zero to avoid
616  // printing silly things such as "2.45e-6%". otherwise print
617  // the actual percentage
618  const double fraction = i->second.total_wall_time/total_wall_time;
619  if (fraction > 0.001)
620  {
621  out_stream << std::setprecision(2);
622  out_stream << fraction * 100;
623  }
624  else
625  out_stream << 0.0;
626 
627  out_stream << "% |";
628  }
629  else
630  out_stream << 0.0 << "% |";
631  }
632  out_stream << std::endl
633  << "+---------------------------------+-----------+"
634  << "------------+------------+\n"
635  << std::endl;
636  }
637 
638  // restore previous precision and width
639  out_stream.get_stream().precision (old_precision);
640  out_stream.get_stream().width (old_width);
641  out_stream.get_stream().flags (old_flags);
642 }
643 
644 
645 
646 void
648 {
649  output_is_enabled = false;
650 }
651 
652 
653 
654 void
656 {
657  output_is_enabled = true;
658 }
659 
660 void
662 {
664  sections.clear();
665  active_sections.clear();
666  timer_all.restart();
667 }
668 
669 
670 DEAL_II_NAMESPACE_CLOSE
void print_summary() const
Definition: timer.cc:478
void reset()
Definition: timer.cc:661
static const unsigned int invalid_unsigned_int
Definition: types.h:170
double get_lap_time() const
Definition: timer.cc:214
MPI_Comm mpi_communicator
Definition: timer.h:676
void reset()
Definition: timer.cc:282
MPI_Comm mpi_communicator
Definition: timer.h:212
bool sync_wall_time
Definition: timer.h:218
double stop()
Definition: timer.cc:166
Utilities::MPI::MinMaxAvg mpi_data
Definition: timer.h:226
double start_wall_time
Definition: timer.h:185
Timer timer_all
Definition: timer.h:635
Threads::Mutex mutex
Definition: timer.h:682
OutputType output_type
Definition: timer.h:628
bool output_is_enabled
Definition: timer.h:663
static ::ExceptionBase & ExcMessage(std::string arg1)
T sum(const T &t, const MPI_Comm &mpi_communicator)
double wall_time() const
Definition: timer.cc:260
double cumulative_time
Definition: timer.h:191
#define Assert(cond, exc)
Definition: exceptions.h:313
double last_lap_time
Definition: timer.h:202
double operator()() const
Definition: timer.cc:222
double start_time_children
Definition: timer.h:179
Timer()
Definition: timer.cc:43
OutputFrequency
Definition: timer.h:432
void disable_output()
Definition: timer.cc:647
bool running
Definition: timer.h:207
TimerOutput(std::ostream &stream, const enum OutputFrequency output_frequency, const enum OutputType output_type)
Definition: timer.cc:294
std::list< std::string > active_sections
Definition: timer.h:671
void start()
Definition: timer.cc:127
void restart()
Definition: timer.h:691
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1211
double start_time
Definition: timer.h:166
std::map< std::string, Section > sections
Definition: timer.h:652
ConditionalOStream out_stream
Definition: timer.h:657
double cumulative_wall_time
Definition: timer.h:197
std::ostream & get_stream() const
void enable_output()
Definition: timer.cc:655
Definition: timer.h:76
void enter_subsection(const std::string &section_name)
Definition: timer.cc:372
MinMaxAvg min_max_avg(const double my_value, const MPI_Comm &mpi_communicator)
Definition: mpi.cc:194
bool job_supports_mpi()
Definition: mpi.cc:519
OutputFrequency output_frequency
Definition: timer.h:623
T max(const T &t, const MPI_Comm &mpi_communicator)
~TimerOutput()
Definition: timer.cc:354
void leave_subsection(const std::string &section_name=std::string())
Definition: timer.cc:416