blob: afa5495dad7cef60109463c191a4ff55007e1a0c [file] [log] [blame]
Brian Silverman88678712018-08-04 23:56:48 -07001// 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
24namespace boost {
25namespace archive {
26namespace 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:
37 high_resolution_timer()
38 {
39 restart();
40 }
41
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
51 high_resolution_timer(high_resolution_timer const& rhs)
52 : start_time(rhs.start_time)
53 {
54 }
55
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
72 void restart()
73 {
74 if (!QueryPerformanceCounter(&start_time))
75 boost::throw_exception(std::runtime_error("Couldn't initialize start_time"));
76 }
77 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
90 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
100 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
121namespace boost {
122namespace archive {
123namespace 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:
134 high_resolution_timer()
135 {
136 start_time.tv_sec = 0;
137 start_time.tv_nsec = 0;
138
139 restart();
140 }
141
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
148 high_resolution_timer(high_resolution_timer const& rhs)
149 : start_time(rhs.start_time)
150 {
151 }
152
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
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 }
166 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
179 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
184 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
205namespace boost {
206namespace archive {
207namespace xml {
208 ///////////////////////////////////////////////////////////////////////////////
209 //
210 // high_resolution_timer
211 // A timer object measures elapsed time.
212 //
213 ///////////////////////////////////////////////////////////////////////////////
214 class high_resolution_timer
215 {
216 public:
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
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
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
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
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 }
260 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
276 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
284 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
318namespace boost {
319namespace archive {
320namespace 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>
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.
350 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:
366 high_resolution_timer()
367 {
368 start_time.tv_sec = 0;
369 start_time.tv_usec = 0;
370
371 restart();
372 }
373
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
380 high_resolution_timer(high_resolution_timer const& rhs)
381 : start_time(rhs.start_time)
382 {
383 }
384
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
399 void restart()
400 {
401 if (gettimeofday(&start_time, NULL))
402 boost::throw_exception(std::runtime_error("Couldn't initialize start_time"));
403 }
404
405 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
413 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
418 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
456namespace boost {
457namespace archive {
458namespace xml {
459
460 struct high_resolution_timer
461 : boost::timer
462 {
463 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//