tlx
multi_timer.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * tlx/multi_timer.cpp
3  *
4  * Part of tlx - http://panthema.net/tlx
5  *
6  * Copyright (C) 2018-2019 Timo Bingmann <tb@panthema.net>
7  *
8  * All rights reserved. Published under the Boost Software License, Version 1.0
9  ******************************************************************************/
10 
11 #include <tlx/multi_timer.hpp>
12 
13 #include <iostream>
14 #include <mutex>
15 
16 #include <tlx/die/core.hpp>
17 #include <tlx/logger/core.hpp>
18 #include <tlx/string/hash_djb2.hpp>
19 
20 namespace tlx {
21 
22 static std::mutex s_timer_add_mutex;
23 
24 /******************************************************************************/
25 // MultiTimer::Entry
26 
28  //! hash of name for faster search
29  uint32_t hash;
30  //! reference to original string for comparison
31  const char* name;
32  //! duration of this timer
33  std::chrono::duration<double> duration;
34 };
35 
36 /******************************************************************************/
37 // MultiTimer
38 
40  : total_duration_(std::chrono::duration<double>::zero()),
41  running_(nullptr),
42  running_hash_(0)
43 { }
44 
45 MultiTimer::MultiTimer(const MultiTimer&) = default;
49 
50 MultiTimer::~MultiTimer() = default;
51 
53  uint32_t hash = hash_djb2(name);
54  for (size_t i = 0; i < timers_.size(); ++i) {
55  if (timers_[i].hash == hash && strcmp(timers_[i].name, name) == 0)
56  return timers_[i];
57  }
58  Entry new_entry;
59  new_entry.hash = hash;
60  new_entry.name = name;
61  new_entry.duration = std::chrono::duration<double>::zero();
62  timers_.emplace_back(new_entry);
63  return timers_.back();
64 }
65 
66 void MultiTimer::start(const char* timer) {
67  tlx_die_unless(timer);
68  uint32_t hash = hash_djb2(timer);
69  if (running_ && hash == running_hash_ && strcmp(running_, timer) == 0) {
70  static bool warning_shown = false;
71  if (!warning_shown) {
72  TLX_LOG1 << "MultiTimer: trying to start timer "
73  << timer << " twice!";
74  TLX_LOG1 << "MultiTimer: multi-threading is not supported, "
75  << "use .add()";
76  warning_shown = true;
77  }
78  }
79  stop();
80  running_ = timer;
81  running_hash_ = hash;
82 }
83 
85  auto new_time_point = std::chrono::high_resolution_clock::now();
86  if (running_) {
88  e.duration += new_time_point - time_point_;
89  total_duration_ += new_time_point - time_point_;
90  }
91  time_point_ = new_time_point;
92  running_ = nullptr;
93  running_hash_ = 0;
94 }
95 
97  timers_.clear();
98  total_duration_ = std::chrono::duration<double>::zero();
99 }
100 
101 const char* MultiTimer::running() const {
102  return running_;
103 }
104 
105 double MultiTimer::get(const char* name) {
106  return find_or_create(name).duration.count();
107 }
108 
109 double MultiTimer::total() const {
110  return total_duration_.count();
111 }
112 
113 void MultiTimer::print(const char* info, std::ostream& os) const {
115 
116  os << "TIMER info=" << info;
117  for (const Entry& timer : timers_) {
118  os << ' ' << timer.name << '=' << timer.duration.count();
119  }
120  os << " total=" << total_duration_.count() << std::endl;
121 }
122 
123 void MultiTimer::print(const char* info) const {
124  return print(info, std::cerr);
125 }
126 
128  std::unique_lock<std::mutex> lock(s_timer_add_mutex);
129  if (b.running_) {
130  TLX_LOG1 << "MultiTimer: trying to add running timer";
131  }
132  for (const Entry& t : b.timers_) {
133  Entry& e = find_or_create(t.name);
134  e.duration += t.duration;
135  }
137  return *this;
138 }
139 
141  return add(b);
142 }
143 
144 /******************************************************************************/
145 // ScopedMultiTimerSwitch
146 
148  MultiTimer& timer, const char* new_timer)
149  : timer_(timer), previous_(timer.running()) {
150  timer_.start(new_timer);
151 }
152 
155 }
156 
157 /******************************************************************************/
158 // ScopedMultiTimer
159 
161  : base_(base) {
162  timer_.start(timer);
163 }
164 
166  timer_.stop();
167  base_.add(timer_);
168 }
169 
170 } // namespace tlx
171 
172 /******************************************************************************/
~ScopedMultiTimerSwitch()
change back timer to previous timer.
~ScopedMultiTimer()
change back timer to previous timer.
MultiTimer & base_
reference to base timer
MultiTimer()
constructor
Definition: multi_timer.cpp:39
const char * name
reference to original string for comparison
Definition: multi_timer.cpp:31
~MultiTimer()
destructor
STL namespace.
static std::mutex s_timer_add_mutex
Definition: multi_timer.cpp:22
MultiTimer & operator=(const MultiTimer &)
default assignment operator
static uint32_t hash_djb2(const unsigned char *str)
Simple, fast, but "insecure" string hash method by Dan Bernstein from http://www.cse.yorku.ca/~oz/hash.html.
Definition: hash_djb2.hpp:26
ScopedMultiTimerSwitch(MultiTimer &timer, const char *new_timer)
construct and timer to switch to
MultiTimer can be used to measure time usage of different phases in a program or algorithm.
Definition: multi_timer.hpp:36
uint32_t hash
hash of name for faster search
Definition: multi_timer.cpp:29
MultiTimer & add(const MultiTimer &b)
add all timers from another, internally holds a global mutex lock, because this is used to add thread...
const char * running() const
return name of currently running timer.
std::vector< Entry > timers_
array of timers
Definition: multi_timer.hpp:86
void reset()
zero timers.
Definition: multi_timer.cpp:96
const char * running_
currently running timer name
Definition: multi_timer.hpp:95
void stop()
stop the currently running timer.
Definition: multi_timer.cpp:84
MultiTimer & timer_
reference to MultiTimer
MultiTimer & operator+=(const MultiTimer &b)
add all timers from another, internally holds a global mutex lock, because this is used to add thread...
void start(const char *timer)
start new timer phase, stop the currently running one.
Definition: multi_timer.cpp:66
void print(const char *info, std::ostream &os) const
print all timers as a TIMER line to os
ScopedMultiTimer(MultiTimer &base, const char *timer)
construct and change timer to tm
double get(const char *timer)
return timer duration in seconds of timer.
const char * previous_
previous timer, used to switch back to on destruction
Entry & find_or_create(const char *name)
internal methods to find or create new timer entries
Definition: multi_timer.cpp:52
std::chrono::duration< double > duration
duration of this timer
Definition: multi_timer.cpp:33
#define TLX_LOG1
Definition: core.hpp:145
std::chrono::duration< double > total_duration_
total duration
Definition: multi_timer.hpp:92
std::chrono::time_point< std::chrono::high_resolution_clock > time_point_
start of currently running timer name
Definition: multi_timer.hpp:99
double total() const
return total duration of all timers.
uint32_t running_hash_
hash of running_
Definition: multi_timer.hpp:97
#define tlx_die_unless(X)
Check condition X and die miserably if false.
Definition: core.hpp:65
MultiTimer timer_
contained independent timer