libMesh
Public Types | Public Member Functions | Private Member Functions | Private Attributes | Static Private Attributes | List of all members
libMesh::PerfLog Class Reference

The PerfLog class allows monitoring of specific events. More...

#include <perf_log.h>

Public Types

typedef std::map< std::pair< const char *, const char * >, PerfDatalog_type
 Typdef for the underlying logging data structure. More...
 

Public Member Functions

 PerfLog (std::string label_name="", const bool log_events=true)
 Constructor. More...
 
 ~PerfLog ()
 Destructor. More...
 
void clear ()
 Clears all the internal data and restores the data structures to a pristine state. More...
 
void disable_logging ()
 Disables performance logging for an active object. More...
 
void enable_logging ()
 Enables performance logging for an active object. More...
 
bool logging_enabled () const
 
void enable_summarized_logs ()
 Tells the PerfLog to only print log results summarized by header. More...
 
void disable_summarized_logs ()
 Tells the PerfLog to print detailed log results (this is the default behavior) More...
 
bool summarized_logs_enabled ()
 
void fast_push (const char *label, const char *header="")
 Push the event label onto the stack, pausing any active event. More...
 
void push (const char *label, const char *header="")
 Push the event label onto the stack, pausing any active event. More...
 
void push (const std::string &label, const std::string &header="")
 Push the event label onto the stack, pausing any active event. More...
 
void fast_pop (const char *label, const char *header="") noexcept
 Pop the event label off the stack, resuming any lower event. More...
 
void pop (const char *label, const char *header="")
 Pop the event label off the stack, resuming any lower event. More...
 
void pop (const std::string &label, const std::string &header="")
 Pop the event label off the stack, resuming any lower event. More...
 
void start_event (const std::string &label, const std::string &header="")
 Start monitoring the event named label. More...
 
void stop_event (const std::string &label, const std::string &header="")
 Stop monitoring the event named label. More...
 
void pause_event (const std::string &label, const std::string &header="")
 Suspend monitoring of the event. More...
 
void restart_event (const std::string &label, const std::string &header="")
 Restart monitoring the event. More...
 
std::string get_log () const
 
std::string get_info_header () const
 
std::string get_perf_info () const
 
void print_log () const
 Print the log. More...
 
double get_elapsed_time () const
 
double get_active_time () const
 
PerfData get_perf_data (const std::string &label, const std::string &header="")
 Return the PerfData object associated with a label and header. More...
 

Private Member Functions

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. More...
 

Private Attributes

const std::string label_name
 The label for this object. More...
 
bool log_events
 Flag to optionally disable all logging. More...
 
bool summarize_logs
 Flag to optionally summarize logs. More...
 
double total_time
 The total running time for recorded events. More...
 
struct timeval tstart
 The time we were constructed or last cleared. More...
 
log_type log
 The actual log. More...
 
std::stack< PerfData * > log_stack
 A stack to hold the current performance log trace. More...
 
std::map< std::string, std::unique_ptr< const char[]> > non_temporary_strings
 Workaround to give us fixed pointers to character arrays for every string. More...
 

Static Private Attributes

static bool called = false
 Flag indicating if print_log() has been called. More...
 

Detailed Description

The PerfLog class allows monitoring of specific events.

An event is defined by a unique string that functions as a label. Each time the event is executed data are recorded. This class is particularly useful for finding performance bottlenecks.

Author
Benjamin Kirk
Date
2003 Responsible for timing and summarizing events.

Definition at line 145 of file perf_log.h.

Member Typedef Documentation

◆ log_type

typedef std::map<std::pair<const char *, const char *>, PerfData> libMesh::PerfLog::log_type

Typdef for the underlying logging data structure.

Definition at line 333 of file perf_log.h.

Constructor & Destructor Documentation

◆ PerfLog()

libMesh::PerfLog::PerfLog ( std::string  label_name = "",
const bool  log_events = true 
)

Constructor.

label_name is the name of the object, which will bw print in the log to distinguish it from other objects. log_events is a flag to optionally disable logging. You can use this flag to turn off logging without touching any other code.

Definition at line 55 of file perf_log.C.

References clear(), gettimeofday(), log_events, and tstart.

56  :
57  label_name(std::move(ln)),
58  log_events(le),
59  summarize_logs(false),
60  total_time(0.)
61 {
62  gettimeofday (&tstart, nullptr);
63 
64  if (log_events)
65  this->clear();
66 }
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
bool summarize_logs
Flag to optionally summarize logs.
Definition: perf_log.h:351
const std::string label_name
The label for this object.
Definition: perf_log.h:341
void clear()
Clears all the internal data and restores the data structures to a pristine state.
Definition: perf_log.C:78
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:361

◆ ~PerfLog()

libMesh::PerfLog::~PerfLog ( )

Destructor.

Calls clear() and print_log().

Definition at line 70 of file perf_log.C.

