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