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 accumulation_ += std::chrono::duration_cast<std::chrono::duration<double>>(Clock::now() - start_time_).count();
80 unsigned long long incrementUpdates(
unsigned long long count=1) {count_updates_ += count;
return count_updates_;}
97 if (count_updates_ > 0) {
98 return accumulation_/count_updates_;
113 if (count_started_> 0) {
114 return accumulation_/count_started_;
127 return accumulation_ - from.accumulation_;
133 error_out(
"BaseTimer, cannot reset a running timer");
135 count_started_ = count_updates_ = 0;
142 unsigned long numCalls()
const {
return count_started_; }
145 unsigned long long numUpdates()
const {
return count_updates_; }
149 { count_started_ = num_calls; }
153 { count_updates_ = num_updates; }
156 TimeInfo():time(0.0), count(0), updates(0),
running(false){}
157 TimeInfo(BaseTimer* t): time(t->accumulation_), count(t->count_started_), updates(t->count_updates_),
running(t->
running()) {}
160 unsigned long long updates;
165 double accumulation_;
166 unsigned long count_started_;
167 unsigned long long count_updates_;
168 Clock::time_point start_time_;
171 friend struct TimeInfo;
211 std::vector<LevelTimer> sub_timers_;
224 const char* name =
"RootTimer",
226 bool start_timer=
true) :
239 BaseTimer(src), level_(src.level_), name_(src.name_),parent_(src.parent_), sub_timers_(src.sub_timers_)
241 for (
unsigned i=0;i<sub_timers_.size();++i)
242 sub_timers_[i].parent_ =
this;
251 for (
unsigned i=0;i<sub_timers_.size();i++ )
252 if (sub_name == sub_timers_[i].name_ ) {
253 sub_timers_[i].BaseTimer::start();
254 return &sub_timers_[i];
256 sub_timers_.push_back(
LevelTimer(level_+1,sub_name,
this,
true));
257 return &sub_timers_[sub_timers_.size()-1];
269 error_out(
"Stopping timer "+name+
" But top level running timer is "+name_);
280 std::string parent_name(
"");
281 if ((parent_ !=
nullptr))
282 parent_name = parent_->get_full_name() +
"@";
284 std::string my_name(name_);
286 std::string full_name = parent_name + my_name;
297 for (
unsigned i=0;i<sub_timers_.size(); ++i)
298 count += sub_timers_[i].countTimers();
303 names[pos++] = get_full_name();
304 for (
unsigned i=0;i<sub_timers_.size(); ++i)
305 sub_timers_[i].addTimerNames(names, pos);
315 if (locate_name ==
"")
318 std::string first_name,second_name;
320 size_t i = locate_name.find_first_of(
'@');
321 if ( i >= locate_name.size() ) {
322 first_name = locate_name;
325 first_name.assign(locate_name,0,i);
326 second_name.assign(locate_name,i+1,locate_name.size()-i-1);
328 for (
unsigned j=0;j<sub_timers_.size();++j)
329 if ( first_name == sub_timers_[j].name_)
330 return sub_timers_[j].accumulatedTime(second_name);
345 void splitString(
const std::string &locate_name, std::string &first_name, std::string &second_name) {
346 size_t i = locate_name.find_first_of(
'@');
347 if ( i >= locate_name.size() ) {
348 first_name = locate_name;
351 first_name.assign(locate_name,0,i);
352 second_name.assign(locate_name,i+1,locate_name.size()-i-1);
364 if (locate_name ==
"")
367 std::string first_name,second_name;
368 splitString(locate_name, first_name, second_name);
370 for (
unsigned j=0;j<sub_timers_.size();j++)
371 if ( first_name == sub_timers_[j].name_)
372 return sub_timers_[j].accumulatedTimePerUpdate(second_name);
383 if (locate_name ==
"")
386 std::string first_name,second_name;
387 splitString(locate_name, first_name, second_name);
389 for (
unsigned j=0;j<sub_timers_.size();j++)
390 if ( first_name == sub_timers_[j].name_)
391 return sub_timers_[j].accumulatedTimePerTimerCall(second_name);
411 void report(std::ostream &os);
418 const BaseTimer* findBaseTimer(
const std::string &name)
const;
426 BaseTimer::TimeInfo findTimer(
const std::string &name,
bool& found);
437 explicit StackedTimer(
const char *name,
const bool start_base_timer =
true)
438 : timer_(0,name,nullptr,false),
439 global_mpi_aggregation_called_(false),
440 enable_verbose_(false),
441 verbose_timestamp_levels_(0),
442 verbose_ostream_(Teuchos::rcpFromRef(std::cout)),
446 if (start_base_timer)
447 this->startBaseTimer();
449 auto check_verbose = std::getenv(
"TEUCHOS_ENABLE_VERBOSE_TIMERS");
450 if (check_verbose !=
nullptr)
451 enable_verbose_ =
true;
453 auto check_timestamp = std::getenv(
"TEUCHOS_ENABLE_VERBOSE_TIMESTAMP_LEVELS");
454 if (check_timestamp !=
nullptr) {
455 verbose_timestamp_levels_ = std::atoi(check_timestamp);
463 timer_.BaseTimer::start();
464 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
465 ::Kokkos::Tools::pushRegion(timer_.get_full_name());
473 timer_.BaseTimer::stop();
474 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
475 ::Kokkos::Tools::popRegion();
485 const bool push_kokkos_profiling_region =
true) {
486 if (enable_timers_) {
488 top_ = timer_.start(name.c_str());
490 top_ = top_->start(name.c_str());
491 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
492 if (push_kokkos_profiling_region) {
493 ::Kokkos::Tools::pushRegion(name);
497 if (enable_verbose_) {
498 if (!verbose_timestamp_levels_) {
499 *verbose_ostream_ <<
"STARTING: " << name << std::endl;
503 #if !defined(__GNUC__) || ( defined(__GNUC__) && (__GNUC__ > 4) )
504 else if (top_ !=
nullptr) {
505 if ( top_->level() <= verbose_timestamp_levels_) {
506 auto now = std::chrono::system_clock::now();
507 auto now_time = std::chrono::system_clock::to_time_t(now);
508 auto gmt = gmtime(&now_time);
509 auto timestamp = std::put_time(gmt,
"%Y-%m-%d %H:%M:%S");
510 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
511 *verbose_ostream_ <<
"STARTING: " << name <<
" LEVEL: " << top_->level() <<
" COUNT: " << timer_.numCalls() <<
" TIMESTAMP: " << timestamp <<
"." << ms.count() << std::endl;
523 void stop(
const std::string &name,
524 const bool pop_kokkos_profiling_region =
true) {
525 if (enable_timers_) {
527 top_ = top_->stop(name);
529 timer_.BaseTimer::stop();
530 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
531 if (pop_kokkos_profiling_region) {
532 ::Kokkos::Tools::popRegion();
536 if (enable_verbose_) {
537 if (!verbose_timestamp_levels_) {
538 *verbose_ostream_ <<
"STOPPING: " << name << std::endl;
542 #if !defined(__GNUC__) || ( defined(__GNUC__) && (__GNUC__ > 4) )
544 else if (top_ !=
nullptr) {
545 if ( (top_->level()+1) <= verbose_timestamp_levels_) {
546 auto now = std::chrono::system_clock::now();
547 auto now_time = std::chrono::system_clock::to_time_t(now);
548 auto gmt = gmtime(&now_time);
549 auto timestamp = std::put_time(gmt,
"%Y-%m-%d %H:%M:%S");
550 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
551 *verbose_ostream_ <<
"STOPPING: " << name <<
" LEVEL: " << top_->level()+1 <<
" COUNT: " << timer_.numCalls() <<
" TIMESTAMP: " << timestamp <<
"." << ms.count() << std::endl;
563 top_->incrementUpdates(i);
573 return top_->accumulatedTime(name);
575 return timer_.accumulatedTime(name);
585 return top_->accumulatedTimePerUpdate(name);
587 return timer_.accumulatedTimePerUpdate(name);
596 return top_->accumulatedTimePerTimerCall(name);
598 return timer_.accumulatedTimePerTimerCall(name);
607 const BaseTimer* baseTimer = timer_.findBaseTimer(name);
609 "StackedTimer::findBaseTimer() failed to find a timer named \"" << name <<
"\"!\n");
618 BaseTimer::TimeInfo
findTimer(
const std::string &name) {
619 bool foundTimer =
false;
620 const auto timeInfo = timer_.findTimer(name,foundTimer);
622 "StackedTimer::findTimer() failed to find a timer named \"" << name <<
"\"!\n");
626 void report(std::ostream &os) {
644 OutputOptions() : output_fraction(
false), output_total_updates(
false), output_histogram(
false),
645 output_minmax(
false), output_proc_minmax(
false), num_histogram(10), max_levels(INT_MAX),
646 print_warnings(
true), align_columns(
false), print_names_before_values(
true),
648 bool output_fraction;
649 bool output_total_updates;
650 bool output_histogram;
652 bool output_proc_minmax;
657 bool print_names_before_values;
714 void enableVerbose(
const bool enable_verbose);
717 void enableVerboseTimestamps(
const unsigned levels);
724 void disableTimers();
745 double getMpiAverageTime(
const std::string& flat_timer_name);
755 double getMpiAverageCount(
const std::string& flat_timer_name);
765 bool isTimer(
const std::string& flat_timer_name);
785 bool global_mpi_aggregation_called_;
789 std::string::size_type timer_names_;
790 std::string::size_type average_time_;
791 std::string::size_type fraction_;
792 std::string::size_type count_;
793 std::string::size_type total_updates_;
794 std::string::size_type min_;
795 std::string::size_type max_;
796 std::string::size_type procmin_;
797 std::string::size_type procmax_;
798 std::string::size_type stddev_;
799 std::string::size_type histogram_;
844 int getFlatNameIndex(
const std::string& flat_timer_name);
852 double computeColumnWidthsForAligment(std::string prefix,
int print_level,
853 std::vector<bool> &printed,
double parent_time,
859 double printLevel(std::string prefix,
int level, std::ostream &os, std::vector<bool> &printed,
866 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.
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