10 #ifndef TEUCHOS_STACKED_TIMER_HPP
11 #define TEUCHOS_STACKED_TIMER_HPP
14 #include "Teuchos_Comm.hpp"
15 #include "Teuchos_DefaultComm.hpp"
16 #include "Teuchos_CommHelpers.hpp"
29 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
32 extern void pushRegion (
const std::string&);
33 extern void popRegion ();
42 TEUCHOSCOMM_LIB_DLL_EXPORT
void error_out(
const std::string& msg,
const bool fail_all =
false);
57 using Clock = std::chrono::high_resolution_clock;
59 BaseTimer() : accumulation_(0.0), count_started_(0), count_updates_(0), running_(
false) {}
64 error_out(
"Base_Timer:start Failed timer already running");
65 start_time_ = Clock::now();
74 error_out(
"Base_Timer:stop Failed timer not running");
75 auto elapsed = std::chrono::duration_cast<std::chrono::duration<double>>(Clock::now() - start_time_).count();
76 accumulation_ += elapsed;
77 accumulationSquared_ += elapsed*elapsed;
82 unsigned long long incrementUpdates(
unsigned long long count=1) {count_updates_ += count;
return count_updates_;}
102 if (count_updates_ > 0) {
103 return accumulation_/count_updates_;
118 if (count_started_> 0) {
119 return accumulation_/count_started_;
133 if (count_started_ > 0) {
135 return sqrt(std::max<double>(accumulationSquared_ / count_started_ - mean*mean, 0.0));
148 return accumulation_ - from.accumulation_;
154 error_out(
"BaseTimer, cannot reset a running timer");
156 count_started_ = count_updates_ = 0;
163 unsigned long numCalls()
const {
return count_started_; }
166 unsigned long long numUpdates()
const {
return count_updates_; }
170 { count_started_ = num_calls; }
174 { count_updates_ = num_updates; }
177 TimeInfo():time(0.0), stdDev(0.0), count(0), updates(0),
running(false){}
178 TimeInfo(BaseTimer* t): time(t->accumulation_), stdDev(t->
timePerCallStdDev()), count(t->count_started_), updates(t->count_updates_),
running(t->
running()) {}
182 unsigned long long updates;
187 double accumulation_;
188 double accumulationSquared_;
189 unsigned long count_started_;
190 unsigned long long count_updates_;
191 Clock::time_point start_time_;
194 friend struct TimeInfo;
234 std::vector<LevelTimer> sub_timers_;
247 const char* name =
"RootTimer",
249 bool start_timer=
true) :
262 BaseTimer(src), level_(src.level_), name_(src.name_),parent_(src.parent_), sub_timers_(src.sub_timers_)
264 for (
unsigned i=0;i<sub_timers_.size();++i)
265 sub_timers_[i].parent_ =
this;
274 for (
unsigned i=0;i<sub_timers_.size();i++ )
275 if (sub_name == sub_timers_[i].name_ ) {
276 sub_timers_[i].BaseTimer::start();
277 return &sub_timers_[i];
279 sub_timers_.push_back(
LevelTimer(level_+1,sub_name,
this,
true));
280 return &sub_timers_[sub_timers_.size()-1];
292 error_out(
"Stopping timer "+name+
" But top level running timer is "+name_);
303 std::string parent_name(
"");
304 if ((parent_ !=
nullptr))
305 parent_name = parent_->get_full_name() +
"@";
307 std::string my_name(name_);
309 std::string full_name = parent_name + my_name;
320 for (
unsigned i=0;i<sub_timers_.size(); ++i)
321 count += sub_timers_[i].countTimers();
326 names[pos++] = get_full_name();
327 for (
unsigned i=0;i<sub_timers_.size(); ++i)
328 sub_timers_[i].addTimerNames(names, pos);
338 if (locate_name ==
"")
341 std::string first_name,second_name;
343 size_t i = locate_name.find_first_of(
'@');
344 if ( i >= locate_name.size() ) {
345 first_name = locate_name;
348 first_name.assign(locate_name,0,i);
349 second_name.assign(locate_name,i+1,locate_name.size()-i-1);
351 for (
unsigned j=0;j<sub_timers_.size();++j)
352 if ( first_name == sub_timers_[j].name_)
353 return sub_timers_[j].accumulatedTime(second_name);
368 void splitString(
const std::string &locate_name, std::string &first_name, std::string &second_name) {
369 size_t i = locate_name.find_first_of(
'@');
370 if ( i >= locate_name.size() ) {
371 first_name = locate_name;
374 first_name.assign(locate_name,0,i);
375 second_name.assign(locate_name,i+1,locate_name.size()-i-1);
387 if (locate_name ==
"")
390 std::string first_name,second_name;
391 splitString(locate_name, first_name, second_name);
393 for (
unsigned j=0;j<sub_timers_.size();j++)
394 if ( first_name == sub_timers_[j].name_)
395 return sub_timers_[j].accumulatedTimePerUpdate(second_name);
406 if (locate_name ==
"")
409 std::string first_name,second_name;
410 splitString(locate_name, first_name, second_name);
412 for (
unsigned j=0;j<sub_timers_.size();j++)
413 if ( first_name == sub_timers_[j].name_)
414 return sub_timers_[j].accumulatedTimePerTimerCall(second_name);
434 void report(std::ostream &os);
441 const BaseTimer* findBaseTimer(
const std::string &name)
const;
449 BaseTimer::TimeInfo findTimer(
const std::string &name,
bool& found);
460 explicit StackedTimer(
const char *name,
const bool start_base_timer =
true)
461 : timer_(0,name,nullptr,false),
462 global_mpi_aggregation_called_(false),
463 enable_verbose_(false),
464 verbose_timestamp_levels_(0),
465 verbose_ostream_(Teuchos::rcpFromRef(std::cout)),
469 if (start_base_timer)
470 this->startBaseTimer();
472 auto check_verbose = std::getenv(
"TEUCHOS_ENABLE_VERBOSE_TIMERS");
473 if (check_verbose !=
nullptr)
474 enable_verbose_ =
true;
476 auto check_timestamp = std::getenv(
"TEUCHOS_ENABLE_VERBOSE_TIMESTAMP_LEVELS");
477 if (check_timestamp !=
nullptr) {
478 verbose_timestamp_levels_ = std::atoi(check_timestamp);
486 timer_.BaseTimer::start();
487 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
488 ::Kokkos::Tools::pushRegion(timer_.get_full_name());
496 timer_.BaseTimer::stop();
497 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
498 ::Kokkos::Tools::popRegion();
508 const bool push_kokkos_profiling_region =
true) {
509 if (enable_timers_) {
511 top_ = timer_.start(name.c_str());
513 top_ = top_->start(name.c_str());
514 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
515 if (push_kokkos_profiling_region) {
516 ::Kokkos::Tools::pushRegion(name);
520 if (enable_verbose_) {
521 if (!verbose_timestamp_levels_) {
522 *verbose_ostream_ <<
"STARTING: " << name << std::endl;
526 #if !defined(__GNUC__) || ( defined(__GNUC__) && (__GNUC__ > 4) )
527 else if (top_ !=
nullptr) {
528 if ( top_->level() <= verbose_timestamp_levels_) {
529 auto now = std::chrono::system_clock::now();
530 auto now_time = std::chrono::system_clock::to_time_t(now);
531 auto gmt = gmtime(&now_time);
532 auto timestamp = std::put_time(gmt,
"%Y-%m-%d %H:%M:%S");
533 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
534 *verbose_ostream_ <<
"STARTING: " << name <<
" LEVEL: " << top_->level() <<
" COUNT: " << timer_.numCalls() <<
" TIMESTAMP: " << timestamp <<
"." << ms.count() << std::endl;
546 void stop(
const std::string &name,
547 const bool pop_kokkos_profiling_region =
true) {
548 if (enable_timers_) {
550 top_ = top_->stop(name);
552 timer_.BaseTimer::stop();
553 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
554 if (pop_kokkos_profiling_region) {
555 ::Kokkos::Tools::popRegion();
559 if (enable_verbose_) {
560 if (!verbose_timestamp_levels_) {
561 *verbose_ostream_ <<
"STOPPING: " << name << std::endl;
565 #if !defined(__GNUC__) || ( defined(__GNUC__) && (__GNUC__ > 4) )
567 else if (top_ !=
nullptr) {
568 if ( (top_->level()+1) <= verbose_timestamp_levels_) {
569 auto now = std::chrono::system_clock::now();
570 auto now_time = std::chrono::system_clock::to_time_t(now);
571 auto gmt = gmtime(&now_time);
572 auto timestamp = std::put_time(gmt,
"%Y-%m-%d %H:%M:%S");
573 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
574 *verbose_ostream_ <<
"STOPPING: " << name <<
" LEVEL: " << top_->level()+1 <<
" COUNT: " << timer_.numCalls() <<
" TIMESTAMP: " << timestamp <<
"." << ms.count() << std::endl;
586 top_->incrementUpdates(i);
596 return top_->accumulatedTime(name);
598 return timer_.accumulatedTime(name);
608 return top_->accumulatedTimePerUpdate(name);
610 return timer_.accumulatedTimePerUpdate(name);
619 return top_->accumulatedTimePerTimerCall(name);
621 return timer_.accumulatedTimePerTimerCall(name);
630 const BaseTimer* baseTimer = timer_.findBaseTimer(name);
632 "StackedTimer::findBaseTimer() failed to find a timer named \"" << name <<
"\"!\n");
641 BaseTimer::TimeInfo
findTimer(
const std::string &name) {
642 bool foundTimer =
false;
643 const auto timeInfo = timer_.findTimer(name,foundTimer);
645 "StackedTimer::findTimer() failed to find a timer named \"" << name <<
"\"!\n");
649 void report(std::ostream &os) {
668 OutputOptions() : output_fraction(
false), output_total_updates(
false), output_histogram(
false),
669 output_minmax(
false), output_proc_minmax(
false), num_histogram(10), max_levels(INT_MAX),
670 print_warnings(
true), align_columns(
false), print_names_before_values(
true),
671 drop_time(-1.0), output_per_proc_stddev(
false) {}
672 bool output_fraction;
673 bool output_total_updates;
674 bool output_histogram;
676 bool output_proc_minmax;
681 bool print_names_before_values;
683 bool output_per_proc_stddev;
739 void enableVerbose(
const bool enable_verbose);
742 void enableVerboseTimestamps(
const unsigned levels);
749 void disableTimers();
770 double getMpiAverageTime(
const std::string& flat_timer_name);
780 double getMpiAverageCount(
const std::string& flat_timer_name);
790 bool isTimer(
const std::string& flat_timer_name);
812 bool global_mpi_aggregation_called_;
816 std::string::size_type timer_names_;
817 std::string::size_type average_time_;
818 std::string::size_type fraction_;
819 std::string::size_type count_;
820 std::string::size_type total_updates_;
821 std::string::size_type min_;
822 std::string::size_type max_;
823 std::string::size_type procmin_;
824 std::string::size_type procmax_;
825 std::string::size_type stddev_;
826 std::string::size_type histogram_;
871 int getFlatNameIndex(
const std::string& flat_timer_name);
879 double computeColumnWidthsForAligment(std::string prefix,
int print_level,
880 std::vector<bool> &printed,
double parent_time,
886 double printLevel(std::string prefix,
int level, std::ostream &os, std::vector<bool> &printed,
893 double printLevelXML(std::string prefix,
int level, std::ostream &os, std::vector<bool> &printed,
double parent_time,
const std::string& rootName =
"");
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 '@' if no '@' 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
#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.
bool enable_timers_
Used to disable timers for asynchronous work.
double accumulatedTimePerUpdate(const std::string &name="")
unsigned verbose_timestamp_levels_
If set to a value greater than 0, verbose mode will print that many levels of timers with timestamps...
unsigned long numCalls() const
Returns the number of calls to start().
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.
void error_out(const std::string &msg, const bool)
Error reporting function for stacked timer.
The basic timer used internally, uses std::chrono::high_resolution_clock.
Stores the column widths for output alignment.
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.
double timePerCallStdDev() const
return the std dev in time per timer start/stop
void setAccumulatedTimeSquared(double accumSq=0)
Setter for squared accumulated time.
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.
unsigned level() const
Returns the level of the timer in the stack.
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.
unsigned long long numUpdates() const
Returns the number of updates added to this timer.
Reference-counted pointer class and non-member templated function implementations.
LevelTimer * start(const char *sub_name)
std::string get_full_name() const