high_resolution_timer.hpp 15 KB

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