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