StopWatch.h
Go to the documentation of this file.
1 /**
2  * @file StopWatch.h
3  * @brief Class to take current wall clock time differences
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date July 3, 2016
6  *
7  * This is a pure header library.
8  *
9  * It provides its namesake class, `testing::StopWatch`.
10  */
11 
12 #ifndef LARCORE_TESTUTILS_STOPWATCH_H
13 #define LARCORE_TESTUTILS_STOPWATCH_H
14 
15 // C/C++ standard libraries
16 #include <cstdint> // std::intmax_t
17 #include <chrono>
18 #include <ratio>
19 #include <type_traits> // std::true_type, std::false_type
20 
21 
22 namespace testing {
23  namespace details {
24  /// Type trait containing whether Duration is std::chrono::duration
25  template <typename Duration>
26  struct isDuration;
27  } // namespace details
28 
29 
30  /**
31  * @brief Provides time interval measurements
32  * @tparam DefaultUnit unit reported by default (seconds, floating point)
33  * @tparam Clock type of clock object used (default: high_resolution_clock)
34  *
35  * The stopwatch keeps track of the clock and can return the time elapsed from
36  * a previous time mark.
37  * Example of use:
38  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
39  *
40  * // do initialisation of task A
41  *
42  * testing::StopWatch<> timer; // starts automatically
43  *
44  * // execute task A
45  *
46  * timer.stop();
47  *
48  * // do initialisation of task B
49  *
50  * timer.resume()
51  *
52  * // execute task B
53  *
54  * timer.stop()
55  *
56  * std::cout << "Tasks A and B took " << timer.elapsed() << " seconds"
57  * << std::endl;
58  *
59  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60  *
61  * The time from all methods returning a value are in the DefaultUnit_t unit.
62  *
63  * Requirements
64  * -------------
65  *
66  * On `DefaultUnit` type:
67  *
68  * * must be a std::chrono::duration specialisation
69  *
70  * On `Clock` type:
71  *
72  * * must have a `now()` static function returning `std::chrono::time_point`
73  *
74  */
75  template <
76  typename DefaultUnit = std::chrono::duration<double>, // seconds (ratio<1>)
77  typename Clock = std::chrono::high_resolution_clock
78  >
79  class StopWatch {
81  "DefaultUnit type is not a std::chrono::duration specialization");
82 
83  public:
84  using Clock_t = Clock; ///< type of clock used to extract current time
85  using DefaultUnit_t = DefaultUnit; ///< default unit for time report
86 
87  /// Type representing the reported time
88  using ElapsedTime_t = typename DefaultUnit_t::rep;
89 
90  /**
91  * @brief Initializes and starts the timer
92  * @param start whether to start immediately (default: true)
93  */
94  StopWatch(bool start = true);
95 
96  /**
97  * @brief Initializes and starts the timer
98  * @param prev time already accumulated on start
99  * @param start whether to start immediately (default: true)
100  */
101  template <typename Unit>
102  StopWatch(Unit prev, bool start = true);
103 
104 
105  /// @{
106  /// @name Watch control
107 
108  /// Restarts the watch; previous time is forgotten
109  void restart();
110 
111  /// Resumes the run of the watch; previous time is preserved
112  void resume();
113 
114  /// Pauses the watch
115  void stop();
116 
117  /// Changes the amount of time accumulated before this run
118  template <typename Unit = DefaultUnit_t>
119  void setPrevious(Unit dur);
120 
121  /// @}
122 
123  /// @{
124  /// @name Query
125 
126  /// Returns the total time spent running since the last restart
127  template <typename Unit = DefaultUnit_t>
128  ElapsedTime_t elapsed() const;
129 
130  /// Returns the time spent running since the last resume
131  template <typename Unit = DefaultUnit_t>
132  ElapsedTime_t partial() const;
133 
134  /// Returns the time accumulated before the current run
135  template <typename Unit = DefaultUnit_t>
136  ElapsedTime_t previous() const;
137 
138  /// Returns whether the watch is tracking time right now
139  bool running() const;
140 
141  /// @}
142 
143 
144  protected:
145  using TimePoint_t = decltype(Clock_t::now()); ///< type to store start time
146 
147  TimePoint_t lastStart; ///< time of the last start
148  DefaultUnit_t previousTime; ///< time accumulated from previous runs
149  bool isRunning; ///< whether we are measuring time now
150 
151  /// Returns the current time point from our clock
152  static TimePoint_t now();
153 
154  /// Returns partial time as a duration
155  DefaultUnit_t partialDur() const;
156 
157 
158  /// Trait whose type member is a std::chrono::duration type
159  template <typename>
160  struct makeDurationTrait;
161 
162  /// Type of std::chrono::duration type constructed from makeDurationTrait
163  template <typename Unit>
165 
166  /// Convert a duration into a unit (may be a ratio or a duration)
167  template <typename Unit, typename From>
168  static auto durationTo(From const& dur);
169 
170  }; // class StopWatch
171 
172 
173  /// A StopWatch with default template arguments
174  using StandardStopWatch = StopWatch<>;
175 
176 } // namespace testing
177 
178 
179 //------------------------------------------------------------------------------
180 namespace testing {
181  namespace details {
182  template <typename Duration>
183  struct isDuration: public std::false_type {};
184 
185  template <typename Rep, typename Period>
186  struct isDuration<std::chrono::duration<Rep, Period>>
187  : public std::true_type
188  {};
189 
190  } // namespace details
191 } // namespace testing
192 
193 
194 //------------------------------------------------------------------------------
195 //--- StopWatch implementartion
196 //---
197 //------------------------------------------------------------------------------
198 template <typename DefaultUnit, typename Clock>
200  : lastStart{start? now(): TimePoint_t{}}
201  , previousTime{}
202  , isRunning{start}
203 {}
204 
205 
206 template <typename DefaultUnit, typename Clock>
207 template <typename Unit>
209  (Unit prev, bool start /* = true */)
210  : StopWatch(start)
211 {
212  previousTime = prev;
213 }
214 
215 
216 //------------------------------------------------------------------------------
217 template <typename DefaultUnit, typename Clock>
219  lastStart = now();
220  isRunning = true;
221  previousTime = DefaultUnit_t();
222 } // testing::StopWatch<>::restart()
223 
224 
225 //------------------------------------------------------------------------------
226 template <typename DefaultUnit, typename Clock>
228  if (running()) return;
229  lastStart = now();
230  isRunning = true;
231 } // testing::StopWatch<>::resume()
232 
233 
234 //------------------------------------------------------------------------------
235 template <typename DefaultUnit, typename Clock>
237  previousTime += partialDur();
238  isRunning = false;
239 } // testing::StopWatch<>::stop()
240 
241 
242 //------------------------------------------------------------------------------
243 template <typename DefaultUnit, typename Clock>
244 template <typename Unit>
246  previousTime = std::chrono::duration_cast<DefaultUnit_t>(dur);
247 } // testing::StopWatch<>::setPrevious()
248 
249 
250 //------------------------------------------------------------------------------
251 template <typename DefaultUnit, typename Clock>
252 template <typename Unit>
255  auto const prev = previous<Unit>();
256  return running()? (prev + partial<Unit>()): prev;
257 } // testing::StopWatch<>::elapsed()
258 
259 
260 //------------------------------------------------------------------------------
261 template <typename DefaultUnit, typename Clock>
262 template <typename Unit>
265  return running()? durationTo<Unit>(partialDur()).count(): ElapsedTime_t(0);
266 } // testing::StopWatch<>::partial()
267 
268 
269 //------------------------------------------------------------------------------
270 template <typename DefaultUnit, typename Clock>
271 template <typename Unit>
274  return durationTo<Unit>(previousTime).count();
275 } // testing::StopWatch<>::previous()
276 
277 
278 //------------------------------------------------------------------------------
279 template <typename DefaultUnit, typename Clock>
281  { return isRunning; }
282 
283 
284 //------------------------------------------------------------------------------
285 template <typename DefaultUnit, typename Clock>
288  { return Clock_t::now(); }
289 
290 
291 //------------------------------------------------------------------------------
292 template <typename DefaultUnit, typename Clock>
295  return std::chrono::duration_cast<DefaultUnit_t>(now() - lastStart);
296 } // testing::StopWatch<>::setPrevious()
297 
298 
299 //------------------------------------------------------------------------------
300 // Specialisation: on std::chrono::duration (type is that very same)
301 namespace testing {
302  template <typename DefaultUnit, typename Clock>
303  template <typename Rep, typename Duration>
304  struct StopWatch<DefaultUnit, Clock>::makeDurationTrait
305  <std::chrono::duration<Rep, Duration>>
306  {
307  using type = std::chrono::duration<Rep, Duration>;
308  }; // StopWatch<>::makeDurationTrait<duration>
309 
310  // Specialisation: on std::ratio (type is a duration based on that ratio)
311  template <typename DefaultUnit, typename Clock>
312  template <std::intmax_t Num, std::intmax_t Den>
313  struct StopWatch<DefaultUnit, Clock>::makeDurationTrait<std::ratio<Num, Den>>
314  {
315  using type = std::chrono::duration<
317  std::ratio<Num, Den>
318  >;
319  }; // struct makeDurationTrait<duration>
320 
321 } // namespace testing
322 
323 //------------------------------------------------------------------------------
324 template <typename DefaultUnit, typename Clock>
325 template <typename Unit, typename From>
327  { return std::chrono::duration_cast<makeDuration_t<Unit>>(dur); }
328 
329 
330 //------------------------------------------------------------------------------
331 
332 
333 #endif // LARCORE_TESTUTILS_STOPWATCH_H
bool running() const
Returns whether the watch is tracking time right now.
Definition: StopWatch.h:280
DefaultUnit DefaultUnit_t
default unit for time report
Definition: StopWatch.h:85
decltype(Clock_t::now()) TimePoint_t
type to store start time
Definition: StopWatch.h:145
LArSoft test utilities.
StopWatch(bool start=true)
Initializes and starts the timer.
Definition: StopWatch.h:199
static auto durationTo(From const &dur)
Convert a duration into a unit (may be a ratio or a duration)
Definition: StopWatch.h:326
StopWatch<> StandardStopWatch
A StopWatch with default template arguments.
Definition: StopWatch.h:174
DefaultUnit_t partialDur() const
Returns partial time as a duration.
Definition: StopWatch.h:294
typename DefaultUnit_t::rep ElapsedTime_t
Type representing the reported time.
Definition: StopWatch.h:88
void stop()
Pauses the watch.
Definition: StopWatch.h:236
ElapsedTime_t elapsed() const
Returns the total time spent running since the last restart.
Definition: StopWatch.h:254
ElapsedTime_t partial() const
Returns the time spent running since the last resume.
Definition: StopWatch.h:264
void restart()
Restarts the watch; previous time is forgotten.
Definition: StopWatch.h:218
void setPrevious(Unit dur)
Changes the amount of time accumulated before this run.
Definition: StopWatch.h:245
static Entry * previous
Definition: pyscanner.cpp:1444
Clock Clock_t
type of clock used to extract current time
Definition: StopWatch.h:84
Provides time interval measurements.
Definition: StopWatch.h:79
ElapsedTime_t previous() const
Returns the time accumulated before the current run.
Definition: StopWatch.h:273
void resume()
Resumes the run of the watch; previous time is preserved.
Definition: StopWatch.h:227
Trait whose type member is a std::chrono::duration type.
Definition: StopWatch.h:160
typename makeDurationTrait< Unit >::type makeDuration_t
Type of std::chrono::duration type constructed from makeDurationTrait.
Definition: StopWatch.h:164
static TimePoint_t now()
Returns the current time point from our clock.
Definition: StopWatch.h:287