libMesh
Loading...
Searching...
No Matches
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.
 

Public Member Functions

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

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.
 

Private Attributes

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

Static Private Attributes

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

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.

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}
double total_time
The total running time for recorded events.
Definition perf_log.h:364
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
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
bool log_events
Flag to optionally disable all logging.
Definition perf_log.h:354
int gettimeofday(struct timeval *tp, struct timezone *tzp)

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

◆ ~PerfLog()

libMesh::PerfLog::~PerfLog ( )

Destructor.

Calls clear() and print_log().

Definition at line 70 of file perf_log.C.

71{
72 if (log_events)
73 this->print_log();
74}
void print_log() const
Print the log.
Definition perf_log.C:714

References log_events, and print_log().

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.

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}
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

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

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

◆ disable_logging()

void libMesh::PerfLog::disable_logging ( )
inline

Disables performance logging for an active object.

Definition at line 184 of file perf_log.h.

184{ log_events = false; }

References log_events.

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

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

205{ summarize_logs = false; }

References summarize_logs.

◆ enable_logging()

void libMesh::PerfLog::enable_logging ( )
inline

Enables performance logging for an active object.

Definition at line 189 of file perf_log.h.

189{ log_events = true; }

References log_events.

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

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

199{ summarize_logs = true; }

References summarize_logs.

Referenced by main().

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

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}
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
OStreamProxy err

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

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

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

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}

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

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

◆ get_active_time()

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

Definition at line 640 of file perf_log.h.

641{
642 return total_time;
643}

References total_time.

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

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}

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

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

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}
void ErrorVector unsigned int
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
Tnew cast_int(Told oldvar)
std::string get_timestamp()
Definition timestamp.C:37
processor_id_type global_processor_id()
processor_id_type global_n_processors()

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

Referenced by get_log().

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

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}
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

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

Referenced by print_log().

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

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}
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
libmesh_assert(ctx)

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

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

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)
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}
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

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().

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

194{ return log_events; }

References log_events.

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

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

References pop().

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

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

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}
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

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

◆ print_log()

void libMesh::PerfLog::print_log ( ) const

Print the log.

Definition at line 714 of file perf_log.C.

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}
std::string get_log() const
Definition perf_log.C:688
OStreamProxy out

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

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

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

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

References push().

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

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

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

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

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

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}

Referenced by get_info_header().

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

752{
753 this->push(label,header);
754}

References push().

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

760{
761 this->pop(label,header);
762}

References pop().

◆ 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: