libMesh
perf_log.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 #ifndef LIBMESH_PERFLOG_H
21 #define LIBMESH_PERFLOG_H
22 
23 
24 // Local includes
25 #include "libmesh/libmesh_common.h"
26 
27 // C++ includes
28 #include <cstddef>
29 #include <map>
30 #include <stack>
31 #include <string>
32 #include <vector>
33 #include <deque>
34 #include <memory>
35 #ifdef LIBMESH_HAVE_SYS_TIME_H
36 #include <sys/time.h> // gettimeofday() on Unix
37 #endif
38 #ifndef LIBMESH_HAVE_GETTIMEOFDAY
39 #include "libmesh/win_gettimeofday.h" // gettimeofday() on Windows
40 #endif
41 
42 namespace libMesh
43 {
44 
53 class PerfData
54 {
55 public:
56 
60  PerfData () :
61  tot_time(0.),
63  tstart(),
65  count(0),
66  open(false),
68  {}
69 
70 
74  double tot_time;
75 
80 
85  struct timeval tstart;
86 
92 
97  unsigned int count;
98 
104  bool open;
105 
106  void start ();
107  void restart ();
108  double pause ();
109  double pause_for(PerfData & other);
110  double stopit ();
111 
115  PerfData & operator += (const PerfData & other)
116  {
118  tot_time += other.tot_time;
120  count += other.count;
121 
122  return *this;
123  }
124 
126 
127 protected:
128  double stop_or_pause(const bool do_stop);
129 };
130 
131 
132 
133 
145 class PerfLog
146 {
147 public:
148 
156  PerfLog(std::string label_name="",
157  const bool log_events=true);
158 
162  ~PerfLog();
163 
171  void clear();
172 
176  void disable_logging() { log_events = false; }
177 
181  void enable_logging() { log_events = true; }
182 
186  bool logging_enabled() const { return log_events; }
187 
192 
198 
203 
212  void fast_push (const char * label,
213  const char * header="");
214 
224  void push (const char * label,
225  const char * header="");
226 
234  void push (const std::string & label,
235  const std::string & header="");
236 
245  void fast_pop (const char * label,
246  const char * header="") noexcept;
247 
254  void pop (const char * label,
255  const char * header="");
256 
264  void pop (const std::string & label,
265  const std::string & header="");
266 
270  void start_event(const std::string & label,
271  const std::string & header="");
272 
276  void stop_event(const std::string & label,
277  const std::string & header="");
278 
282  void pause_event(const std::string & label,
283  const std::string & header="");
284 
288  void restart_event(const std::string & label,
289  const std::string & header="");
290 
296  std::string get_log() const;
297 
301  std::string get_info_header() const;
302 
306  std::string get_perf_info() const;
307 
311  void print_log() const;
312 
316  double get_elapsed_time() const;
317 
321  double get_active_time() const;
322 
326  PerfData get_perf_data(const std::string & label, const std::string & header="");
327 
331  typedef std::map<std::pair<const char *,
332  const char *>,
334 
335 private:
336 
337 
341  const std::string label_name;
342 
347 
352 
356  double total_time;
357 
361  struct timeval tstart;
362 
371 
376 
382  static bool called;
383 
388  void split_on_whitespace(const std::string & input,
389  std::vector<std::string> & output) const;
390 
399  std::map<std::string, std::unique_ptr<const char[]>> non_temporary_strings;
400 };
401 
402 
403 
404 // ------------------------------------------------------------
405 // PerfData class member functions
406 inline
407 void PerfData::start ()
408 {
409  this->count++;
410  this->called_recursively++;
411  gettimeofday (&(this->tstart), nullptr);
412  this->tstart_incl_sub = this->tstart;
413 }
414 
415 
416 
417 inline
419 {
420  gettimeofday (&(this->tstart), nullptr);
421 }
422 
423 
424 
425 inline
427 {
428  return this->stop_or_pause(false);
429 }
430 
431 
432 inline
433 double PerfData::stop_or_pause(const bool do_stop)
434 {
435  // save the start times, reuse the structure we have rather than create
436  // a new one.
437  const time_t
438  tstart_tv_sec = this->tstart.tv_sec,
439  tstart_tv_usec = this->tstart.tv_usec;
440 
441  gettimeofday (&(this->tstart), nullptr);
442 
443  const double elapsed_time = (static_cast<double>(this->tstart.tv_sec - tstart_tv_sec) +
444  static_cast<double>(this->tstart.tv_usec - tstart_tv_usec)*1.e-6);
445 
446  this->tot_time += elapsed_time;
447 
448  if (do_stop)
449  {
450  const double elapsed_time_incl_sub = (static_cast<double>(this->tstart.tv_sec - this->tstart_incl_sub.tv_sec) +
451  static_cast<double>(this->tstart.tv_usec - this->tstart_incl_sub.tv_usec)*1.e-6);
452 
453  this->tot_time_incl_sub += elapsed_time_incl_sub;
454  }
455 
456  return elapsed_time;
457 }
458 
459 
460 
461 inline
463 {
464  gettimeofday (&(other.tstart), nullptr);
465 
466  const double elapsed_time = (static_cast<double>(other.tstart.tv_sec - this->tstart.tv_sec) +
467  static_cast<double>(other.tstart.tv_usec - this->tstart.tv_usec)*1.e-6);
468  this->tot_time += elapsed_time;
469 
470  other.count++;
471  other.called_recursively++;
472  other.tstart_incl_sub = other.tstart;
473 
474  return elapsed_time;
475 }
476 
477 
478 
479 inline
481 {
482  // stopit is just similar to pause except that it decrements the
483  // recursive call counter
484 
485  this->called_recursively--;
486  return this->stop_or_pause(true);
487 }
488 
489 
490 
491 // ------------------------------------------------------------
492 // PerfLog class inline member functions
493 inline
494 void PerfLog::fast_push (const char * label,
495  const char * header)
496 {
497  if (this->log_events)
498  {
499  // Get a reference to the event data to avoid
500  // repeated map lookups
501  PerfData * perf_data = &(log[std::make_pair(header,label)]);
502 
503  if (!log_stack.empty())
504  total_time += log_stack.top()->pause_for(*perf_data);
505  else
506  perf_data->start();
507  log_stack.push(perf_data);
508  }
509 }
510 
511 
512 
513 inline
514 void PerfLog::fast_pop(const char * libmesh_dbg_var(label),
515  const char * libmesh_dbg_var(header)) noexcept
516 {
517  if (this->log_events)
518  {
519  // If there's nothing on the stack, then we can't pop anything. Previously we
520  // asserted that the log_stack was not empty, but we should not throw from
521  // this function, so instead just return in that case.
522  if (log_stack.empty())
523  return;
524 
525 #ifndef NDEBUG
526  // In debug mode, we carefully check that before popping the stack,
527  // we have the correct event.
528 
529  // Get pointer to corresponding PerfData, or nullptr if it does not exist.
530  auto it = log.find(std::make_pair(header, label));
531  PerfData * perf_data = (it == log.end()) ? nullptr : &(it->second);
532 
533  // If this event is not found in the log, then it could indicate
534  // that you have a STOP_LOG(a,b) without a corresponding
535  // START_LOG(a,b) call. We don't pop anything from the log_stack
536  // in this case.
537  if (!perf_data)
538  {
539  libMesh::err << "PerfLog can't pop (" << header << ',' << label << ')' << std::endl;
540  libMesh::err << "No such event was found in the log, you may have a mismatched START/STOP_LOG statement." << std::endl;
541  return;
542  }
543 
544  if (perf_data != log_stack.top())
545  {
546  // We've been asked to pop an event which is not at the
547  // top() of the log_stack. The event may be deeper in the
548  // stack instead, so search for it now. If we find it, we'll
549  // pop all intermediate items off the stack (abandoning any
550  // attempt to time them accurately) and let the optimized
551  // code path take over from there.
552  std::deque<PerfData*> tmp_stack;
553 
554  while (!log_stack.empty() && perf_data != log_stack.top())
555  {
556  tmp_stack.push_front(log_stack.top());
557  log_stack.pop();
558  }
559 
560  // If we exhaustively searched the log_stack without finding
561  // the event, we can't do anything else so just put
562  // everything back and return, not doing anything for this
563  // event.
564  if (log_stack.empty())
565  {
566  while (!tmp_stack.empty())
567  {
568  log_stack.push(tmp_stack.back());
569  tmp_stack.pop_back();
570  }
571 
572  return;
573  }
574  }
575 #endif
576 
577  // In optimized mode, we just pop from the top of the stack and
578  // resume timing the next entry.
579  total_time += log_stack.top()->stopit();
580 
581  log_stack.pop();
582 
583  if (!log_stack.empty())
584  log_stack.top()->restart();
585  }
586 }
587 
588 
589 
590 inline
592 {
593  struct timeval tnow;
594 
595  gettimeofday (&tnow, nullptr);
596 
597  const double elapsed_time = (static_cast<double>(tnow.tv_sec - tstart.tv_sec) +
598  static_cast<double>(tnow.tv_usec - tstart.tv_usec)*1.e-6);
599  return elapsed_time;
600 }
601 
602 inline
604 {
605  return total_time;
606 }
607 
608 } // namespace libMesh
609 
610 
611 
612 #endif // LIBMESH_PERFLOG_H
OStreamProxy err
double pause()
Definition: perf_log.h:426
double tot_time_incl_sub
Total time spent in this event, including sub-events.
Definition: perf_log.h:79
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.C:168
PerfLog(std::string label_name="", const bool log_events=true)
Constructor.
Definition: perf_log.C:55
int called_recursively
Definition: perf_log.h:125
double stopit()
Definition: perf_log.h:480
void disable_summarized_logs()
Tells the PerfLog to print detailed log results (this is the default behavior)
Definition: perf_log.h:197
void fast_push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.h:494
PerfData()
Constructor.
Definition: perf_log.h:60
The PerfData class simply contains the performance data that is recorded for individual events...
Definition: perf_log.h:53
void enable_logging()
Enables performance logging for an active object.
Definition: perf_log.h:181
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
int gettimeofday(struct timeval *tp, struct timezone *tzp)
double total_time
The total running time for recorded events.
Definition: perf_log.h:356
double get_elapsed_time() const
Definition: perf_log.h:591
PerfData & operator+=(const PerfData &other)
Sums timing results from other.
Definition: perf_log.h:115
double pause_for(PerfData &other)
Definition: perf_log.h:462
void stop_event(const std::string &label, const std::string &header="")
Stop monitoring the event named label.
Definition: perf_log.C:741
log_type log
The actual log.
Definition: perf_log.h:370
The libMesh namespace provides an interface to certain functionality in the library.
void fast_pop(const char *label, const char *header="") noexcept
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.h:514
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:375
bool summarized_logs_enabled()
Definition: perf_log.h:202
bool summarize_logs
Flag to optionally summarize logs.
Definition: perf_log.h:351
PerfData get_perf_data(const std::string &label, const std::string &header="")
Return the PerfData object associated with a label and header.
Definition: perf_log.C:709
The PerfLog class allows monitoring of specific events.
Definition: perf_log.h:145
void enable_summarized_logs()
Tells the PerfLog to only print log results summarized by header.
Definition: perf_log.h:191
std::string get_perf_info() const
Definition: perf_log.C:343
const std::string label_name
The label for this object.
Definition: perf_log.h:341
double stop_or_pause(const bool do_stop)
Definition: perf_log.h:433
double get_active_time() const
Definition: perf_log.h:603
std::map< std::pair< const char *, const char * >, PerfData > log_type
Typdef for the underlying logging data structure.
Definition: perf_log.h:333
libmesh_assert(ctx)
std::string get_log() const
Definition: perf_log.C:671
std::string get_info_header() const
Definition: perf_log.C:176
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.C:138
void restart_event(const std::string &label, const std::string &header="")
Restart monitoring the event.
Definition: perf_log.C:757
bool logging_enabled() const
Definition: perf_log.h:186
~PerfLog()
Destructor.
Definition: perf_log.C:70
void split_on_whitespace(const std::string &input, std::vector< std::string > &output) const
Splits a string on whitespace into a vector of separate strings.
Definition: perf_log.C:765
struct timeval tstart
Structure defining when the event was last started.
Definition: perf_log.h:85
struct timeval tstart_incl_sub
Structure defining when the event was last started, including sub-events.
Definition: perf_log.h:91
void clear()
Clears all the internal data and restores the data structures to a pristine state.
Definition: perf_log.C:78
double tot_time
Total time spent in this event.
Definition: perf_log.h:74
void print_log() const
Print the log.
Definition: perf_log.C:697
void pause_event(const std::string &label, const std::string &header="")
Suspend monitoring of the event.
Definition: perf_log.C:749
unsigned int count
The number of times this event has been executed.
Definition: perf_log.h:97
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:361
static bool called
Flag indicating if print_log() has been called.
Definition: perf_log.h:382
bool open
Flag indicating if we are currently monitoring this event.
Definition: perf_log.h:104
void disable_logging()
Disables performance logging for an active object.
Definition: perf_log.h:176
std::map< std::string, std::unique_ptr< const char[]> > non_temporary_strings
Workaround to give us fixed pointers to character arrays for every string.
Definition: perf_log.h:399
void start_event(const std::string &label, const std::string &header="")
Start monitoring the event named label.
Definition: perf_log.C:733