OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 // Windows Timer Primer | 6 // Windows Timer Primer |
7 // | 7 // |
8 // A good article: http://www.ddj.com/windows/184416651 | 8 // A good article: http://www.ddj.com/windows/184416651 |
9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 | 9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 |
10 // | 10 // |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 // (3) System time. The system time provides a low-resolution (typically 10ms | 337 // (3) System time. The system time provides a low-resolution (typically 10ms |
338 // to 55 milliseconds) time stamp but is comparatively less expensive to | 338 // to 55 milliseconds) time stamp but is comparatively less expensive to |
339 // retrieve and more reliable. | 339 // retrieve and more reliable. |
340 class HighResNowSingleton { | 340 class HighResNowSingleton { |
341 public: | 341 public: |
342 static HighResNowSingleton* GetInstance() { | 342 static HighResNowSingleton* GetInstance() { |
343 return Singleton<HighResNowSingleton>::get(); | 343 return Singleton<HighResNowSingleton>::get(); |
344 } | 344 } |
345 | 345 |
346 bool IsUsingHighResClock() { | 346 bool IsUsingHighResClock() { |
347 return ticks_per_microsecond_ != 0.0; | 347 return ticks_per_second_ != 0.0; |
348 } | 348 } |
349 | 349 |
350 void DisableHighResClock() { | 350 void DisableHighResClock() { |
351 ticks_per_microsecond_ = 0.0; | 351 ticks_per_second_ = 0.0; |
352 } | 352 } |
353 | 353 |
354 TimeDelta Now() { | 354 TimeDelta Now() { |
355 if (IsUsingHighResClock()) | 355 if (IsUsingHighResClock()) |
356 return TimeDelta::FromMicroseconds(UnreliableNow()); | 356 return TimeDelta::FromMicroseconds(UnreliableNow()); |
357 | 357 |
358 // Just fallback to the slower clock. | 358 // Just fallback to the slower clock. |
359 return RolloverProtectedNow(); | 359 return RolloverProtectedNow(); |
360 } | 360 } |
361 | 361 |
362 int64 GetQPCDriftMicroseconds() { | 362 int64 GetQPCDriftMicroseconds() { |
363 if (!IsUsingHighResClock()) | 363 if (!IsUsingHighResClock()) |
364 return 0; | 364 return 0; |
365 | 365 |
366 // The static_cast<long> is needed as a hint to VS 2008 to tell it | 366 // The static_cast<long> is needed as a hint to VS 2008 to tell it |
367 // which version of abs() to use. Other compilers don't seem to | 367 // which version of abs() to use. Other compilers don't seem to |
368 // need it, including VS 2010, but to keep code identical we use it | 368 // need it, including VS 2010, but to keep code identical we use it |
369 // everywhere. | 369 // everywhere. |
370 // TODO(joi): Remove the hint if/when we no longer support VS 2008. | 370 // TODO(joi): Remove the hint if/when we no longer support VS 2008. |
371 return abs(static_cast<long>((UnreliableNow() - ReliableNow()) - skew_)); | 371 return abs(static_cast<long>((UnreliableNow() - ReliableNow()) - skew_)); |
372 } | 372 } |
373 | 373 |
| 374 int64 QPCValueToMicroseconds(LONGLONG qpc_value) { |
| 375 if (!ticks_per_second_) |
| 376 return 0; |
| 377 |
| 378 // Intentionally calculate microseconds in a round about manner to avoid |
| 379 // overflow and precision issues. Think twice before simplifying! |
| 380 int64 whole_seconds = qpc_value / ticks_per_second_; |
| 381 int64 leftover_ticks = qpc_value % ticks_per_second_; |
| 382 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + |
| 383 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
| 384 ticks_per_second_); |
| 385 return microseconds; |
| 386 } |
| 387 |
374 private: | 388 private: |
375 HighResNowSingleton() | 389 HighResNowSingleton() |
376 : ticks_per_microsecond_(0.0), | 390 : ticks_per_second_(0), |
377 skew_(0) { | 391 skew_(0) { |
378 InitializeClock(); | 392 InitializeClock(); |
379 | 393 |
380 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is | 394 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is |
381 // unreliable. Fallback to low-res clock. | 395 // unreliable. Fallback to low-res clock. |
382 base::CPU cpu; | 396 base::CPU cpu; |
383 if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) | 397 if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) |
384 DisableHighResClock(); | 398 DisableHighResClock(); |
385 } | 399 } |
386 | 400 |
387 // Synchronize the QPC clock with GetSystemTimeAsFileTime. | 401 // Synchronize the QPC clock with GetSystemTimeAsFileTime. |
388 void InitializeClock() { | 402 void InitializeClock() { |
389 LARGE_INTEGER ticks_per_sec = {0}; | 403 LARGE_INTEGER ticks_per_sec = {0}; |
390 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 404 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
391 return; // Broken, we don't guarantee this function works. | 405 return; // Broken, we don't guarantee this function works. |
392 ticks_per_microsecond_ = static_cast<float>(ticks_per_sec.QuadPart) / | 406 ticks_per_second_ = ticks_per_sec.QuadPart; |
393 static_cast<float>(Time::kMicrosecondsPerSecond); | |
394 | 407 |
395 skew_ = UnreliableNow() - ReliableNow(); | 408 skew_ = UnreliableNow() - ReliableNow(); |
396 } | 409 } |
397 | 410 |
398 // Get the number of microseconds since boot in an unreliable fashion. | 411 // Get the number of microseconds since boot in an unreliable fashion. |
399 int64 UnreliableNow() { | 412 int64 UnreliableNow() { |
400 LARGE_INTEGER now; | 413 LARGE_INTEGER now; |
401 QueryPerformanceCounter(&now); | 414 QueryPerformanceCounter(&now); |
402 return static_cast<int64>(now.QuadPart / ticks_per_microsecond_); | 415 return QPCValueToMicroseconds(now.QuadPart); |
403 } | 416 } |
404 | 417 |
405 // Get the number of microseconds since boot in a reliable fashion. | 418 // Get the number of microseconds since boot in a reliable fashion. |
406 int64 ReliableNow() { | 419 int64 ReliableNow() { |
407 return RolloverProtectedNow().InMicroseconds(); | 420 return RolloverProtectedNow().InMicroseconds(); |
408 } | 421 } |
409 | 422 |
410 // Cached clock frequency -> microseconds. This assumes that the clock | 423 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. |
411 // frequency is faster than one microsecond (which is 1MHz, should be OK). | |
412 float ticks_per_microsecond_; // 0 indicates QPF failed and we're broken. | |
413 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). | 424 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). |
414 | 425 |
415 friend struct DefaultSingletonTraits<HighResNowSingleton>; | 426 friend struct DefaultSingletonTraits<HighResNowSingleton>; |
416 }; | 427 }; |
417 | 428 |
418 } // namespace | 429 } // namespace |
419 | 430 |
420 // static | 431 // static |
421 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 432 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
422 TickFunctionType ticker) { | 433 TickFunctionType ticker) { |
(...skipping 16 matching lines...) Expand all Loading... |
439 TimeTicks TimeTicks::NowFromSystemTraceTime() { | 450 TimeTicks TimeTicks::NowFromSystemTraceTime() { |
440 return HighResNow(); | 451 return HighResNow(); |
441 } | 452 } |
442 | 453 |
443 // static | 454 // static |
444 int64 TimeTicks::GetQPCDriftMicroseconds() { | 455 int64 TimeTicks::GetQPCDriftMicroseconds() { |
445 return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds(); | 456 return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds(); |
446 } | 457 } |
447 | 458 |
448 // static | 459 // static |
| 460 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 461 return TimeTicks( |
| 462 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); |
| 463 } |
| 464 |
| 465 // static |
449 bool TimeTicks::IsHighResClockWorking() { | 466 bool TimeTicks::IsHighResClockWorking() { |
450 return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); | 467 return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); |
451 } | 468 } |
| 469 |
| 470 // TimeDelta ------------------------------------------------------------------ |
| 471 |
| 472 // static |
| 473 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 474 return TimeDelta( |
| 475 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); |
| 476 } |
OLD | NEW |