References log_events, and print_log().

71 {
72  if (log_events)
73  this->print_log();
74 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
void print_log() const
Print the log.
Definition: perf_log.C:697

Member Function Documentation

◆ clear()

void libMesh::PerfLog::clear ( )

Clears all the internal data and restores the data structures to a pristine state.

This function checks to see if it is currently monitoring any events, and if so errors. Be sure you are not logging any events when you call this function.

Definition at line 78 of file perf_log.C.

References gettimeofday(), label_name, log, log_events, log_stack, and tstart.

Referenced by libMesh::libmesh_terminate_handler(), main(), PerfLog(), and libMesh::LibMeshInit::~LibMeshInit().

79 {
80  if (log_events)
81  {
82  // check that all events are closed
83  for (auto pos : log)
84  libmesh_error_msg_if(pos.second.open,
85  "ERROR clearing performance log for class "
86  << label_name
87  << "\nevent "
88  << pos.first.second
89  << " is still being monitored!");
90 
91  gettimeofday (&tstart, nullptr);
92 
93  log.clear();
94 
95  while (!log_stack.empty())
96  log_stack.pop();
97  }
98 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
int gettimeofday(struct timeval *tp, struct timezone *tzp)
log_type log
The actual log.
Definition: perf_log.h:370
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:375
const std::string label_name
The label for this object.
Definition: perf_log.h:341
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:361

◆ disable_logging()

void libMesh::PerfLog::disable_logging ( )
inline

Disables performance logging for an active object.

Definition at line 176 of file perf_log.h.

References log_events.

Referenced by libMesh::Threads::DisablePerfLogInScope::DisablePerfLogInScope().

176 { log_events = false; }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346

◆ disable_summarized_logs()

void libMesh::PerfLog::disable_summarized_logs ( )
inline

Tells the PerfLog to print detailed log results (this is the default behavior)

Definition at line 197 of file perf_log.h.

References summarize_logs.

197 { summarize_logs = false; }
bool summarize_logs
Flag to optionally summarize logs.
Definition: perf_log.h:351

◆ enable_logging()

void libMesh::PerfLog::enable_logging ( )
inline

Enables performance logging for an active object.

Definition at line 181 of file perf_log.h.

References log_events.

Referenced by libMesh::Threads::DisablePerfLogInScope::~DisablePerfLogInScope().

181 { log_events = true; }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346

◆ enable_summarized_logs()

void libMesh::PerfLog::enable_summarized_logs ( )
inline

Tells the PerfLog to only print log results summarized by header.

Definition at line 191 of file perf_log.h.

References summarize_logs.

Referenced by main().

191 { summarize_logs = true; }
bool summarize_logs
Flag to optionally summarize logs.
Definition: perf_log.h:351

◆ fast_pop()

void libMesh::PerfLog::fast_pop ( const char *  label,
const char *  header = "" 
)
inlinenoexcept

Pop the event label off the stack, resuming any lower event.

This method must be passed the exact same pointers as were passed to fast_push, not merely pointers to identical strings. This method is called from the PerfItem destructor, so it should not throw. We have therefore marked it noexcept as a reminder.

Definition at line 514 of file perf_log.h.

References libMesh::err, log, log_events, log_stack, and total_time.

Referenced by pop(), and libMesh::PerfItem::~PerfItem().

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 }
OStreamProxy err
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
double total_time
The total running time for recorded events.
Definition: perf_log.h:356
log_type log
The actual log.
Definition: perf_log.h:370
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:375

◆ fast_push()

void libMesh::PerfLog::fast_push ( const char *  label,
const char *  header = "" 
)
inline

Push the event label onto the stack, pausing any active event.

Note - for speed the PerfLog directly considers the pointers here. Supply pointers to string literals or other character arrays whose lifetime will exceed the lifetime of the PerfLog object, not to temporarily allocated arrays.

Definition at line 494 of file perf_log.h.

References log, log_events, log_stack, libMesh::PerfData::start(), and total_time.

Referenced by libMesh::PerfItem::PerfItem(), and push().

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 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
double total_time
The total running time for recorded events.
Definition: perf_log.h:356
log_type log
The actual log.
Definition: perf_log.h:370
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:375

◆ get_active_time()

double libMesh::PerfLog::get_active_time ( ) const
inline
Returns
The active time

Definition at line 603 of file perf_log.h.

References total_time.

604 {
605  return total_time;
606 }
double total_time
The total running time for recorded events.
Definition: perf_log.h:356

◆ get_elapsed_time()

double libMesh::PerfLog::get_elapsed_time ( ) const
inline
Returns
The total time spent on this event.

Definition at line 591 of file perf_log.h.

References gettimeofday(), tstart, timeval::tv_sec, and timeval::tv_usec.

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 }
int gettimeofday(struct timeval *tp, struct timezone *tzp)
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:361

