Turi Create  4.0
timer.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_TIMER_HPP
7 #define TURI_TIMER_HPP
8 
9 #ifndef _MSC_VER
10 #include <sys/time.h>
11 #endif
12 
13 #include <stdio.h>
14 
15 #include <iostream>
16 
17 namespace turi {
18  /**
19  * \ingroup util
20  *
21  * \brief A simple class that can be used for benchmarking/timing up
22  * to microsecond resolution.
23  *
24  * Standard Usage
25  * =================
26  *
27  * The timer is used by calling \ref turi::timer::start and then
28  * by getting the current time since start by calling
29  * \ref turi::timer::current_time.
30  *
31  * For example:
32  *
33  * \code
34  * #include <timer/timer.hpp>
35  *
36  *
37  * turi::timer timer;
38  * timer.start();
39  * // do something
40  * std::cout << "Elapsed time: " << timer.current_time() << std::endl;
41  * \endcode
42  *
43  * Sleeping
44  * ========
45  * The sleep routines here are preferred than the sleep method provided
46  * by the standard C library. On Linux, the C sleep method can be woken up
47  * by signals, hence it may not sleep the full prescribed interval.
48  * The sleep implemented in the timer are more resilient.
49  *
50  * Fast approximate time
51  * ====================
52  *
53  * Calling current item in a tight loop can be costly and so we
54  * provide a faster less accurate timing primitive which reads a
55  * local time variable that is updated roughly every 100 millisecond.
56  * These are the \ref turi::timer::approx_time_seconds and
57  * \ref turi::timer::approx_time_millis.
58  */
59  class timer {
60  private:
61  /**
62  * \brief The internal start time for this timer object
63  */
64  timeval start_time_;
65  public:
66  /**
67  * \brief The timer starts on construction but can be restarted by
68  * calling \ref turi::timer::start.
69  */
70  inline timer() { start(); }
71 
72  /**
73  * \brief Reset the timer.
74  */
75  inline void start() { gettimeofday(&start_time_, NULL); }
76 
77  /**
78  * \brief Returns the elapsed time in seconds since
79  * \ref turi::timer::start was last called.
80  *
81  * @return time in seconds since \ref turi::timer::start was called.
82  */
83  inline double current_time() const {
84  timeval current_time;
85  gettimeofday(&current_time, NULL);
86  double answer =
87  // (current_time.tv_sec + ((double)current_time.tv_usec)/1.0E6) -
88  // (start_time_.tv_sec + ((double)start_time_.tv_usec)/1.0E6);
89  (double)(current_time.tv_sec - start_time_.tv_sec) +
90  ((double)(current_time.tv_usec - start_time_.tv_usec))/1.0E6;
91  return answer;
92  } // end of current_time
93 
94  /**
95  * \brief Returns the elapsed time in milliseconds since
96  * \ref turi::timer::start was last called.
97  *
98  * @return time in milliseconds since \ref turi::timer::start was called.
99  */
100  inline double current_time_millis() const { return current_time() * 1000; }
101 
102  /**
103  * \brief Get the number of seconds (as a floating point value)
104  * since the Unix Epoch.
105  */
106  static double sec_of_day() {
107  timeval current_time;
108  gettimeofday(&current_time, NULL);
109  double answer =
110  (double)current_time.tv_sec + ((double)current_time.tv_usec)/1.0E6;
111  return answer;
112  } // end of sec_of_day
113 
114  /**
115  * \brief Returns only the micro-second component of the
116  * time since the Unix Epoch.
117  */
118  static size_t usec_of_day() {
119  timeval current_time;
120  gettimeofday(&current_time, NULL);
121  size_t answer =
122  (size_t)current_time.tv_sec * 1000000 + (size_t)current_time.tv_usec;
123  return answer;
124  } // end of usec_of_day
125 
126  /**
127  * \brief Returns the time since program start.
128  *
129  * This value is only updated once every 100ms and is therefore
130  * approximate (but fast).
131  */
132  static float approx_time_seconds();
133 
134  /**
135  * \brief Returns the time since program start.
136  *
137  * This value is only updated once every 100ms and is therefore
138  * approximate (but fast).
139  */
140  static size_t approx_time_millis();
141 
142  /**
143  * \brief Stops the approximate timer.
144  *
145  * This stops the approximate timer thread. Once stoped, the approximate
146  * time will never be advanced again. This function should not generally
147  * be used, but it seems like on certain platforms (windows for instance)
148  * it does not like terminating threads inside DLLs at program terminiation.
149  * This can be used to force thread termination.
150  *
151  * \see approx_time_seconds approx_time_millis
152  */
153  static void stop_approx_timer();
154 
155  /**
156  * Sleeps for sleeplen seconds
157  */
158  static void sleep(size_t sleeplen);
159 
160  /**
161  * Sleeps for sleeplen milliseconds.
162  */
163  static void sleep_ms(size_t sleeplen);
164  }; // end of Timer
165 
166  typedef unsigned long long rdtsc_type;
167 
168  /**
169  * \ingroup util
170  * Estimates the number of RDTSC ticks per second.
171  */
172  rdtsc_type estimate_ticks_per_second();
173 
174  #if defined(__i386__)
175  /**
176  * \ingroup util
177  * Returns the RDTSC value.
178  */
179  inline rdtsc_type rdtsc(void) {
180  unsigned long long int x;
181  __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
182  return x;
183  }
184  #elif defined(__x86_64__)
185  /**
186  * \ingroup util
187  * Returns the RDTSC value.
188  */
189  inline rdtsc_type rdtsc(void) {
190  unsigned hi, lo;
191  __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
192  return ( (unsigned long long)lo) | ( ((unsigned long long)hi)<<32 );
193  }
194  #else
195  /**
196  * \ingroup util
197  * Returns the RDTSC value.
198  */
199  inline rdtsc_type rdtsc(void) {
200  return 0;
201  }
202  #endif
203 
204 
205  /**
206  * \ingroup util
207  * Very rudimentary timer class which allows tracking of fine grained
208  * time with extremely low overhead using the RDTSC instruction.
209  * Basic usage:
210  * \code
211  * rdtsc_time time;
212  * ... // do stuff
213  * time.ms(); // returns the number of milliseconds passed.
214  * \endcode
215  *
216  * Also see \ref rdtsc and \ref estimate_ticks_per_second
217  */
218  struct rdtsc_time {
219  rdtsc_type begin;
220  /**
221  * Constructs an rdtsc_time object and begin tracking the time.
222  */
223  rdtsc_time():begin(rdtsc()) { }
224 
225  /**
226  * Returns the number of milliseconds passed since the rdtsc_time
227  * object was constructed.
228  */
229  double ms() const {
230  rdtsc_type end = rdtsc();
231  double dtime = end - begin;
232  dtime = dtime * 1000 / estimate_ticks_per_second();
233  return dtime;
234  }
235  };
236 
237 
238 
239 } // end of turi namespace
240 
241 /**
242  * Convenience function. Allows you to call "cout << ti" where ti is
243  * a timer object and it will print the number of seconds elapsed
244  * since ti.start() was called.
245  */
246 std::ostream& operator<<(std::ostream& out, const turi::timer& t);
247 
248 
249 #endif
double current_time_millis() const
Returns the elapsed time in milliseconds since turi::timer::start was last called.
Definition: timer.hpp:100
void start()
Reset the timer.
Definition: timer.hpp:75
double ms() const
Definition: timer.hpp:229
static void sleep_ms(size_t sleeplen)
static size_t approx_time_millis()
Returns the time since program start.
static double sec_of_day()
Get the number of seconds (as a floating point value) since the Unix Epoch.
Definition: timer.hpp:106
static float approx_time_seconds()
Returns the time since program start.
rdtsc_type rdtsc(void)
Definition: timer.hpp:199
static size_t usec_of_day()
Returns only the micro-second component of the time since the Unix Epoch.
Definition: timer.hpp:118
rdtsc_type estimate_ticks_per_second()
double current_time() const
Returns the elapsed time in seconds since turi::timer::start was last called.
Definition: timer.hpp:83
static void stop_approx_timer()
Stops the approximate timer.
timer()
The timer starts on construction but can be restarted by calling turi::timer::start.
Definition: timer.hpp:70
A simple class that can be used for benchmarking/timing up to microsecond resolution.
Definition: timer.hpp:59
static void sleep(size_t sleeplen)