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"
20 #include "Teuchos_Behavior.hpp"
21 #ifdef HAVE_TEUCHOSCORE_KOKKOS
22 #include "Kokkos_Core.hpp"
33 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
36 extern void pushRegion (
const std::string&);
37 extern void popRegion ();
46 TEUCHOSCOMM_LIB_DLL_EXPORT
void error_out(
const std::string& msg,
const bool fail_all =
false);
61 using Clock = std::chrono::high_resolution_clock;
63 BaseTimer() : accumulation_(0.0), accumulationSquared_(0.0), count_started_(0), count_updates_(0), running_(
false) {}
68 error_out(
"Base_Timer:start Failed timer already running");
69 start_time_ = Clock::now();
78 error_out(
"Base_Timer:stop Failed timer not running");
79 auto elapsed = std::chrono::duration_cast<std::chrono::duration<double>>(Clock::now() - start_time_).count();
80 accumulation_ += elapsed;
81 accumulationSquared_ += elapsed*elapsed;
86 unsigned long long incrementUpdates(
unsigned long long count=1) {count_updates_ += count;
return count_updates_;}
106 if (count_updates_ > 0) {
107 return accumulation_/count_updates_;
122 if (count_started_> 0) {
123 return accumulation_/count_started_;
137 if (count_started_ > 0) {
139 return sqrt(std::max<double>(accumulationSquared_ / count_started_ - mean*mean, 0.0));
152 return accumulation_ - from.accumulation_;
158 error_out(
"BaseTimer, cannot reset a running timer");
160 count_started_ = count_updates_ = 0;
167 unsigned long numCalls()
const {
return count_started_; }
170 unsigned long long numUpdates()
const {
return count_updates_; }
174 { count_started_ = num_calls; }
178 { count_updates_ = num_updates; }
181 TimeInfo():time(0.0), stdDev(0.0), count(0), updates(0),
running(false){}
182 TimeInfo(BaseTimer* t): time(t->accumulation_), stdDev(t->
timePerCallStdDev()), count(t->count_started_), updates(t->count_updates_),
running(t->
running()) {}
186 unsigned long long updates;
191 double accumulation_;
192 double accumulationSquared_;
193 unsigned long count_started_;
194 unsigned long long count_updates_;
195 Clock::time_point start_time_;
198 friend struct TimeInfo;
238 std::vector<LevelTimer> sub_timers_;
251 const char* name =
"RootTimer",
253 bool start_timer=
true) :
266 BaseTimer(src), level_(src.level_), name_(src.name_),parent_(src.parent_), sub_timers_(src.sub_timers_)
268 for (
unsigned i=0;i<sub_timers_.size();++i)
269 sub_timers_[i].parent_ =
this;
278 for (
unsigned i=0;i<sub_timers_.size();i++ )
279 if (sub_name == sub_timers_[i].name_ ) {
280 sub_timers_[i].BaseTimer::start();
281 return &sub_timers_[i];
283 sub_timers_.push_back(
LevelTimer(level_+1,sub_name,
this,
true));
284 return &sub_timers_[sub_timers_.size()-1];
296 error_out(
"Stopping timer "+name+
" But top level running timer is "+name_);
307 std::string parent_name(
"");
308 if ((parent_ !=
nullptr))
309 parent_name = parent_->get_full_name() +
"@";
311 std::string my_name(name_);
313 std::string full_name = parent_name + my_name;
324 for (
unsigned i=0;i<sub_timers_.size(); ++i)
325 count += sub_timers_[i].countTimers();
330 names[pos++] = get_full_name();
331 for (
unsigned i=0;i<sub_timers_.size(); ++i)
332 sub_timers_[i].addTimerNames(names, pos);
342 if (locate_name ==
"")
345 std::string first_name,second_name;
347 size_t i = locate_name.find_first_of(
'@');
348 if ( i >= locate_name.size() ) {
349 first_name = locate_name;
352 first_name.assign(locate_name,0,i);
353 second_name.assign(locate_name,i+1,locate_name.size()-i-1);
355 for (
unsigned j=0;j<sub_timers_.size();++j)
356 if ( first_name == sub_timers_[j].name_)
357 return sub_timers_[j].accumulatedTime(second_name);
372 void splitString(
const std::string &locate_name, std::string &first_name, std::string &second_name) {
373 size_t i = locate_name.find_first_of(
'@');
374 if ( i >= locate_name.size() ) {
375 first_name = locate_name;
378 first_name.assign(locate_name,0,i);
379 second_name.assign(locate_name,i+1,locate_name.size()-i-1);
391 if (locate_name ==
"")
394 std::string first_name,second_name;
395 splitString(locate_name, first_name, second_name);
397 for (
unsigned j=0;j<sub_timers_.size();j++)
398 if ( first_name == sub_timers_[j].name_)
399 return sub_timers_[j].accumulatedTimePerUpdate(second_name);
410 if (locate_name ==
"")
413 std::string first_name,second_name;
414 splitString(locate_name, first_name, second_name);
416 for (
unsigned j=0;j<sub_timers_.size();j++)
417 if ( first_name == sub_timers_[j].name_)
418 return sub_timers_[j].accumulatedTimePerTimerCall(second_name);
438 void report(std::ostream &os);
445 const BaseTimer* findBaseTimer(
const std::string &name)
const;
453 BaseTimer::TimeInfo findTimer(
const std::string &name,
bool& found);
464 explicit StackedTimer(
const char *name,
const bool start_base_timer =
true)
465 : timer_(0,name,nullptr,false),
466 global_mpi_aggregation_called_(false),
467 enable_verbose_(false),
468 verbose_timestamp_levels_(0),
469 verbose_ostream_(Teuchos::rcpFromRef(std::cout)),
473 if (start_base_timer)
474 this->startBaseTimer();
476 auto check_verbose = std::getenv(
"TEUCHOS_ENABLE_VERBOSE_TIMERS");
477 if (check_verbose !=
nullptr)
478 enable_verbose_ =
true;
480 auto check_timestamp = std::getenv(
"TEUCHOS_ENABLE_VERBOSE_TIMESTAMP_LEVELS");
481 if (check_timestamp !=
nullptr) {
482 verbose_timestamp_levels_ = std::atoi(check_timestamp);
487 return timer_.get_full_name();
494 timer_.BaseTimer::start();
501 timer_.BaseTimer::stop();
510 const bool push_kokkos_profiling_region =
true) {
511 if (enable_timers_) {
512 if (top_ ==
nullptr) {
513 top_ = timer_.start(name.c_str());
515 top_ = top_->start(name.c_str());
516 #ifdef HAVE_TEUCHOSCORE_KOKKOS
517 if (Behavior::fenceTimers()) {
518 Kokkos::fence(
"timer_fence_begin_"+name);
521 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
522 if (push_kokkos_profiling_region) {
523 ::Kokkos::Tools::pushRegion(name);
528 if (enable_verbose_) {
529 if (!verbose_timestamp_levels_) {
530 *verbose_ostream_ <<
"STARTING: " << name << std::endl;
534 #if !defined(__GNUC__) || ( defined(__GNUC__) && (__GNUC__ > 4) )
535 else if (top_ !=
nullptr) {
536 if ( top_->level() <= verbose_timestamp_levels_) {
537 auto now = std::chrono::system_clock::now();
538 auto now_time = std::chrono::system_clock::to_time_t(now);
539 auto gmt = gmtime(&now_time);
540 auto timestamp = std::put_time(gmt,
"%Y-%m-%d %H:%M:%S");
541 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
542 *verbose_ostream_ <<
"STARTING: " << name <<
" LEVEL: " << top_->level() <<
" COUNT: " << timer_.numCalls() <<
" TIMESTAMP: " << timestamp <<
"." << ms.count() << std::endl;
554 void stop(
const std::string &name,
555 const bool pop_kokkos_profiling_region =
true) {
556 if (enable_timers_) {
558 top_ = top_->stop(name);
559 #ifdef HAVE_TEUCHOSCORE_KOKKOS
560 if (Behavior::fenceTimers()) {
561 Kokkos::fence(
"timer_fence_end_"+name);
564 #if defined(HAVE_TEUCHOS_KOKKOS_PROFILING) && defined(HAVE_TEUCHOSCORE_KOKKOS)
565 if (pop_kokkos_profiling_region) {
566 ::Kokkos::Tools::popRegion();
570 timer_.BaseTimer::stop();
573 if (enable_verbose_) {
574 if (!verbose_timestamp_levels_) {
575 *verbose_ostream_ <<
"STOPPING: " << name << std::endl;
579 #if !defined(__GNUC__) || ( defined(__GNUC__) && (__GNUC__ > 4) )
581 else if (top_ !=
nullptr) {
582 if ( (top_->level()+1) <= verbose_timestamp_levels_) {
583 auto now = std::chrono::system_clock::now();
584 auto now_time = std::chrono::system_clock::to_time_t(now);
585 auto gmt = gmtime(&now_time);
586 auto timestamp = std::put_time(gmt,
"%Y-%m-%d %H:%M:%S");
587 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
588 *verbose_ostream_ <<
"STOPPING: " << name <<
" LEVEL: " << top_->level()+1 <<
" COUNT: " << timer_.numCalls() <<
" TIMESTAMP: " << timestamp <<
"." << ms.count() << std::endl;
600 top_->incrementUpdates(i);
610 return top_->accumulatedTime(name);
612 return timer_.accumulatedTime(name);
622 return top_->accumulatedTimePerUpdate(name);
624 return timer_.accumulatedTimePerUpdate(name);
633 return top_->accumulatedTimePerTimerCall(name);
635 return timer_.accumulatedTimePerTimerCall(name);
644 const BaseTimer* baseTimer = timer_.findBaseTimer(name);
646 "StackedTimer::findBaseTimer() failed to find a timer named \"" << name <<
"\"!\n");
655 BaseTimer::TimeInfo
findTimer(
const std::string &name) {
656 bool foundTimer =
false;
657 const auto timeInfo = timer_.findTimer(name,foundTimer);
659 "StackedTimer::findTimer() failed to find a timer named \"" << name <<
"\"!\n");
663 void report(std::ostream &os) {
682 OutputOptions() : output_fraction(
false), output_total_updates(
false), output_histogram(
false),
683 output_minmax(
false), output_proc_minmax(
false), num_histogram(10), max_levels(INT_MAX),
684 print_warnings(
true), align_columns(
false), print_names_before_values(
true),
685 drop_time(-1.0), output_per_proc_stddev(
false) {}
686 bool output_fraction;
687 bool output_total_updates;
688 bool output_histogram;
690 bool output_proc_minmax;
695 bool print_names_before_values;
697 bool output_per_proc_stddev;
753 void enableVerbose(
const bool enable_verbose);
756 void enableVerboseTimestamps(
const unsigned levels);
763 void disableTimers();
784 double getMpiAverageTime(
const std::string& flat_timer_name);
794 double getMpiAverageCount(
const std::string& flat_timer_name);
804 bool isTimer(
const std::string& flat_timer_name);
826 bool global_mpi_aggregation_called_;
830 std::string::size_type timer_names_;
831 std::string::size_type average_time_;
832 std::string::size_type fraction_;
833 std::string::size_type count_;
834 std::string::size_type total_updates_;
835 std::string::size_type min_;
836 std::string::size_type max_;
837 std::string::size_type procmin_;
838 std::string::size_type procmax_;
839 std::string::size_type stddev_;
840 std::string::size_type histogram_;
885 int getFlatNameIndex(
const std::string& flat_timer_name);
893 double computeColumnWidthsForAligment(std::string prefix,
int print_level,
894 std::vector<bool> &printed,
double parent_time,
900 double printLevel(std::string prefix,
int level, std::ostream &os, std::vector<bool> &printed,
907 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