◆ get_info_header()

std::string libMesh::PerfLog::get_info_header ( ) const
Returns
A string containing ONLY the information header.

Definition at line 176 of file perf_log.C.

References libMesh::Utility::get_timestamp(), libMesh::global_n_processors(), libMesh::global_processor_id(), log_events, and split_on_whitespace().

Referenced by get_log().

177 {
178  std::ostringstream oss;
179 
180  if (log_events)
181  {
182  std::string date = Utility::get_timestamp();
183 
184 #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
185  // Get system information
186  struct utsname sysInfo;
187  uname(&sysInfo);
188 #endif
189 
190  // Get user information
191  //
192  // Some systems, for example Crays, actually have getpwuid on the head-node
193  // but (if I understand correctly) a dynamically-linked glibc is not available
194  // on the backend, which is running a reduced operating system like Compute
195  // Node Linux. Thus functions like getpwuid cannot be called. This makes
196  // automatically testing for the existence of getpwuid on the login node
197  // difficult. The configure test would work on the login node but will fail
198  // on the backend. Hence we have added a configure flag, --disable-getpwuid,
199  // to manually turn this off.
200 #ifdef LIBMESH_HAVE_GETPWUID
201  struct passwd * p = getpwuid(getuid());
202 #endif
203  oss << "\n";
204 
205  // Construct string stream objects for each of the outputs
206  std::ostringstream
207  pid_stream,
208  nprocs_stream,
209  time_stream,
210  os_stream,
211  host_stream,
212  osrel_stream,
213  osver_stream,
214  machine_stream,
215  user_stream;
216 
217 
218  // Put pointers to these streams in a vector
219  std::vector<std::ostringstream*> v;
220  v.push_back(&pid_stream);
221  v.push_back(&nprocs_stream);
222  v.push_back(&time_stream);
223  v.push_back(&os_stream);
224  v.push_back(&host_stream);
225  v.push_back(&osrel_stream);
226  v.push_back(&osver_stream);
227  v.push_back(&machine_stream);
228  v.push_back(&user_stream);
229 
230  // Fill string stream objects
232  {
233  pid_stream << "| Processor id: " << libMesh::global_processor_id();
234  nprocs_stream << "| Num Processors: " << libMesh::global_n_processors();
235  }
236 
237  time_stream << "| Time: ";
238  os_stream << "| OS: ";
239  host_stream << "| HostName: ";
240  osrel_stream << "| OS Release: ";
241  osver_stream << "| OS Version: ";
242  machine_stream << "| Machine: ";
243 
244  time_stream << date;
245 #ifdef LIBMESH_HAVE_SYS_UTSNAME_H
246  os_stream << sysInfo.sysname ;
247  host_stream << sysInfo.nodename ;
248  osrel_stream << sysInfo.release ;
249  osver_stream << sysInfo.version ;
250  machine_stream << sysInfo.machine ;
251 #else
252  os_stream << "Unknown";
253  host_stream << "Unknown";
254  osrel_stream << "Unknown";
255  osver_stream << "Unknown";
256  machine_stream << "Unknown";
257 
258 #endif
259  user_stream << "| Username: ";
260 #ifdef LIBMESH_HAVE_GETPWUID
261  if (p && p->pw_name)
262  user_stream << p->pw_name;
263  else
264 #endif
265  user_stream << "Unknown";
266 
267  // Parse the LIBMESH_CONFIGURE_INFO string literal before using it in PerfLog output
268  std::string libmesh_configure_info(LIBMESH_CONFIGURE_INFO);
269  std::vector<std::string> parsed_libmesh_configure_info;
270  this->split_on_whitespace(libmesh_configure_info,
271  parsed_libmesh_configure_info);
272 
273  // There should always be at at least one entry in
274  // parsed_libmesh_configure_info, even if the user just ran
275  // ../configure.
276  libmesh_assert_greater (parsed_libmesh_configure_info.size(), 0);
277 
278  // Find the longest string in all the streams
279  unsigned int max_length = 0;
280  for (auto & v_i : v)
281  if (v_i->str().size() > max_length)
282  max_length = cast_int<unsigned int>
283  (v_i->str().size());
284 
285  // Find the longest string in the parsed_libmesh_configure_info
286  for (auto & plci_i : parsed_libmesh_configure_info)
287  if (plci_i.size() > max_length)
288  max_length = cast_int<unsigned int> (plci_i.size());
289 
290  // Print dashed line for the header
291  oss << ' '
292  << std::string(max_length+1, '-')
293  << '\n';
294 
295  // Loop over all the strings and add end formatting
296  for (auto & v_i : v)
297  {
298  if (v_i->str().size())
299  oss << v_i->str()
300  << std::setw (cast_int<int>
301  (max_length + 4 - v_i->str().size()))
302  << std::right
303  << "|\n";
304  }
305 
306  // Print out configuration header plus first parsed string. The
307  // magic number 18 below accounts for the length of the word
308  // 'Configuration'.
309  oss << "| Configuration: "
310  << parsed_libmesh_configure_info[0]
311  << std::setw (cast_int<int>
312  (max_length + 4 -
313  parsed_libmesh_configure_info[0].size() - 18))
314  << std::right
315  << "|\n";
316 
317  // Loop over the parsed_libmesh_configure_info and add end formatting. The magic
318  // number 3 below accounts for the leading 'pipe' character and indentation
319  for (auto i : IntRange<std::size_t>(1, parsed_libmesh_configure_info.size()))
320  {
321  oss << "| "
322  << parsed_libmesh_configure_info[i]
323  << std::setw (cast_int<int>
324  (max_length + 4 -
325  parsed_libmesh_configure_info[i].size() - 3))
326  << std::right
327  << "|\n";
328  }
329 
330 
331  // Print dashed line
332  oss << ' '
333  << std::string(max_length+1, '-')
334  << '\n';
335  }
336 
337  return oss.str();
338 }
processor_id_type global_n_processors()
Definition: libmesh_base.h:75
std::string get_timestamp()
Definition: timestamp.C:37
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
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
processor_id_type global_processor_id()
Definition: libmesh_base.h:85

◆ get_log()

std::string libMesh::PerfLog::get_log ( ) const
Returns
A string containing: (1) Basic machine information (if first call) (2) The performance log

Definition at line 671 of file perf_log.C.

References called, get_info_header(), get_perf_info(), log, and log_events.

Referenced by print_log().

672 {
673  std::ostringstream oss;
674 
675  if (log_events)
676  {
677  // Only print the log
678  // if it isn't empty
679  if (!log.empty())
680  {
681  // Possibly print machine info,
682  // but only do this once
683  if (!called)
684  {
685  called = true;
686  oss << get_info_header();
687  }
688  oss << get_perf_info();
689  }
690  }
691 
692  return oss.str();
693 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
log_type log
The actual log.
Definition: perf_log.h:370
std::string get_perf_info() const
Definition: perf_log.C:343
std::string get_info_header() const
Definition: perf_log.C:176
static bool called
Flag indicating if print_log() has been called.
Definition: perf_log.h:382

◆ get_perf_data()

PerfData libMesh::PerfLog::get_perf_data ( const std::string &  label,
const std::string &  header = "" 
)

Return the PerfData object associated with a label and header.

Definition at line 709 of file perf_log.C.

References libMesh::libmesh_assert(), log, and non_temporary_strings.

710 {
711  if (non_temporary_strings.count(label) &&
712  non_temporary_strings.count(header))
713  {
714  const char * label_c_str = non_temporary_strings[label].get();
715  const char * header_c_str = non_temporary_strings[header].get();
716  return log[std::make_pair(header_c_str, label_c_str)];
717  }
718 
719  auto iter = std::find_if
720  (log.begin(), log.end(),
721  [&label, &header] (log_type::const_reference a)
722  {
723  return
724  !std::strcmp(header.c_str(), a.first.first) &&
725  !std::strcmp(label.c_str(), a.first.second);
726  });
727 
728  libmesh_assert(iter != log.end());
729 
730  return iter->second;
731 }
log_type log
The actual log.
Definition: perf_log.h:370
libmesh_assert(ctx)
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

◆ get_perf_info()

std::string libMesh::PerfLog::get_perf_info ( ) const
Returns
A string containing ONLY the log information

Definition at line 343 of file perf_log.C.

References libMesh::PerfData::count, gettimeofday(), label_name, log, log_events, libMesh::Real, summarize_logs, libMesh::PerfData::tot_time, libMesh::PerfData::tot_time_incl_sub, total_time, tstart, timeval::tv_sec, and timeval::tv_usec.

Referenced by get_log().

344 {
345  std::ostringstream oss;
346 
347  if (!log_events || log.empty())
348  return oss.str();
349 
350  // Stop timing for this event.
351  struct timeval tstop;
352 
353  gettimeofday (&tstop, nullptr);
354 
355  const double elapsed_time = (static_cast<double>(tstop.tv_sec - tstart.tv_sec) +
356  static_cast<double>(tstop.tv_usec - tstart.tv_usec)*1.e-6);
357 
358  // Figure out the formatting required based on the event names
359  // Unsigned ints for each of the column widths
360  unsigned int event_col_width = 30;
361  const unsigned int ncalls_col_width = 11;
362  const unsigned int tot_time_col_width = 12;
363  const unsigned int avg_time_col_width = 12;
364  const unsigned int tot_time_incl_sub_col_width = 12;
365  const unsigned int avg_time_incl_sub_col_width = 12;
366  const unsigned int pct_active_col_width = 9;
367  const unsigned int pct_active_incl_sub_col_width = 9;
368 
369  // Reset the event column width based on the longest event name plus
370  // a possible 2-character indentation, plus a space.
371  for (auto pos : log)
372  if (std::strlen(pos.first.second)+3 > event_col_width)
373  event_col_width = cast_int<unsigned int>
374  (std::strlen(pos.first.second)+3);
375 
376  // Set the total width of the column
377  const unsigned int total_col_width =
378  event_col_width +
379  ncalls_col_width +
380  tot_time_col_width +
381  avg_time_col_width +
382  tot_time_incl_sub_col_width +
383  avg_time_incl_sub_col_width +
384  pct_active_col_width+
385  pct_active_incl_sub_col_width+1;
386 
387  // Print dashed line
388  oss << ' '
389  << std::string(total_col_width, '-')
390  << '\n';
391 
392  {
393  // Construct temporary message string
394  std::ostringstream temp;
395  temp << "| " << label_name << " Performance: Alive time=" << elapsed_time
396  << ", Active time=" << total_time;
397 
398  // Get the size of the temporary string
399  const unsigned int temp_size = cast_int<unsigned int>
400  (temp.str().size());
401 
402  // Send the temporary message to the output
403  oss << temp.str();
404 
405  // If this string is longer than the previously computed total
406  // column width, skip the additional formatting... this shouldn't
407  // happen often, hopefully. Add two additional characters for a
408  // space and a "|" character at the end.
409  if (temp_size < total_col_width+2)
410  oss << std::setw(total_col_width - temp_size + 2)
411  << std::right
412  << "|";
413 
414  oss << '\n';
415  }
416 
417  // Print dashed line
418  oss << ' '
419  << std::string(total_col_width, '-')
420  << '\n';
421 
422 
423  // Write out the header for the events listing
424  oss << "| "
425  << std::setw(event_col_width)
426  << std::left
427  << "Event"
428  << std::setw(ncalls_col_width)
429  << std::left
430  << "nCalls"
431  << std::setw(tot_time_col_width)
432  << std::left
433  << "Total Time"
434  << std::setw(avg_time_col_width)
435  << std::left
436  << "Avg Time"
437  << std::setw(tot_time_incl_sub_col_width)
438  << std::left
439  << "Total Time"
440  << std::setw(avg_time_incl_sub_col_width)
441  << std::left
442  << "Avg Time"
443  << std::setw(pct_active_col_width+pct_active_incl_sub_col_width)
444  << std::left
445  << "% of Active Time"
446  << "|\n"
447  << "| "
448  << std::setw(event_col_width)
449  << std::left
450  << ""
451  << std::setw(ncalls_col_width)
452  << std::left
453  << ""
454  << std::setw(tot_time_col_width)
455  << std::left
456  << "w/o Sub"
457  << std::setw(avg_time_col_width)
458  << std::left
459  << "w/o Sub"
460  << std::setw(tot_time_incl_sub_col_width)
461  << std::left
462  << "With Sub"
463  << std::setw(avg_time_incl_sub_col_width)
464  << std::left
465  << "With Sub"
466  << std::setw(pct_active_col_width)
467  << std::left
468  << "w/o S"
469  << std::setw(pct_active_incl_sub_col_width)
470  << std::left
471  << "With S"
472  << "|\n|"
473  << std::string(total_col_width, '-')
474  << "|\n|"
475  << std::string(total_col_width, ' ')
476  << "|\n";
477 
478  unsigned int summed_function_calls = 0;
479  double summed_total_time = 0;
480  double summed_percentage = 0;
481 
482  std::string last_header("");
483 
484  // Make a new log to sort entries alphabetically
485  std::map<std::pair<std::string, std::string>, PerfData> string_log;
486 
487  for (auto char_data : log)
488  if (summarize_logs)
489  {
490  string_log[std::make_pair(std::string(), char_data.first.first)] +=
491  char_data.second;
492  }
493  else
494  {
495  string_log[std::make_pair(char_data.first.first,
496  char_data.first.second)] =
497  char_data.second;
498  }
499 
500  for (auto pos : string_log)
501  {
502  const PerfData & perf_data = pos.second;
503 
504  // Only print the event if the count is non-zero.
505  if (perf_data.count != 0)
506  {
507  const unsigned int perf_count = perf_data.count;
508  const double perf_time = perf_data.tot_time;
509  const double perf_avg_time = perf_time / static_cast<double>(perf_count);
510  const double perf_time_incl_sub = perf_data.tot_time_incl_sub;
511  const double perf_avg_time_incl_sub = perf_time_incl_sub / static_cast<double>(perf_count);
512  const double perf_percent = (total_time != 0.) ? perf_time / total_time * 100. : 0.;
513  const double perf_percent_incl_sub = (total_time != 0.) ? perf_time_incl_sub / total_time * 100. : 0.;
514 
515  summed_function_calls += perf_count;
516  summed_total_time += perf_time;
517  summed_percentage += perf_percent;
518 
519  // Print the event name
520  if (pos.first.first == "")
521  oss << "| "
522  << std::setw(event_col_width)
523  << std::left
524  << pos.first.second;
525 
526  else
527  {
528  if (last_header != pos.first.first)
529  {
530  last_header = pos.first.first;
531 
532  // print blank line followed by header name
533  // (account for additional space before the
534  // header)
535  oss << "|"
536  << std::string(total_col_width, ' ')
537  << "|\n| "
538  << std::setw(total_col_width-1)
539  << std::left
540  << pos.first.first
541  << "|\n";
542  }
543 
544  oss << "| "
545  << std::setw(event_col_width-2)
546  << std::left
547  << pos.first.second;
548  }
549 
550 
551  // Print the number of calls to the event.
552  oss << std::setw(ncalls_col_width)
553  << perf_count;
554 
555  // Save the original stream flags
556  std::ios_base::fmtflags out_flags = oss.flags();
557 
558  // Print the total time spent in the event
559  oss << std::fixed
560  << std::setprecision(4)
561  << std::setw(tot_time_col_width)
562  << std::left
563  << perf_time;
564 
565 
566  // Print the average time per function call
567  oss << std::fixed
568  << std::setprecision(6)
569  << std::setw(avg_time_col_width)
570  << std::left
571  << perf_avg_time;
572 
573  // Print the total time spent in the event incl. sub-events
574  oss << std::fixed
575  << std::setprecision(4)
576  << std::setw(tot_time_incl_sub_col_width)
577  << std::left
578  << perf_time_incl_sub;
579 
580  // Print the average time per function call incl. sub-events
581  oss << std::fixed
582  << std::setprecision(6)
583  << std::setw(avg_time_incl_sub_col_width)
584  << std::left
585  << perf_avg_time_incl_sub;
586 
587  // Print the percentage of the time spent in the event
588  oss << std::fixed
589  << std::setprecision(2)
590  << std::setw(pct_active_col_width)
591  << std::left
592  << perf_percent;
593 
594  // Print the percentage of the time spent in the event incl. sub-events
595  oss << std::fixed
596  << std::setprecision(2)
597  << std::setw(pct_active_incl_sub_col_width)
598  << std::left
599  << perf_percent_incl_sub;
600 
601  // Reset the stream flags
602  oss.flags(out_flags);
603 
604  oss << "|\n";
605  }
606  }
607 
608  oss << ' '
609  << std::string(total_col_width, '-')
610  << "\n| "
611  << std::setw(event_col_width)
612  << std::left
613  << "Totals:";
614 
615  // Print the total number of logged function calls
616  // For routines which are called many times, summed_function_calls may
617  // exceed 7 digits. If this happens use, scientific notation.
618  if (summed_function_calls < 9999999)
619  oss << std::setw(ncalls_col_width)
620  << summed_function_calls;
621 
622  else
623  {
624  // Save the original stream flags
625  std::ios_base::fmtflags out_flags = oss.flags();
626 
627  oss << std::scientific
628  << std::setprecision(3)
629  << std::setw(ncalls_col_width)
630  << std::left
631  << static_cast<Real>(summed_function_calls);
632 
633  // Reset the stream flags
634  oss.flags(out_flags);
635  }
636 
637  // Print the total time spent in logged function calls. Don't bother saving/restoring
638  // the flags here since we are almost done with this stream anyway...
639  oss << std::fixed
640  << std::setprecision(4)
641  << std::setw(tot_time_col_width)
642  << std::left
643  << summed_total_time;
644 
645  // Null, the average time doesn't make sense as a total
646  oss << std::setw(avg_time_col_width) << "";
647 
648  // Same for times that include sub-events
649  oss << std::setw(tot_time_incl_sub_col_width)
650  << ""
651  << std::setw(avg_time_incl_sub_col_width)
652  << "";
653 
654  // Print the total percentage followed by dashed line
655  oss << std::fixed
656  << std::setprecision(2)
657  << std::setw(pct_active_col_width)
658  << std::left
659  << summed_percentage
660  << std::setw(pct_active_incl_sub_col_width)
661  << ""
662  << "|\n "
663  << std::string(total_col_width, '-')
664  << '\n';
665 
666  return oss.str();
667 }
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
log_type log
The actual log.
Definition: perf_log.h:370
bool summarize_logs
Flag to optionally summarize logs.
Definition: perf_log.h:351
const std::string label_name
The label for this object.
Definition: perf_log.h:341
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:361

◆ logging_enabled()

bool libMesh::PerfLog::logging_enabled ( ) const
inline
Returns
true iff performance logging is enabled

Definition at line 186 of file perf_log.h.

References log_events.

186 { return log_events; }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346

◆ pause_event()

void libMesh::PerfLog::pause_event ( const std::string &  label,
const std::string &  header = "" 
)

Suspend monitoring of the event.

Definition at line 749 of file perf_log.C.

751 {
752  // nothing to do. pushing the next object on the stack will handle it
753 }

◆ pop() [1/2]

void libMesh::PerfLog::pop ( const char *  label,
const char *  header = "" 
)

Pop the event label off the stack, resuming any lower event.

This method will eventually be deprecated. Use fast_pop() (with the exact same pointers supplied to fast_push()) instead.

Definition at line 168 of file perf_log.C.

Referenced by assemble_biharmonic(), assemble_laplace(), assemble_poisson(), main(), stop_event(), and UnitPerfItem::~UnitPerfItem().

170 {
171  this->pop(std::string(label), std::string(header));
172 }
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.C:168

◆ pop() [2/2]

void libMesh::PerfLog::pop ( const std::string &  label,
const std::string &  header = "" 
)

Pop the event label off the stack, resuming any lower event.

This method will eventually be deprecated. String manipulation is too low performance to use when performance monitoring hot spots. Use fast_pop() instead.

Definition at line 148 of file perf_log.C.

References fast_pop(), libMesh::libmesh_assert(), log_events, and non_temporary_strings.

150 {
151 
152  const char * label_c_str = non_temporary_strings[label].get();
153  const char * header_c_str = non_temporary_strings[header].get();
154 
155  // This could happen if users are *mixing* string and char* APIs for
156  // the same label/header combination. For perfect backwards
157  // compatibility we should handle that, but there's just no fast way
158  // to do so.
159  libmesh_assert(label_c_str);
160  libmesh_assert(header_c_str);
161 
162  if (this->log_events)
163  this->fast_pop(label_c_str, header_c_str);
164 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
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
libmesh_assert(ctx)
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

◆ print_log()

void libMesh::PerfLog::print_log ( ) const

Print the log.

Definition at line 697 of file perf_log.C.

References get_log(), log_events, and libMesh::out.

Referenced by libMesh::libmesh_terminate_handler(), libMesh::LibMeshInit::~LibMeshInit(), and ~PerfLog().

698 {
699  if (log_events)
700  {
701  // Check to see if the log_string is empty, and if so,
702  // avoid printing an unnecessary newline.
703  std::string log_string = this->get_log();
704  if (log_string.size() > 0)
705  libMesh::out << log_string << std::endl;
706  }
707 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
std::string get_log() const
Definition: perf_log.C:671
OStreamProxy out

◆ push() [1/2]

void libMesh::PerfLog::push ( const char *  label,
const char *  header = "" 
)

Push the event label onto the stack, pausing any active event.

This method will eventually be deprecated. For backwards compatibility, the PerfLog must copy the contents of these character arrays into strings, which ironically damages the performance we are trying to profile. Use fast_push() (with compatible long-lived character array data) instead.

Definition at line 138 of file perf_log.C.

Referenced by assemble_biharmonic(), assemble_laplace(), assemble_poisson(), main(), start_event(), and UnitPerfItem::UnitPerfItem().

140 {
141  this->push(std::string(label), std::string(header));
142 }
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.C:138

◆ push() [2/2]

void libMesh::PerfLog::push ( const std::string &  label,
const std::string &  header = "" 
)

Push the event label onto the stack, pausing any active event.

This method will eventually be deprecated. String manipulation is too low performance to use when performance monitoring hot spots. Use fast_push() instead.

Definition at line 102 of file perf_log.C.

References fast_push(), log_events, and non_temporary_strings.

104 {
105  const char * label_c_str;
106  const char * header_c_str;
107 
108  auto label_it = non_temporary_strings.find(label);
109  if (label_it != non_temporary_strings.end())
110  label_c_str = label_it->second.get();
111  else
112  {
113  const std::size_t labelsizep1 = label.size()+1;
114  auto newcopy = std::make_unique<char[]>(labelsizep1);
115  std::strncpy(newcopy.get(), label.c_str(), labelsizep1);
116  label_c_str = newcopy.get();
117  non_temporary_strings[label] = std::move(newcopy);
118  }
119 
120  auto header_it = non_temporary_strings.find(header);
121  if (header_it != non_temporary_strings.end())
122  header_c_str = header_it->second.get();
123  else
124  {
125  const std::size_t headersizep1 = header.size()+1;
126  auto newcopy = std::make_unique<char[]>(headersizep1);
127  std::strncpy(newcopy.get(), header.c_str(), headersizep1);
128  header_c_str = newcopy.get();
129  non_temporary_strings[header] = std::move(newcopy);
130  }
131 
132  if (this->log_events)
133  this->fast_push(label_c_str, header_c_str);
134 }
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
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:346
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

◆ restart_event()

void libMesh::PerfLog::restart_event ( const std::string &  label,
const std::string &  header = "" 
)

Restart monitoring the event.

Definition at line 757 of file perf_log.C.

759 {
760  // nothing to do. popping the top off the stack will handle it.
761 }

◆ split_on_whitespace()

void libMesh::PerfLog::split_on_whitespace ( const std::string &  input,
std::vector< std::string > &  output 
) const
private

Splits a string on whitespace into a vector of separate strings.

This is used to make the LIBMESH_CONFIGURE_INFO a little more manageable.

Definition at line 765 of file perf_log.C.

Referenced by get_info_header().

766 {
767  // Check for easy return
768  if (input.size()==0)
769  return;
770 
771  // Here we hard-code the string to split on, since the algorithm below
772  // is somewhat specific to it...
773  const std::string split_on("' '");
774 
775  size_t current_pos = 0;
776  while (true)
777  {
778  // Find next end location
779  size_t end_pos = input.find(split_on, current_pos);
780 
781  if (end_pos != std::string::npos)
782  {
783  // Create substring. Note: the second argument to substr is
784  // the *length* of string to create, not the ending position!
785  output.push_back( input.substr(current_pos, end_pos - current_pos + 1) );
786 
787  // Update search starting position, make sure to go past the end of the split_on string, but
788  // include the previous single quote (hence the -1).
789  current_pos = end_pos + split_on.size() - 1;
790  }
791  else
792  {
793  // Push back whatever remains of the string onto the output.
794  // Note that substr with only 1 argument pushes back
795  // whatever remains of the string. This also handles the
796  // case where the string does not contain any matches.
797  output.push_back( input.substr(current_pos) );
798 
799  // We are done searching the string, so break out of the while loop
800  break;
801  }
802  }
803 }

◆ start_event()

void libMesh::PerfLog::start_event ( const std::string &  label,
const std::string &  header = "" 
)

Start monitoring the event named label.

Definition at line 733 of file perf_log.C.

References push().

735 {
736  this->push(label,header);
737 }
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.C:138

◆ stop_event()

void libMesh::PerfLog::stop_event ( const std::string &  label,
const std::string &  header = "" 
)

Stop monitoring the event named label.

Definition at line 741 of file perf_log.C.

References pop().

743 {
744  this->pop(label,header);
745 }
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.C:168

◆ summarized_logs_enabled()

bool libMesh::PerfLog::summarized_logs_enabled ( )
inline

Member Data Documentation

◆ called

bool libMesh::PerfLog::called = false
staticprivate

Flag indicating if print_log() has been called.

This is used to print a header with machine-specific data the first time that print_log() is called.

Definition at line 382 of file perf_log.h.

Referenced by get_log().

◆ label_name

const std::string libMesh::PerfLog::label_name
private

The label for this object.

Definition at line 341 of file perf_log.h.

Referenced by clear(), and get_perf_info().

◆ log

log_type libMesh::PerfLog::log
private

The actual log.

An unsorted_map would work fine here and would be asymptotically faster, but in my tests for our log sizes there was no improvement.

Definition at line 370 of file perf_log.h.

Referenced by clear(), fast_pop(), fast_push(), get_log(), get_perf_data(), and get_perf_info().

◆ log_events

bool libMesh::PerfLog::log_events
private

Flag to optionally disable all logging.

Definition at line 346 of file perf_log.h.

Referenced by clear(), disable_logging(), enable_logging(), fast_pop(), fast_push(), get_info_header(), get_log(), get_perf_info(), logging_enabled(), PerfLog(), pop(), print_log(), push(), and ~PerfLog().

◆ log_stack

std::stack<PerfData*> libMesh::PerfLog::log_stack
private

A stack to hold the current performance log trace.

Definition at line 375 of file perf_log.h.

Referenced by clear(), fast_pop(), and fast_push().

◆ non_temporary_strings

std::map<std::string, std::unique_ptr<const char[]> > libMesh::PerfLog::non_temporary_strings
private

Workaround to give us fixed pointers to character arrays for every string.

Using std::set instead might work: it won't invalidate iterators, which I think means it doesn't have any reason to modify or copy their contents or otherwise invalidate their c_str() pointers... but I can't prove it from the standards doc, so let's be safe.

Definition at line 399 of file perf_log.h.

Referenced by get_perf_data(), pop(), and push().

◆ summarize_logs

bool libMesh::PerfLog::summarize_logs
private

Flag to optionally summarize logs.

Definition at line 351 of file perf_log.h.

Referenced by disable_summarized_logs(), enable_summarized_logs(), get_perf_info(), and summarized_logs_enabled().

◆ total_time

double libMesh::PerfLog::total_time
private

The total running time for recorded events.

Definition at line 356 of file perf_log.h.

Referenced by fast_pop(), fast_push(), get_active_time(), and get_perf_info().

◆ tstart

struct timeval libMesh::PerfLog::tstart
private

The documentation for this class was generated from the following files: