high_resolution_timer.hpp 15 KB

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