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