1 //  Copyright (c) 2005-2010 Hartmut Kaiser
2 //  Copyright (c) 2009      Edward Grace
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(HIGH_RESOLUTION_TIMER_MAR_24_2008_1222PM)
8 #define HIGH_RESOLUTION_TIMER_MAR_24_2008_1222PM
9 
10 #include <boost/config.hpp>
11 #include <boost/throw_exception.hpp>
12 
13 #if defined(BOOST_HAS_UNISTD_H)
14 #include <unistd.h>
15 #endif
16 #include <time.h>
17 #include <stdexcept>
18 #include <limits>
19 
20 #if defined(BOOST_WINDOWS)
21 
22 #include <windows.h>
23 
24 namespace util
25 {
26     ///////////////////////////////////////////////////////////////////////////////
27     //
28     //  high_resolution_timer
29     //      A timer object measures elapsed time.
30     //      CAUTION: Windows only!
31     //
32     ///////////////////////////////////////////////////////////////////////////////
33     class high_resolution_timer
34     {
35     public:
high_resolution_timer()36         high_resolution_timer()
37         {
38             restart();
39         }
40 
high_resolution_timer(double t)41         high_resolution_timer(double t)
42         {
43             LARGE_INTEGER frequency;
44             if (!QueryPerformanceFrequency(&frequency))
45                 boost::throw_exception(std::runtime_error("Couldn't acquire frequency"));
46 
47             start_time.QuadPart = (LONGLONG)(t * frequency.QuadPart);
48         }
49 
high_resolution_timer(high_resolution_timer const & rhs)50         high_resolution_timer(high_resolution_timer const& rhs)
51           : start_time(rhs.start_time)
52         {
53         }
54 
now()55         static double now()
56         {
57             SYSTEMTIME st;
58             GetSystemTime(&st);
59 
60             FILETIME ft;
61             SystemTimeToFileTime(&st, &ft);
62 
63             LARGE_INTEGER now;
64             now.LowPart = ft.dwLowDateTime;
65             now.HighPart = ft.dwHighDateTime;
66 
67             // FileTime is in 100ns increments, result needs to be in [s]
68             return now.QuadPart * 1e-7;
69         }
70 
restart()71         void restart()
72         {
73             if (!QueryPerformanceCounter(&start_time))
74                 boost::throw_exception(std::runtime_error("Couldn't initialize start_time"));
75         }
elapsed() const76         double elapsed() const                  // return elapsed time in seconds
77         {
78             LARGE_INTEGER now;
79             if (!QueryPerformanceCounter(&now))
80                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
81 
82             LARGE_INTEGER frequency;
83             if (!QueryPerformanceFrequency(&frequency))
84                 boost::throw_exception(std::runtime_error("Couldn't acquire frequency"));
85 
86             return double(now.QuadPart - start_time.QuadPart) / frequency.QuadPart;
87         }
88 
elapsed_max() const89         double elapsed_max() const   // return estimated maximum value for elapsed()
90         {
91             LARGE_INTEGER frequency;
92             if (!QueryPerformanceFrequency(&frequency))
93                 boost::throw_exception(std::runtime_error("Couldn't acquire frequency"));
94 
95             return double((std::numeric_limits<LONGLONG>::max)() - start_time.QuadPart) /
96                 double(frequency.QuadPart);
97         }
98 
elapsed_min() const99         double elapsed_min() const            // return minimum value for elapsed()
100         {
101             LARGE_INTEGER frequency;
102             if (!QueryPerformanceFrequency(&frequency))
103                 boost::throw_exception(std::runtime_error("Couldn't acquire frequency"));
104 
105             return 1.0 / frequency.QuadPart;
106         }
107 
108     private:
109         LARGE_INTEGER start_time;
110     };
111 
112 } // namespace util
113 
114 #elif defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(_POSIX_THREAD_CPUTIME)
115 
116 #if _POSIX_THREAD_CPUTIME > 0   // timer always supported
117 
118 namespace util
119 {
120 
121     ///////////////////////////////////////////////////////////////////////////////
122     //
123     //  high_resolution_timer
124     //      A timer object measures elapsed time.
125     //
126     ///////////////////////////////////////////////////////////////////////////////
127     class high_resolution_timer
128     {
129     public:
high_resolution_timer()130         high_resolution_timer()
131         {
132             start_time.tv_sec = 0;
133             start_time.tv_nsec = 0;
134 
135             restart();
136         }
137 
high_resolution_timer(double t)138         high_resolution_timer(double t)
139         {
140             start_time.tv_sec = time_t(t);
141             start_time.tv_nsec = (t - start_time.tv_sec) * 1e9;
142         }
143 
high_resolution_timer(high_resolution_timer const & rhs)144         high_resolution_timer(high_resolution_timer const& rhs)
145           : start_time(rhs.start_time)
146         {
147         }
148 
now()149         static double now()
150         {
151             timespec now;
152             if (-1 == clock_gettime(CLOCK_REALTIME, &now))
153                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
154             return double(now.tv_sec) + double(now.tv_nsec) * 1e-9;
155         }
156 
restart()157         void restart()
158         {
159             if (-1 == clock_gettime(CLOCK_REALTIME, &start_time))
160                 boost::throw_exception(std::runtime_error("Couldn't initialize start_time"));
161         }
elapsed() const162         double elapsed() const                  // return elapsed time in seconds
163         {
164             timespec now;
165             if (-1 == clock_gettime(CLOCK_REALTIME, &now))
166                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
167 
168             if (now.tv_sec == start_time.tv_sec)
169                 return double(now.tv_nsec - start_time.tv_nsec) * 1e-9;
170 
171             return double(now.tv_sec - start_time.tv_sec) +
172                 (double(now.tv_nsec - start_time.tv_nsec) * 1e-9);
173         }
174 
elapsed_max() const175         double elapsed_max() const   // return estimated maximum value for elapsed()
176         {
177             return double((std::numeric_limits<time_t>::max)() - start_time.tv_sec);
178         }
179 
elapsed_min() const180         double elapsed_min() const            // return minimum value for elapsed()
181         {
182             timespec resolution;
183             if (-1 == clock_getres(CLOCK_REALTIME, &resolution))
184                 boost::throw_exception(std::runtime_error("Couldn't get resolution"));
185             return double(resolution.tv_sec + resolution.tv_nsec * 1e-9);
186         }
187 
188     private:
189         timespec start_time;
190     };
191 
192 } // namespace util
193 
194 #else   // _POSIX_THREAD_CPUTIME > 0
195 
196 #include <boost/timer.hpp>
197 
198 // availability of high performance timers must be checked at runtime
199 namespace util
200 {
201     ///////////////////////////////////////////////////////////////////////////////
202     //
203     //  high_resolution_timer
204     //      A timer object measures elapsed time.
205     //
206     ///////////////////////////////////////////////////////////////////////////////
207     class high_resolution_timer
208     {
209     public:
high_resolution_timer()210         high_resolution_timer()
211           : use_backup(sysconf(_SC_THREAD_CPUTIME) <= 0)
212         {
213             if (!use_backup) {
214                 start_time.tv_sec = 0;
215                 start_time.tv_nsec = 0;
216             }
217             restart();
218         }
219 
high_resolution_timer(double t)220         high_resolution_timer(double t)
221           : use_backup(sysconf(_SC_THREAD_CPUTIME) <= 0)
222         {
223             if (!use_backup) {
224                 start_time.tv_sec = time_t(t);
225                 start_time.tv_nsec = (t - start_time.tv_sec) * 1e9;
226             }
227         }
228 
high_resolution_timer(high_resolution_timer const & rhs)229         high_resolution_timer(high_resolution_timer const& rhs)
230           : use_backup(sysconf(_SC_THREAD_CPUTIME) <= 0),
231             start_time(rhs.start_time)
232         {
233         }
234 
now()235         static double now()
236         {
237             if (sysconf(_SC_THREAD_CPUTIME) <= 0)
238                 return double(std::clock());
239 
240             timespec now;
241             if (-1 == clock_gettime(CLOCK_REALTIME, &now))
242                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
243             return double(now.tv_sec) + double(now.tv_nsec) * 1e-9;
244         }
245 
restart()246         void restart()
247         {
248             if (use_backup)
249                 start_time_backup.restart();
250             else if (-1 == clock_gettime(CLOCK_REALTIME, &start_time))
251                 boost::throw_exception(std::runtime_error("Couldn't initialize start_time"));
252         }
elapsed() const253         double elapsed() const                  // return elapsed time in seconds
254         {
255             if (use_backup)
256                 return start_time_backup.elapsed();
257 
258             timespec now;
259             if (-1 == clock_gettime(CLOCK_REALTIME, &now))
260                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
261 
262             if (now.tv_sec == start_time.tv_sec)
263                 return double(now.tv_nsec - start_time.tv_nsec) * 1e-9;
264 
265             return double(now.tv_sec - start_time.tv_sec) +
266                 (double(now.tv_nsec - start_time.tv_nsec) * 1e-9);
267         }
268 
elapsed_max() const269         double elapsed_max() const   // return estimated maximum value for elapsed()
270         {
271             if (use_backup)
272                 start_time_backup.elapsed_max();
273 
274             return double((std::numeric_limits<time_t>::max)() - start_time.tv_sec);
275         }
276 
elapsed_min() const277         double elapsed_min() const            // return minimum value for elapsed()
278         {
279             if (use_backup)
280                 start_time_backup.elapsed_min();
281 
282             timespec resolution;
283             if (-1 == clock_getres(CLOCK_REALTIME, &resolution))
284                 boost::throw_exception(std::runtime_error("Couldn't get resolution"));
285             return double(resolution.tv_sec + resolution.tv_nsec * 1e-9);
286         }
287 
288     private:
289         bool use_backup;
290         timespec start_time;
291         boost::timer start_time_backup;
292     };
293 
294 } // namespace util
295 
296 #endif  // _POSIX_THREAD_CPUTIME > 0
297 
298 #else   //  !defined(BOOST_WINDOWS) && (!defined(_POSIX_TIMERS)
299         //      || _POSIX_TIMERS <= 0
300         //      || !defined(_POSIX_THREAD_CPUTIME)
301         //      || _POSIX_THREAD_CPUTIME <= 0)
302 
303 #if defined(BOOST_HAS_GETTIMEOFDAY)
304 
305 // For platforms that do not support _POSIX_TIMERS but do have
306 // GETTIMEOFDAY, which is still preferable to std::clock()
307 #include <sys/time.h>
308 
309 namespace util
310 {
311 
312     ///////////////////////////////////////////////////////////////////////////
313     //
314     //  high_resolution_timer
315     //      A timer object measures elapsed time.
316     //
317     //  Implemented with gettimeofday() for platforms that support it,
318     //  such as Darwin (OS X) but do not support the previous options.
319     //
320     //  Copyright (c) 2009 Edward Grace
321     //
322     ///////////////////////////////////////////////////////////////////////////
323     class high_resolution_timer
324     {
325     private:
326         template <typename U>
unsigned_diff(const U & a,const U & b)327         static inline double unsigned_diff(const U &a, const U &b)
328         {
329             if (a > b)
330                 return static_cast<double>(a-b);
331             return -static_cast<double>(b-a);
332         }
333 
334         // @brief Return the difference between two timeval types.
335         //
336         // @param t1 The most recent timeval.
337         // @param t0 The historical timeval.
338         //
339         // @return The difference between the two in seconds.
elapsed(const timeval & t1,const timeval & t0) const340         double elapsed(const timeval &t1, const timeval &t0) const
341         {
342             if (t1.tv_sec == t0.tv_sec)
343                 return unsigned_diff(t1.tv_usec,t0.tv_usec) * 1e-6;
344 
345             // We do it this way as the result of the difference of the
346             // microseconds can be negative if the clock is implemented so
347             // that the seconds timer increases in large steps.
348             //
349             // Naive subtraction of the unsigned types and conversion to
350             // double can wreak havoc!
351             return unsigned_diff(t1.tv_sec,t0.tv_sec) +
352                 unsigned_diff(t1.tv_usec,t0.tv_usec) * 1e-6;
353         }
354 
355     public:
high_resolution_timer()356         high_resolution_timer()
357         {
358             start_time.tv_sec = 0;
359             start_time.tv_usec = 0;
360 
361             restart();
362         }
363 
high_resolution_timer(double t)364         high_resolution_timer(double t)
365         {
366             start_time.tv_sec = time_t(t);
367             start_time.tv_usec = (t - start_time.tv_sec) * 1e6;
368         }
369 
high_resolution_timer(high_resolution_timer const & rhs)370         high_resolution_timer(high_resolution_timer const& rhs)
371           : start_time(rhs.start_time)
372         {
373         }
374 
now()375         static double now()
376         {
377             // Under some implementations gettimeofday() will always
378             // return zero. If it returns anything else however then
379             // we accept this as evidence of an error.  Note we are
380             // not assuming that -1 explicitly indicates the error
381             // condition, just that non zero is indicative of the
382             // error.
383             timeval now;
384             if (gettimeofday(&now, NULL))
385                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
386             return double(now.tv_sec) + double(now.tv_usec) * 1e-6;
387         }
388 
restart()389         void restart()
390         {
391             if (gettimeofday(&start_time, NULL))
392                 boost::throw_exception(std::runtime_error("Couldn't initialize start_time"));
393         }
394 
elapsed() const395         double elapsed() const                  // return elapsed time in seconds
396         {
397             timeval now;
398             if (gettimeofday(&now, NULL))
399                 boost::throw_exception(std::runtime_error("Couldn't get current time"));
400             return elapsed(now,start_time);
401         }
402 
elapsed_max() const403         double elapsed_max() const   // return estimated maximum value for elapsed()
404         {
405             return double((std::numeric_limits<time_t>::max)() - start_time.tv_sec);
406         }
407 
elapsed_min() const408         double elapsed_min() const            // return minimum value for elapsed()
409         {
410             // On systems without an explicit clock_getres or similar
411             // we can only estimate an upper bound on the resolution
412             // by repeatedly calling the gettimeofday function.  This
413             // is often likely to be indicative of the true
414             // resolution.
415             timeval t0, t1;
416             double delta(0);
417 
418             if (gettimeofday(&t0, NULL))
419                 boost::throw_exception(std::runtime_error("Couldn't get resolution."));
420 
421             // Spin around in a tight loop until we observe a change
422             // in the reported timer value.
423             do {
424                 if (gettimeofday(&t1, NULL))
425                     boost::throw_exception(std::runtime_error("Couldn't get resolution."));
426                 delta = elapsed(t1, t0);
427             } while (delta <= 0.0);
428 
429             return delta;
430         }
431 
432     private:
433         timeval start_time;
434     };
435 
436 }
437 
438 #else // BOOST_HAS_GETTIMEOFDAY
439 
440 //  For platforms other than Windows or Linux, or not implementing gettimeofday
441 //  simply fall back to boost::timer
442 #include <boost/timer.hpp>
443 
444 namespace util
445 {
446     struct high_resolution_timer
447         : boost::timer
448     {
nowutil::high_resolution_timer449         static double now()
450         {
451             return double(std::clock());
452         }
453     };
454 }
455 
456 #endif
457 
458 #endif
459 
460 #endif  // HIGH_RESOLUTION_TIMER_AUG_14_2009_0425PM
461 
462 //
463 // $Log: high_resolution_timer.hpp,v $
464 // Revision 1.4  2009/08/14 15:28:10  graceej
465 // * It is entirely possible for the updating clock to increment the
466 // * seconds and *decrement* the microseconds field.  Consequently
467 // * when subtracting these unsigned microseconds fields a wrap-around
468 // * error can occur.  For this reason elapsed(t1, t0) is used in a
469 // * similar maner to cycle.h this preserves the sign of the
470 // * difference.
471 //
472 
473 
474