Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_StackedTimer.hpp
1 // @HEADER BEGIN
2 // @HEADER END
3 
4 #ifndef TEUCHOS_STACKED_TIMER_HPP
5 #define TEUCHOS_STACKED_TIMER_HPP
6 
7 #include "Teuchos_ConfigDefs.hpp"
8 #include "Teuchos_Comm.hpp"
9 #include "Teuchos_DefaultComm.hpp"
10 #include "Teuchos_CommHelpers.hpp"
11 #include "Teuchos_RCP.hpp"
12 #include "Teuchos_Array.hpp"
14 #include <string>
15 #include <vector>
16 #include <cassert>
17 #include <chrono>
18 #include <climits>
19 #include <cstdlib> // for std::getenv
20 #include <iostream>
21 
22 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOSCORE)
23 namespace Kokkos {
24 namespace Profiling {
25 extern void pushRegion (const std::string&);
26 extern void popRegion ();
27 } // namespace Profiling
28 } // namespace Kokkos
29 #endif
30 
31 
32 namespace Teuchos {
33 
35 void error_out(const std::string& msg, const bool fail_all = false);
36 
46 class BaseTimer {
47 
48 public:
49 
50  using Clock = std::chrono::high_resolution_clock;
51 
52  BaseTimer() : accumulation_(0.0), count_started_(0), count_updates_(0), running_(false) {}
53 
55  void start(){
56  if (running_)
57  error_out("Base_Timer:start Failed timer already running");
58  start_time_ = Clock::now();
59 
60  count_started_++;
61  running_ = true;
62  }
63 
65  void stop(){
66  if (!running_)
67  error_out("Base_Timer:stop Failed timer not running");
68  accumulation_ += std::chrono::duration_cast<std::chrono::duration<double>>(Clock::now() - start_time_).count();
69  running_ = false;
70  }
71 
73  unsigned long long incrementUpdates(unsigned long long count=1) {count_updates_ += count; return count_updates_;}
74 
76  double accumulatedTime() const {return accumulation_;}
77 
79  void setAccumulatedTime(double accum=0) {accumulation_=accum;}
80  double accumulatedTimePerUpdate() const {
90  if (count_updates_ > 0) {
91  return accumulation_/count_updates_;
92  } else {
93  return 0;
94  }
95  }
96 
97 
106  if (count_started_> 0) {
107  return accumulation_/count_started_;
108  } else {
109  return 0;
110  }
111  }
112 
119  double difference(const BaseTimer &from) const {
120  return accumulation_ - from.accumulation_;
121  }
122 
124  void reset() {
125  if (running_)
126  error_out("BaseTimer, cannot reset a running timer");
127  accumulation_ = 0.0;
128  count_started_ = count_updates_ = 0;
129  }
130 
132  bool running() const { return running_;}
133 
135  unsigned long numCalls() const { return count_started_; }
136 
138  unsigned long long numUpdates() const { return count_updates_; }
139 
141  void overrideNumCallsForUnitTesting(const unsigned long num_calls)
142  { count_started_ = num_calls; }
143 
145  void overrideNumUpdatesForUnitTesting(const unsigned long long num_updates)
146  { count_updates_ = num_updates; }
147 
148  struct TimeInfo {
149  TimeInfo():time(0.0), count(0), updates(0), running(false){}
150  TimeInfo(BaseTimer* t): time(t->accumulation_), count(t->count_started_), updates(t->count_updates_), running(t->running()) {}
151  double time;
152  unsigned long count;
153  unsigned long long updates;
154  bool running;
155  };
156 
157 protected:
158  double accumulation_; // total time
159  unsigned long count_started_; // Number of times this timer has been started
160  unsigned long long count_updates_; // Total count of items updated during this timer
161  Clock::time_point start_time_;
162  bool running_;
163 
164  friend struct TimeInfo;
165 };
166 
185 {
186 protected:
187 
196  class LevelTimer : public BaseTimer {
197  protected:
198 
199  // TODO: implement operator=
200 
201  unsigned level_;
202  std::string name_;
203  LevelTimer *parent_;
204  std::vector<LevelTimer> sub_timers_;
205  public:
207  LevelTimer();
208 
216  LevelTimer(int level,
217  const char* name = "RootTimer",
218  LevelTimer *parent=nullptr,
219  bool start_timer=true) :
220  BaseTimer(),
221  level_(level),
222  name_(name),
223  parent_(parent)
224  {
225  if ( start_timer )
227 
228  }
229 
231  LevelTimer(const LevelTimer &src) :
232  BaseTimer(src), level_(src.level_), name_(src.name_),parent_(src.parent_), sub_timers_(src.sub_timers_)
233  {
234  for (unsigned i=0;i<sub_timers_.size();++i)
235  sub_timers_[i].parent_ = this;
236  }
237 
243  LevelTimer* start(const char* sub_name) {
244  for (unsigned i=0;i<sub_timers_.size();i++ )
245  if (sub_name == sub_timers_[i].name_ ) {
246  sub_timers_[i].BaseTimer::start();
247  return &sub_timers_[i];
248  }
249  sub_timers_.push_back(LevelTimer(level_+1,sub_name,this,true));
250  return &sub_timers_[sub_timers_.size()-1];
251  }
252 
260  LevelTimer* stop(const std::string &name = "RootTimer") {
261  if (name != name_)
262  error_out("Stopping timer "+name+" But top level running timer is "+name_);
263  BaseTimer::stop();
264  return parent_;
265  }
266 
267 
272  std::string get_full_name() const {
273  std::string parent_name("");
274  if ((parent_ != nullptr))
275  parent_name = parent_->get_full_name() + "@";
276 
277  std::string my_name(name_);
278 
279  std::string full_name = parent_name + my_name;
280  return full_name;
281  }
282 
288  int countTimers() {
289  int count=1;
290  for (unsigned i=0;i<sub_timers_.size(); ++i)
291  count += sub_timers_[i].countTimers();
292  return count;
293  }
294 
295  void addTimerNames(Array<std::string> &names, unsigned &pos) {
296  names[pos++] = get_full_name();
297  for (unsigned i=0;i<sub_timers_.size(); ++i)
298  sub_timers_[i].addTimerNames(names, pos);
299  }
300 
306  double accumulatedTime(const std::string &locate_name="") {
307 
308  if (locate_name == "")
310 
311  std::string first_name,second_name;
312 
313  size_t i = locate_name.find_first_of('@');
314  if ( i >= locate_name.size() ) {
315  first_name = locate_name;
316  second_name = "";
317  } else {
318  first_name.assign(locate_name,0,i);
319  second_name.assign(locate_name,i+1,locate_name.size()-i-1);
320  }
321  for (unsigned j=0;j<sub_timers_.size();++j)
322  if ( first_name == sub_timers_[j].name_)
323  return sub_timers_[j].accumulatedTime(second_name);
324  return 0;
325  }
326 
327  protected:
334  void splitString(const std::string &locate_name, std::string &first_name, std::string &second_name) {
335  size_t i = locate_name.find_first_of('@');
336  if ( i >= locate_name.size() ) {
337  first_name = locate_name;
338  second_name = "";
339  } else {
340  first_name.assign(locate_name,0,i);
341  second_name.assign(locate_name,i+1,locate_name.size()-i-1);
342  }
343  }
344 
345  public:
351  double accumulatedTimePerUpdate(const std::string &locate_name="") {
352 
353  if (locate_name == "")
355 
356  std::string first_name,second_name;
357  splitString(locate_name, first_name, second_name);
358 
359  for (unsigned j=0;j<sub_timers_.size();j++)
360  if ( first_name == sub_timers_[j].name_)
361  return sub_timers_[j].accumulatedTimePerUpdate(second_name);
362  return 0;
363  }
364 
370  double accumulatedTimePerTimerCall(const std::string &locate_name="") {
371 
372  if (locate_name == "")
374 
375  std::string first_name,second_name;
376  splitString(locate_name, first_name, second_name);
377 
378  for (unsigned j=0;j<sub_timers_.size();j++)
379  if ( first_name == sub_timers_[j].name_)
380  return sub_timers_[j].accumulatedTimePerTimerCall(second_name);
381  return 0;
382  }
383 
387  void pack();
388 
394  LevelTimer* unpack(unsigned from);
395 
400  void report(std::ostream &os);
401 
407  const BaseTimer* findBaseTimer(const std::string &name) const;
408 
415  BaseTimer::TimeInfo findTimer(const std::string &name,bool& found);
416 
417  protected:
418 
419 
420  }; // LevelTimer
421 
422 
423 
424 
425 public:
431  explicit StackedTimer(const char *name, const bool start_base_timer = true)
432  : timer_(0,name,nullptr,false),
433  enable_verbose_(false),
434  verbose_ostream_(Teuchos::rcpFromRef(std::cout))
435  {
436  top_ = &timer_;
437  if (start_base_timer)
438  this->startBaseTimer();
439 
440  auto check_verbose = std::getenv("TEUCHOS_ENABLE_VERBOSE_TIMERS");
441  if (check_verbose != nullptr)
442  enable_verbose_ = true;
443  }
444 
448  void startBaseTimer() {
449  timer_.BaseTimer::start();
450 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOSCORE)
451  ::Kokkos::Profiling::pushRegion(timer_.get_full_name());
452 #endif
453  }
454 
458  void stopBaseTimer() {
459  timer_.BaseTimer::stop();
460 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOSCORE)
461  ::Kokkos::Profiling::popRegion();
462 #endif
463  }
464 
470  void start(const std::string name,
471  const bool push_kokkos_profiling_region = true) {
472  if (top_ == nullptr)
473  top_ = timer_.start(name.c_str());
474  else
475  top_ = top_->start(name.c_str());
476 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOSCORE)
477  if (push_kokkos_profiling_region) {
478  ::Kokkos::Profiling::pushRegion(name);
479  }
480 #endif
481  if (enable_verbose_)
482  *verbose_ostream_ << "STARTING: " << name << std::endl;
483  }
484 
490  void stop(const std::string &name,
491  const bool pop_kokkos_profiling_region = true) {
492  if (top_)
493  top_ = top_->stop(name);
494  else
495  timer_.BaseTimer::stop();
496 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOSCORE)
497  if (pop_kokkos_profiling_region) {
498  ::Kokkos::Profiling::popRegion();
499  }
500 #endif
501  if (enable_verbose_)
502  *verbose_ostream_ << "STOPPING: " << name << std::endl;
503  }
504 
509  void incrementUpdates(const long long i = 1) {
511  }
512 
518  double accumulatedTime(const std::string &name="") {
519  if (top_) // Top is null for the head node when nothing is running
520  return top_->accumulatedTime(name);
521  else
522  return timer_.accumulatedTime(name);
523  }
524 
530  double accumulatedTimePerUpdate(const std::string &name="") {
531  if (top_) // Top is null for the head node when nothing is running
532  return top_->accumulatedTimePerUpdate(name);
533  else
534  return timer_.accumulatedTimePerUpdate(name);
535  }
541  double accumulatedTimePerTimerCall(const std::string &name="") {
542  if (top_) // Top is null for the head node when nothing is running
543  return top_->accumulatedTimePerTimerCall(name);
544  else
545  return timer_.accumulatedTimePerTimerCall(name);
546  }
547 
553  const BaseTimer* findBaseTimer(const std::string &name) const {
554  const BaseTimer* baseTimer = timer_.findBaseTimer(name);
555  TEUCHOS_TEST_FOR_EXCEPTION(baseTimer == nullptr, std::runtime_error,
556  "StackedTimer::findBaseTimer() failed to find a timer named \"" << name << "\"!\n");
557  return baseTimer;
558  }
559 
565  BaseTimer::TimeInfo findTimer(const std::string &name) {
566  bool foundTimer = false;
567  const auto timeInfo = timer_.findTimer(name,foundTimer);
568  TEUCHOS_TEST_FOR_EXCEPTION(!foundTimer, std::runtime_error,
569  "StackedTimer::findTimer() failed to find a timer named \"" << name << "\"!\n");
570  return timeInfo;
571  }
572 
573  void report(std::ostream &os) {
574  timer_.report(os);
575  }
576 
578  struct OutputOptions {
579  OutputOptions() : output_fraction(false), output_total_updates(false), output_histogram(false),
580  output_minmax(false), num_histogram(10), max_levels(INT_MAX),
581  print_warnings(true), align_columns(false), print_names_before_values(true) {}
582  bool output_fraction;
583  bool output_total_updates;
584  bool output_histogram;
585  bool output_minmax;
586  int num_histogram;
587  int max_levels;
588  bool print_warnings;
589  bool align_columns;
590  bool print_names_before_values;
591  };
592 
598  void report(std::ostream &os, Teuchos::RCP<const Teuchos::Comm<int> > comm, OutputOptions options = OutputOptions());
599 
600 
601  // If set to true, print timer start/stop to verbose ostream.
602  void enableVerbose(const bool enable_verbose);
603 
604  // Set the ostream for verbose mode(defaults to std::cout).
605  void setVerboseOstream(const Teuchos::RCP<std::ostream>& os);
606 
607 protected:
612 
613  Array<std::string> flat_names_;
614  Array<double> min_;
615  Array<double> max_;
616  Array<double> sum_;
617  Array<double> sum_sq_;
618  Array<Array<int>> hist_;
619  Array<unsigned long> count_;
620  Array<unsigned long long> updates_;
621  Array<int> active_;
622 
625  std::string::size_type timer_names_;
626  std::string::size_type average_time_;
627  std::string::size_type fraction_;
628  std::string::size_type count_;
629  std::string::size_type total_updates_;
630  std::string::size_type min_;
631  std::string::size_type max_;
632  std::string::size_type stddev_;
633  std::string::size_type histogram_;
634  AlignmentWidths() :
635  timer_names_(0),
636  average_time_(0),
637  fraction_(0),
638  count_(0),
639  total_updates_(0),
640  min_(0),
641  max_(0),
642  stddev_(0),
643  histogram_(0){}
644  } alignments_;
645 
648 
651 
655  void flatten();
656 
661  void merge(Teuchos::RCP<const Teuchos::Comm<int> > comm);
662 
666  void collectRemoteData(Teuchos::RCP<const Teuchos::Comm<int> > comm, const OutputOptions &options );
667 
674  double computeColumnWidthsForAligment(std::string prefix, int print_level,
675  std::vector<bool> &printed, double parent_time,
676  const OutputOptions &options);
677 
681  double printLevel(std::string prefix, int level, std::ostream &os, std::vector<bool> &printed,
682  double parent_time, const OutputOptions &options);
683 
684 }; //StackedTimer
685 
686 
687 } //namespace Teuchos
688 
689 #endif /* TEUCHOS_STACKED_TIMER_HPP */
void setAccumulatedTime(double accum=0)
Setter for accumulated time.
double accumulatedTimePerTimerCall(const std::string &name="")
double difference(const BaseTimer &from) const
Return the difference between two timers in seconds,.
StackedTimer(const char *name, const bool start_base_timer=true)
void overrideNumUpdatesForUnitTesting(const unsigned long long num_updates)
Sets the number of counts for this timer. This is only used for unit testing.
double accumulatedTime() const
Get the total accumulated time since last reset or construction when the timer is running...
void splitString(const std::string &locate_name, std::string &first_name, std::string &second_name)
split a string into two parts split by a &#39;@&#39; if no &#39;@&#39; first gets the full string ...
void stop(const std::string &name, const bool pop_kokkos_profiling_region=true)
LevelTimer(int level, const char *name="RootTimer", LevelTimer *parent=nullptr, bool start_timer=true)
unsigned long long incrementUpdates(unsigned long long count=1)
Increment the total number of items updated between a start stop.
bool running() const
Returns true if the timer is currently accumulating time.
double accumulatedTimePerTimerCall() const
return the average time per timer start/stop
void merge(Teuchos::RCP< const Teuchos::Comm< int > > comm)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
double accumulatedTimePerUpdate() const
return the average time per item updated
Teuchos header file which uses auto-configuration information to include necessary C++ headers...
bool enable_verbose_
If set to true, prints to the debug ostream. At construction, default value is set from environment v...
void incrementUpdates(const long long i=1)
void start()
Start a currently stopped timer.
LevelTimer * top_
Current level running.
double accumulatedTimePerUpdate(const std::string &name="")
unsigned long numCalls() const
Returns the number of calls to start().
BaseTimer::TimeInfo findTimer(const std::string &name, bool &found)
double printLevel(std::string prefix, int level, std::ostream &os, std::vector< bool > &printed, double parent_time, const OutputOptions &options)
LevelTimer * unpack(unsigned from)
double accumulatedTime(const std::string &name="")
void start(const std::string name, const bool push_kokkos_profiling_region=true)
double accumulatedTime(const std::string &locate_name="")
void overrideNumCallsForUnitTesting(const unsigned long num_calls)
Sets the number of calls to start() for this timer. This is only used for unit testing.
the basic timer used elsewhere, uses MPI_Wtime for time
double computeColumnWidthsForAligment(std::string prefix, int print_level, std::vector< bool > &printed, double parent_time, const OutputOptions &options)
Stores the column widths for output alignment.
void collectRemoteData(Teuchos::RCP< const Teuchos::Comm< int > > comm, const OutputOptions &options)
LevelTimer(const LevelTimer &src)
Copy constructor.
Timer info at a given level and all the children.
const BaseTimer * findBaseTimer(const std::string &name) const
double accumulatedTimePerUpdate(const std::string &locate_name="")
Teuchos::RCP< std::ostream > verbose_ostream_
For debugging, this is the ostream used for printing.
LevelTimer timer_
Base timer.
double accumulatedTimePerTimerCall(const std::string &locate_name="")
Templated array class derived from the STL std::vector.
void error_out(const std::string &msg, const bool)
Error reporting function for stacked timer.
Abstract interface for distributed-memory communication.
LevelTimer * stop(const std::string &name="RootTimer")
void reset()
Reset all the timer stats, throws if it is already running.
void stop()
Stop a current running timer and accumulate time difference.
LevelTimer()
Default constructor, shouldn&#39;t be used but needed for std::vector.
const BaseTimer * findBaseTimer(const std::string &name) const
Smart reference counting pointer class for automatic garbage collection.
BaseTimer::TimeInfo findTimer(const std::string &name)
This class allows one to push and pop timers on and off a stack.
Common capabilities for collecting and reporting performance data collectively across MPI processes...
unsigned long long numUpdates() const
Returns the number of updates added to this timer.
Struct for controlling output options like histograms.
Reference-counted pointer class and non-member templated function implementations.
LevelTimer * start(const char *sub_name)