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