libMesh
Loading...
Searching...
No Matches
perf_log.h
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20#ifndef LIBMESH_PERFLOG_H
21#define LIBMESH_PERFLOG_H
22
23
24// Local includes
25#include "libmesh/libmesh_common.h"
26
27#include "libmesh/threads.h"
28
29// C++ includes
30#include <cstddef>
31#include <map>
32#include <stack>
33#include <string>
34#include <vector>
35#include <deque>
36#include <memory>
37#ifdef LIBMESH_HAVE_SYS_TIME_H
38#include <sys/time.h> // gettimeofday() on Unix
39#endif
40#ifndef LIBMESH_HAVE_GETTIMEOFDAY
41#include "libmesh/win_gettimeofday.h" // gettimeofday() on Windows
42#endif
43#ifdef LIBMESH_HAVE_NVTX_API
44#include <nvtx3/nvtx3.hpp>
45#endif
46#ifdef LIBMESH_HAVE_OPENMP
47#include <omp.h>
48#endif
49
50namespace libMesh
51{
52
62{
63public:
64
69 tot_time(0.),
71 tstart(),
73 count(0),
74 open(false),
76 {}
77
78
82 double tot_time;
83
88
94
100
105 unsigned int count;
106
112 bool open;
113
114 void start ();
115 void restart ();
116 double pause ();
117 double pause_for(PerfData & other);
118 double stopit ();
119
124 {
126 tot_time += other.tot_time;
128 count += other.count;
129
130 return *this;
131 }
132
134
135protected:
136 double stop_or_pause(const bool do_stop);
137};
138
139
140
141
154{
155public:
156
164 PerfLog(std::string label_name="",
165 const bool log_events=true);
166
170 ~PerfLog();
171
179 void clear();
180
184 void disable_logging() { log_events = false; }
185
189 void enable_logging() { log_events = true; }
190
194 bool logging_enabled() const { return log_events; }
195
200
206
211
228 void fast_push (const char * label,
229 const char * header="",
230 bool per_entity=false);
231
241 void push (const char * label,
242 const char * header="");
243
251 void push (const std::string & label,
252 const std::string & header="");
253
265 void fast_pop (const char * label,
266 const char * header="",
267 bool per_entity=false) noexcept;
268
275 void pop (const char * label,
276 const char * header="");
277
285 void pop (const std::string & label,
286 const std::string & header="");
287
291 void start_event(const std::string & label,
292 const std::string & header="");
293
297 void stop_event(const std::string & label,
298 const std::string & header="");
299
303 void pause_event(const std::string & label,
304 const std::string & header="");
305
309 void restart_event(const std::string & label,
310 const std::string & header="");
311
317 std::string get_log() const;
318
322 std::string get_info_header() const;
323
327 std::string get_perf_info() const;
328
332 void print_log() const;
333
337 double get_elapsed_time() const;
338
342 double get_active_time() const;
343
347 PerfData get_perf_data(const std::string & label, const std::string & header="");
348
352 typedef std::map<std::pair<const char *,
353 const char *>,
355
356private:
357
358
362 const std::string label_name;
363
368
373
378
383
392
397
403 static bool called;
404
409 void split_on_whitespace(const std::string & input,
410 std::vector<std::string> & output) const;
411
420 std::map<std::string, std::unique_ptr<const char[]>> non_temporary_strings;
421};
422
423
424
425// ------------------------------------------------------------
426// PerfData class member functions
427inline
428void PerfData::start ()
429{
430 this->count++;
431 this->called_recursively++;
432 gettimeofday (&(this->tstart), nullptr);
433 this->tstart_incl_sub = this->tstart;
434}
435
436
437
438inline
440{
441 gettimeofday (&(this->tstart), nullptr);
442}
443
444
445
446inline
448{
449 return this->stop_or_pause(false);
450}
451
452
453inline
454double PerfData::stop_or_pause(const bool do_stop)
455{
456 // save the start times, reuse the structure we have rather than create
457 // a new one.
458 const time_t
459 tstart_tv_sec = this->tstart.tv_sec,
460 tstart_tv_usec = this->tstart.tv_usec;
461
462 gettimeofday (&(this->tstart), nullptr);
463
464 const double elapsed_time = (static_cast<double>(this->tstart.tv_sec - tstart_tv_sec) +
465 static_cast<double>(this->tstart.tv_usec - tstart_tv_usec)*1.e-6);
466
467 this->tot_time += elapsed_time;
468
469 if (do_stop)
470 {
471 const double elapsed_time_incl_sub = (static_cast<double>(this->tstart.tv_sec - this->tstart_incl_sub.tv_sec) +
472 static_cast<double>(this->tstart.tv_usec - this->tstart_incl_sub.tv_usec)*1.e-6);
473
474 this->tot_time_incl_sub += elapsed_time_incl_sub;
475 }
476
477 return elapsed_time;
478}
479
480
481
482inline
484{
485 gettimeofday (&(other.tstart), nullptr);
486
487 const double elapsed_time = (static_cast<double>(other.tstart.tv_sec - this->tstart.tv_sec) +
488 static_cast<double>(other.tstart.tv_usec - this->tstart.tv_usec)*1.e-6);
489 this->tot_time += elapsed_time;
490
491 other.count++;
492 other.called_recursively++;
493 other.tstart_incl_sub = other.tstart;
494
495 return elapsed_time;
496}
497
498
499
500inline
502{
503 // stopit is just similar to pause except that it decrements the
504 // recursive call counter
505
506 this->called_recursively--;
507 return this->stop_or_pause(true);
508}
509
510
511
512// ------------------------------------------------------------
513// PerfLog class inline member functions
514inline
515void PerfLog::fast_push (const char * label,
516 const char * header,
517 bool per_entity)
518{
519#ifndef LIBMESH_HAVE_NVTX_API
520 libmesh_ignore(per_entity);
521#endif
522
523 if (this->log_events)
524 {
525 // The global perflog stack may not be thread-safe, but if we're
526 // creating threads we should have disabled it already
527 libmesh_assert_equal_to(Threads::active_threads, 1);
528#ifdef LIBMESH_HAVE_OPENMP
529 // Users might be doing their own non-libMesh threading. We
530 // can't catch every case of that but we can catch OpenMP
531 libmesh_assert_equal_to(omp_get_num_threads(), 1);
532#endif
533
534 // Get a reference to the event data to avoid
535 // repeated map lookups
536 PerfData * perf_data = &(log[std::make_pair(header,label)]);
537
538 if (!log_stack.empty())
539 total_time += log_stack.top()->pause_for(*perf_data);
540 else
541 perf_data->start();
542 log_stack.push(perf_data);
543
544#ifdef LIBMESH_HAVE_NVTX_API
545 // This takes a single const char *, and we don't want to waste
546 // time allocating a new string on every push, so for now we'll
547 // drop the header. Maybe we should allocate a new string in
548 // the PerfData?
549 if (!per_entity)
550 nvtxRangePushA(label);
551#endif
552 }
553}
554
555
556
557inline
558void PerfLog::fast_pop(const char * libmesh_dbg_var(label),
559 const char * libmesh_dbg_var(header),
560 bool per_entity) noexcept
561{
562#ifndef LIBMESH_HAVE_NVTX_API
563 libmesh_ignore(per_entity);
564#endif
565
566 if (this->log_events)
567 {
568 // The global perflog stack may not be thread-safe, but if we're
569 // creating threads we should have disabled it already
570 libmesh_exceptionless_assert(Threads::active_threads == 1);
571#ifdef LIBMESH_HAVE_OPENMP
572 // Users might be doing their own non-libMesh threading. We
573 // can't catch every case of that but we can catch OpenMP.
574 libmesh_exceptionless_assert(omp_get_num_threads() == 1);
575#endif
576
577#ifdef LIBMESH_HAVE_NVTX_API
578 if (!per_entity)
579 nvtxRangePop();
580#endif
581 // If there's nothing on the stack, then we can't pop anything. Previously we
582 // asserted that the log_stack was not empty, but we should not throw from
583 // this function, so instead just return in that case.
584 if (log_stack.empty())
585 return;
586
587#ifndef NDEBUG
588 // In debug mode, we carefully check that before popping the stack,
589 // we have the correct event.
590
591 // Get pointer to corresponding PerfData, or nullptr if it does not exist.
592 auto it = log.find(std::make_pair(header, label));
593 PerfData * perf_data = (it == log.end()) ? nullptr : &(it->second);
594
595 // If this event is not found in the log, then it could indicate
596 // that you have a STOP_LOG(a,b) without a corresponding
597 // START_LOG(a,b) call. We don't pop anything from the log_stack
598 // in this case.
599 if (!perf_data)
600 {
601 libMesh::err << "PerfLog can't pop (" << header << ',' << label << ')' << std::endl;
602 libMesh::err << "No such event was found in the log, you may have a mismatched START/STOP_LOG statement." << std::endl;
603 return;
604 }
605
606 if (perf_data != log_stack.top())
607 {
608 // We've been asked to pop an event which is not at the
609 // top() of the log_stack. The event may be deeper in the
610 // stack instead, so search for it now. If we find it, we'll
611 // pop all intermediate items off the stack (abandoning any
612 // attempt to time them accurately) and let the optimized
613 // code path take over from there.
614 std::deque<PerfData*> tmp_stack;
615
616 while (!log_stack.empty() && perf_data != log_stack.top())
617 {
618 tmp_stack.push_front(log_stack.top());
619 log_stack.pop();
620 }
621
622 // If we exhaustively searched the log_stack without finding
623 // the event, we can't do anything else so just put
624 // everything back and return, not doing anything for this
625 // event.
626 if (log_stack.empty())
627 {
628 while (!tmp_stack.empty())
629 {
630 log_stack.push(tmp_stack.back());
631 tmp_stack.pop_back();
632 }
633
634 return;
635 }
636 }
637#endif
638
639 // In optimized mode, we just pop from the top of the stack and
640 // resume timing the next entry.
641 total_time += log_stack.top()->stopit();
642
643 log_stack.pop();
644
645 if (!log_stack.empty())
646 log_stack.top()->restart();
647 }
648}
649
650
651
652inline
654{
655 struct timeval tnow;
656
657 gettimeofday (&tnow, nullptr);
658
659 const double elapsed_time = (static_cast<double>(tnow.tv_sec - tstart.tv_sec) +
660 static_cast<double>(tnow.tv_usec - tstart.tv_usec)*1.e-6);
661 return elapsed_time;
662}
663
664inline
666{
667 return total_time;
668}
669
670} // namespace libMesh
671
672
673
674#endif // LIBMESH_PERFLOG_H
The PerfData class simply contains the performance data that is recorded for individual events.
Definition perf_log.h:62
double tot_time_incl_sub
Total time spent in this event, including sub-events.
Definition perf_log.h:87
PerfData & operator+=(const PerfData &other)
Sums timing results from other.
Definition perf_log.h:123
double stopit()
Definition perf_log.h:501
double pause_for(PerfData &other)
Definition perf_log.h:483
double stop_or_pause(const bool do_stop)
Definition perf_log.h:454
struct timeval tstart_incl_sub
Structure defining when the event was last started, including sub-events.
Definition perf_log.h:99
PerfData()
Constructor.
Definition perf_log.h:68
double tot_time
Total time spent in this event.
Definition perf_log.h:82
unsigned int count
The number of times this event has been executed.
Definition perf_log.h:105
struct timeval tstart
Structure defining when the event was last started.
Definition perf_log.h:93
bool open
Flag indicating if we are currently monitoring this event.
Definition perf_log.h:112
The PerfLog class allows monitoring of specific events.
Definition perf_log.h:154
void start_event(const std::string &label, const std::string &header="")
Start monitoring the event named label.
Definition perf_log.C:750
bool summarized_logs_enabled()
Definition perf_log.h:210
void print_log() const
Print the log.
Definition perf_log.C:714
double total_time
The total running time for recorded events.
Definition perf_log.h:377
void disable_logging()
Disables performance logging for an active object.
Definition perf_log.h:184
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition perf_log.C:185
void clear()
Clears all the internal data and restores the data structures to a pristine state.
Definition perf_log.C:78
void fast_push(const char *label, const char *header="", bool per_entity=false)
Push the event label onto the stack, pausing any active event.
Definition perf_log.h:515
std::string get_log() const
Definition perf_log.C:688
void restart_event(const std::string &label, const std::string &header="")
Restart monitoring the event.
Definition perf_log.C:774
std::string get_perf_info() const
Definition perf_log.C:360
double get_active_time() const
Definition perf_log.h:665
double get_elapsed_time() const
Definition perf_log.h:653
log_type log
The actual log.
Definition perf_log.h:391
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:420
std::map< std::pair< const char *, const char * >, PerfData > log_type
Typdef for the underlying logging data structure.
Definition perf_log.h:354
struct timeval tstart
The time we were constructed or last cleared.
Definition perf_log.h:382
~PerfLog()
Destructor.
Definition perf_log.C:70
void enable_logging()
Enables performance logging for an active object.
Definition perf_log.h:189
bool summarize_logs
Flag to optionally summarize logs.
Definition perf_log.h:372
void enable_summarized_logs()
Tells the PerfLog to only print log results summarized by header.
Definition perf_log.h:199
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition perf_log.C:147
void pause_event(const std::string &label, const std::string &header="")
Suspend monitoring of the event.
Definition perf_log.C:766
const std::string label_name
The label for this object.
Definition perf_log.h:362
PerfData get_perf_data(const std::string &label, const std::string &header="")
Return the PerfData object associated with a label and header.
Definition perf_log.C:726
bool logging_enabled() const
Definition perf_log.h:194
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
std::string get_info_header() const
Definition perf_log.C:193
void fast_pop(const char *label, const char *header="", bool per_entity=false) noexcept
Pop the event label off the stack, resuming any lower event.
Definition perf_log.h:558
void stop_event(const std::string &label, const std::string &header="")
Stop monitoring the event named label.
Definition perf_log.C:758
static bool called
Flag indicating if print_log() has been called.
Definition perf_log.h:403
bool log_events
Flag to optionally disable all logging.
Definition perf_log.h:367
void disable_summarized_logs()
Tells the PerfLog to print detailed log results (this is the default behavior)
Definition perf_log.h:205
std::stack< PerfData * > log_stack
A stack to hold the current performance log trace.
Definition perf_log.h:396
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
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
int gettimeofday(struct timeval *tp, struct timezone *tzp)