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 153 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 341 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:354
int gettimeofday(struct timeval *tp, struct timezone *tzp)
double total_time
The total running time for recorded events.
Definition: perf_log.h:364
bool summarize_logs
Flag to optionally summarize logs.
Definition: perf_log.h:359
const std::string label_name
The label for this object.
Definition: perf_log.h:349
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:369

◆ ~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:354
void print_log() const
Print the log.
Definition: perf_log.C:714

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_abort(), 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:354
int gettimeofday(struct timeval *tp, struct timezone *tzp)
log_type log
The actual log.
Definition: perf_log.h:378
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:383
const std::string label_name
The label for this object.
Definition: perf_log.h:349
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:369

◆ disable_logging()

void libMesh::PerfLog::disable_logging ( )
inline

Disables performance logging for an active object.

Definition at line 184 of file perf_log.h.

References log_events.

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

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

◆ 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 205 of file perf_log.h.

References summarize_logs.

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

◆ enable_logging()

void libMesh::PerfLog::enable_logging ( )
inline

Enables performance logging for an active object.

Definition at line 189 of file perf_log.h.

References log_events.

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

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

◆ enable_summarized_logs()

void libMesh::PerfLog::enable_summarized_logs ( )
inline

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

Definition at line 199 of file perf_log.h.

References summarize_logs.

Referenced by main().

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

◆ 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 539 of file perf_log.h.

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

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

541 {
542  if (this->log_events)
543  {
544  // The global perflog stack may not be thread-safe, but if we're
545  // creating threads we should have disabled it already
546  libmesh_exceptionless_assert(Threads::active_threads == 1);
547 #ifdef LIBMESH_HAVE_OPENMP
548  // Users might be doing their own non-libMesh threading. We
549  // can't catch every case of that but we can catch OpenMP.
550  libmesh_exceptionless_assert(omp_get_num_threads() == 1);
551 #endif
552 
553 #ifdef LIBMESH_HAVE_NVTX_API
554  nvtxRangePop();
555 #endif
556  // If there's nothing on the stack, then we can't pop anything. Previously we
557  // asserted that the log_stack was not empty, but we should not throw from
558  // this function, so instead just return in that case.
559  if (log_stack.empty())
560  return;
561 
562 #ifndef NDEBUG
563  // In debug mode, we carefully check that before popping the stack,
564  // we have the correct event.
565 
566  // Get pointer to corresponding PerfData, or nullptr if it does not exist.
567  auto it = log.find(std::make_pair(header, label));
568  PerfData * perf_data = (it == log.end()) ? nullptr : &(it->second);
569 
570  // If this event is not found in the log, then it could indicate
571  // that you have a STOP_LOG(a,b) without a corresponding
572  // START_LOG(a,b) call. We don't pop anything from the log_stack
573  // in this case.
574  if (!perf_data)
575  {
576  libMesh::err << "PerfLog can't pop (" << header << ',' << label << ')' << std::endl;
577  libMesh::err << "No such event was found in the log, you may have a mismatched START/STOP_LOG statement." << std::endl;
578  return;
579  }
580 
581  if (perf_data != log_stack.top())
582  {
583  // We've been asked to pop an event which is not at the
584  // top() of the log_stack. The event may be deeper in the
585  // stack instead, so search for it now. If we find it, we'll
586  // pop all intermediate items off the stack (abandoning any
587  // attempt to time them accurately) and let the optimized
588  // code path take over from there.
589  std::deque<PerfData*> tmp_stack;
590 
591  while (!log_stack.empty() && perf_data != log_stack.top())
592  {
593  tmp_stack.push_front(log_stack.top());
594  log_stack.pop();
595  }
596 
597  // If we exhaustively searched the log_stack without finding
598  // the event, we can't do anything else so just put
599  // everything back and return, not doing anything for this
600  // event.
601  if (log_stack.empty())
602  {
603  while (!tmp_stack.empty())
604  {
605  log_stack.push(tmp_stack.back());
606  tmp_stack.pop_back();
607  }
608 
609  return;
610  }
611  }
612 #endif
613 
614  // In optimized mode, we just pop from the top of the stack and
615  // resume timing the next entry.
616  total_time += log_stack.top()->stopit();
617 
618  log_stack.pop();
619 
620  if (!log_stack.empty())
621  log_stack.top()->restart();
622  }
623 }
OStreamProxy err
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:354
double total_time
The total running time for recorded events.
Definition: perf_log.h:364
log_type log
The actual log.
Definition: perf_log.h:378
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:383
int active_threads
An integer which is set to the number of active threads when we are in a Threads:: parallel operation...
Definition: threads.C:32

◆ 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 502 of file perf_log.h.

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

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

504 {
505  if (this->log_events)
506  {
507  // The global perflog stack may not be thread-safe, but if we're
508  // creating threads we should have disabled it already
509  libmesh_assert_equal_to(Threads::active_threads, 1);
510 #ifdef LIBMESH_HAVE_OPENMP
511  // Users might be doing their own non-libMesh threading. We
512  // can't catch every case of that but we can catch OpenMP
513  libmesh_assert_equal_to(omp_get_num_threads(), 1);
514 #endif
515 
516  // Get a reference to the event data to avoid
517  // repeated map lookups
518  PerfData * perf_data = &(log[std::make_pair(header,label)]);
519 
520  if (!log_stack.empty())
521  total_time += log_stack.top()->pause_for(*perf_data);
522  else
523  perf_data->start();
524  log_stack.push(perf_data);
525 
526 #ifdef LIBMESH_HAVE_NVTX_API
527  // This takes a single const char *, and we don't want to waste
528  // time allocating a new string on every push, so for now we'll
529  // drop the header. Maybe we should allocate a new string in
530  // the PerfData?
531  nvtxRangePushA(label);
532 #endif
533  }
534 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:354
double total_time
The total running time for recorded events.
Definition: perf_log.h:364
log_type log
The actual log.
Definition: perf_log.h:378
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition: perf_log.h:383
int active_threads
An integer which is set to the number of active threads when we are in a Threads:: parallel operation...
Definition: threads.C:32

◆ get_active_time()

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

Definition at line 640 of file perf_log.h.

References total_time.

641 {
642  return total_time;
643 }
double total_time
The total running time for recorded events.
Definition: perf_log.h:364

◆ get_elapsed_time()

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

Definition at line 628 of file perf_log.h.

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

629 {
630  struct timeval tnow;
631 
632  gettimeofday (&tnow, nullptr);
633 
634  const double elapsed_time = (static_cast<double>(tnow.tv_sec - tstart.tv_sec) +
635  static_cast<double>(tnow.tv_usec - tstart.tv_usec)*1.e-6);
636  return elapsed_time;
637 }
int gettimeofday(struct timeval *tp, struct timezone *tzp)
struct timeval tstart
The time we were constructed or last cleared.
Definition: perf_log.h:369

◆ get_info_header()

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

Definition at line 193 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().

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

◆ 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 688 of file perf_log.C.

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

Referenced by print_log().

689 {
690  std::ostringstream oss;
691 
692  if (log_events)
693  {
694  // Only print the log
695  // if it isn't empty
696  if (!log.empty())
697  {
698  // Possibly print machine info,
699  // but only do this once
700  if (!called)
701  {
702  called = true;
703  oss << get_info_header();
704  }
705  oss << get_perf_info();
706  }
707  }
708 
709  return oss.str();
710 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:354
log_type log
The actual log.
Definition: perf_log.h:378
std::string get_perf_info() const
Definition: perf_log.C:360
std::string get_info_header() const
Definition: perf_log.C:193
static bool called
Flag indicating if print_log() has been called.
Definition: perf_log.h:390

◆ 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 726 of file perf_log.C.

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

727 {
728  if (non_temporary_strings.count(label) &&
729  non_temporary_strings.count(header))
730  {
731  const char * label_c_str = non_temporary_strings[label].get();
732  const char * header_c_str = non_temporary_strings[header].get();
733  return log[std::make_pair(header_c_str, label_c_str)];
734  }
735 
736  auto iter = std::find_if
737  (log.begin(), log.end(),
738  [&label, &header] (log_type::const_reference a)
739  {
740  return
741  !std::strcmp(header.c_str(), a.first.first) &&
742  !std::strcmp(label.c_str(), a.first.second);
743  });
744 
745  libmesh_assert(iter != log.end());
746 
747  return iter->second;
748 }
log_type log
The actual log.
Definition: perf_log.h:378
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:407

◆ get_perf_info()

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

Definition at line 360 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().

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

◆ logging_enabled()

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

Definition at line 194 of file perf_log.h.

References log_events.

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

◆ pause_event()

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

Suspend monitoring of the event.

Definition at line 766 of file perf_log.C.

768 {
769  // nothing to do. pushing the next object on the stack will handle it
770 }

◆ 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 185 of file perf_log.C.

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

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

◆ 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 157 of file perf_log.C.

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

159 {
160  // The global perflog stack may not be thread-safe, but if we're
161  // creating threads we should have disabled it already
162  libmesh_assert_equal_to(Threads::active_threads, 1);
163 #ifdef LIBMESH_HAVE_OPENMP
164  // Users might be doing their own non-libMesh threading. We can't
165  // catch every case of that but we can catch OpenMP.
166  libmesh_exceptionless_assert(omp_get_num_threads() == 1);
167 #endif
168 
169  const char * label_c_str = non_temporary_strings[label].get();
170  const char * header_c_str = non_temporary_strings[header].get();
171 
172  // This could happen if users are *mixing* string and char* APIs for
173  // the same label/header combination. For perfect backwards
174  // compatibility we should handle that, but there's just no fast way
175  // to do so.
176  libmesh_assert(label_c_str);
177  libmesh_assert(header_c_str);
178 
179  if (this->log_events)
180  this->fast_pop(label_c_str, header_c_str);
181 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:354
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:539
libmesh_assert(ctx)
int active_threads
An integer which is set to the number of active threads when we are in a Threads:: parallel operation...
Definition: threads.C:32
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:407

◆ print_log()

void libMesh::PerfLog::print_log ( ) const

Print the log.

Definition at line 714 of file perf_log.C.

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

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

715 {
716  if (log_events)
717  {
718  // Check to see if the log_string is empty, and if so,
719  // avoid printing an unnecessary newline.
720  std::string log_string = this->get_log();
721  if (log_string.size() > 0)
722  libMesh::out << log_string << std::endl;
723  }
724 }
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:354
std::string get_log() const
Definition: perf_log.C:688
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 147 of file perf_log.C.

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

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

◆ 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 libMesh::Threads::active_threads, fast_push(), log_events, and non_temporary_strings.

104 {
105  // The global perflog stack may not be thread-safe, but if we're
106  // creating threads we should have disabled it already
107  libmesh_assert_equal_to(Threads::active_threads, 1);
108 #ifdef LIBMESH_HAVE_OPENMP
109  // Users might be doing their own non-libMesh threading. We can't
110  // catch every case of that but we can catch OpenMP.
111  libmesh_assert_equal_to(omp_get_num_threads(), 1);
112 #endif
113 
114  const char * label_c_str;
115  const char * header_c_str;
116 
117  if (const auto label_it = non_temporary_strings.find(label);
118  label_it != non_temporary_strings.end())
119  label_c_str = label_it->second.get();
120  else
121  {
122  const std::size_t labelsizep1 = label.size()+1;
123  auto newcopy = std::make_unique<char[]>(labelsizep1);
124  std::strncpy(newcopy.get(), label.c_str(), labelsizep1);
125  label_c_str = newcopy.get();
126  non_temporary_strings[label] = std::move(newcopy);
127  }
128 
129  if (const auto header_it = non_temporary_strings.find(header);
130  header_it != non_temporary_strings.end())
131  header_c_str = header_it->second.get();
132  else
133  {
134  const std::size_t headersizep1 = header.size()+1;
135  auto newcopy = std::make_unique<char[]>(headersizep1);
136  std::strncpy(newcopy.get(), header.c_str(), headersizep1);
137  header_c_str = newcopy.get();
138  non_temporary_strings[header] = std::move(newcopy);
139  }
140 
141  if (this->log_events)
142  this->fast_push(label_c_str, header_c_str);
143 }
void fast_push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.h:502
bool log_events
Flag to optionally disable all logging.
Definition: perf_log.h:354
int active_threads
An integer which is set to the number of active threads when we are in a Threads:: parallel operation...
Definition: threads.C:32
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:407

◆ restart_event()

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

Restart monitoring the event.

Definition at line 774 of file perf_log.C.

776 {
777  // nothing to do. popping the top off the stack will handle it.
778 }

◆ 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 782 of file perf_log.C.

Referenced by get_info_header().

783 {
784  // Check for easy return
785  if (input.size()==0)
786  return;
787 
788  // Here we hard-code the string to split on, since the algorithm below
789  // is somewhat specific to it...
790  const std::string split_on("' '");
791 
792  size_t current_pos = 0;
793  while (true)
794  {
795  // Find next end location
796  if (size_t end_pos = input.find(split_on, current_pos);
797  end_pos != std::string::npos)
798  {
799  // Create substring. Note: the second argument to substr is
800  // the *length* of string to create, not the ending position!
801  output.push_back( input.substr(current_pos, end_pos - current_pos + 1) );
802 
803  // Update search starting position, make sure to go past the end of the split_on string, but
804  // include the previous single quote (hence the -1).
805  current_pos = end_pos + split_on.size() - 1;
806  }
807  else
808  {
809  // Push back whatever remains of the string onto the output.
810  // Note that substr with only 1 argument pushes back
811  // whatever remains of the string. This also handles the
812  // case where the string does not contain any matches.
813  output.push_back( input.substr(current_pos) );
814 
815  // We are done searching the string, so break out of the while loop
816  break;
817  }
818  }
819 }

◆ start_event()

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

Start monitoring the event named label.

Definition at line 750 of file perf_log.C.

References push().

752 {
753  this->push(label,header);
754 }
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.C:147

◆ stop_event()

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

Stop monitoring the event named label.

Definition at line 758 of file perf_log.C.

References pop().

760 {
761  this->pop(label,header);
762 }
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.C:185

◆ 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 390 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 349 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 378 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 354 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 383 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 407 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 359 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 364 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: