Chromium Code Reviews| 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 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 352 // reality due to bugs in BIOS or HAL on some, especially old computers. | 352 // reality due to bugs in BIOS or HAL on some, especially old computers. |
| 353 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but | 353 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but |
| 354 // it should be used with caution. | 354 // it should be used with caution. |
| 355 // | 355 // |
| 356 // (3) System time. The system time provides a low-resolution (typically 10ms | 356 // (3) System time. The system time provides a low-resolution (typically 10ms |
| 357 // to 55 milliseconds) time stamp but is comparatively less expensive to | 357 // to 55 milliseconds) time stamp but is comparatively less expensive to |
| 358 // retrieve and more reliable. | 358 // retrieve and more reliable. |
| 359 class HighResNowSingleton { | 359 class HighResNowSingleton { |
| 360 public: | 360 public: |
| 361 HighResNowSingleton() | 361 HighResNowSingleton() |
| 362 : ticks_per_second_(0), | 362 : ticks_per_second_(0), |
| 363 skew_(0) { | 363 skew_(0) { |
| 364 InitializeClock(); | |
| 365 | 364 |
| 366 base::CPU cpu; | 365 base::CPU cpu; |
| 367 if (IsBuggyAthlon(cpu)) | 366 if (IsBuggyAthlon(cpu)) |
| 368 DisableHighResClock(); | 367 return; |
| 368 | |
| 369 // Synchronize the QPC clock with GetSystemTimeAsFileTime. | |
| 370 LARGE_INTEGER ticks_per_sec = {0}; | |
| 371 if (!QueryPerformanceFrequency(&ticks_per_sec)) | |
| 372 return; // QPC is not available. | |
| 373 ticks_per_second_ = ticks_per_sec.QuadPart; | |
| 374 | |
| 375 skew_ = UnreliableNow() - ReliableNow(); | |
| 369 } | 376 } |
| 370 | 377 |
| 371 bool IsUsingHighResClock() { | 378 bool IsUsingHighResClock() { |
| 372 return ticks_per_second_ != 0.0; | 379 return ticks_per_second_ != 0; |
| 373 } | |
| 374 | |
| 375 void DisableHighResClock() { | |
| 376 ticks_per_second_ = 0.0; | |
| 377 } | 380 } |
| 378 | 381 |
| 379 TimeDelta Now() { | 382 TimeDelta Now() { |
| 380 if (IsUsingHighResClock()) | 383 if (IsUsingHighResClock()) |
| 381 return TimeDelta::FromMicroseconds(UnreliableNow()); | 384 return TimeDelta::FromMicroseconds(UnreliableNow()); |
| 382 | 385 |
| 383 // Just fallback to the slower clock. | 386 // Just fallback to the slower clock. |
| 384 return RolloverProtectedNow(); | 387 return RolloverProtectedNow(); |
| 385 } | 388 } |
| 386 | 389 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 401 // overflow and precision issues. | 404 // overflow and precision issues. |
| 402 int64 whole_seconds = qpc_value / ticks_per_second_; | 405 int64 whole_seconds = qpc_value / ticks_per_second_; |
| 403 int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_); | 406 int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_); |
| 404 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + | 407 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + |
| 405 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 408 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
| 406 ticks_per_second_); | 409 ticks_per_second_); |
| 407 return microseconds; | 410 return microseconds; |
| 408 } | 411 } |
| 409 | 412 |
| 410 private: | 413 private: |
| 411 // Synchronize the QPC clock with GetSystemTimeAsFileTime. | |
| 412 void InitializeClock() { | |
| 413 LARGE_INTEGER ticks_per_sec = {0}; | |
| 414 if (!QueryPerformanceFrequency(&ticks_per_sec)) | |
| 415 return; // Broken, we don't guarantee this function works. | |
| 416 ticks_per_second_ = ticks_per_sec.QuadPart; | |
| 417 | |
| 418 skew_ = UnreliableNow() - ReliableNow(); | |
| 419 } | |
| 420 | |
| 421 // Get the number of microseconds since boot in an unreliable fashion. | 414 // Get the number of microseconds since boot in an unreliable fashion. |
| 422 int64 UnreliableNow() { | 415 int64 UnreliableNow() { |
| 423 LARGE_INTEGER now; | 416 LARGE_INTEGER now; |
| 424 QueryPerformanceCounter(&now); | 417 QueryPerformanceCounter(&now); |
| 425 return QPCValueToMicroseconds(now.QuadPart); | 418 return QPCValueToMicroseconds(now.QuadPart); |
| 426 } | 419 } |
| 427 | 420 |
| 428 // Get the number of microseconds since boot in a reliable fashion. | 421 // Get the number of microseconds since boot in a reliable fashion. |
| 429 int64 ReliableNow() { | 422 int64 ReliableNow() { |
| 430 return RolloverProtectedNow().InMicroseconds(); | 423 return RolloverProtectedNow().InMicroseconds(); |
| 431 } | 424 } |
| 432 | 425 |
| 433 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. | 426 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. |
| 434 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). | 427 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). |
| 435 }; | 428 }; |
| 436 | 429 |
| 437 static base::LazyInstance<HighResNowSingleton>::Leaky | 430 static base::LazyInstance<HighResNowSingleton>::Leaky |
| 438 leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER; | 431 leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER; |
| 439 | 432 |
| 440 HighResNowSingleton* GetHighResNowSingleton() { | 433 HighResNowSingleton* GetHighResNowSingleton() { |
| 441 return leaky_high_res_now_singleton.Pointer(); | 434 return leaky_high_res_now_singleton.Pointer(); |
| 442 } | 435 } |
| 443 | 436 |
| 444 TimeDelta HighResNowWrapper() { | 437 TimeDelta HighResNowWrapper() { |
| 445 return GetHighResNowSingleton()->Now(); | 438 return GetHighResNowSingleton()->Now(); |
| 446 } | 439 } |
| 447 | 440 |
| 448 typedef TimeDelta (*NowFunction)(void); | 441 typedef TimeDelta (*NowFunction)(void); |
| 449 NowFunction now_function = RolloverProtectedNow; | |
| 450 | 442 |
| 451 bool CPUReliablySupportsHighResTime() { | 443 bool CPUReliablySupportsHighResTime() { |
| 452 base::CPU cpu; | 444 base::CPU cpu; |
| 453 if (!cpu.has_non_stop_time_stamp_counter() || | 445 if (!cpu.has_non_stop_time_stamp_counter() || |
| 454 !GetHighResNowSingleton()->IsUsingHighResClock()) | 446 !GetHighResNowSingleton()->IsUsingHighResClock()) |
| 455 return false; | 447 return false; |
| 456 | 448 |
| 457 if (IsBuggyAthlon(cpu)) | 449 if (IsBuggyAthlon(cpu)) |
| 458 return false; | 450 return false; |
| 459 | 451 |
| 460 return true; | 452 return true; |
| 461 } | 453 } |
| 462 | 454 |
| 455 NowFunction GetNowFunction() { | |
| 456 if (!CPUReliablySupportsHighResTime()) | |
| 457 return RolloverProtectedNow; | |
| 458 return HighResNowWrapper; | |
| 459 } | |
| 460 | |
| 461 NowFunction now_function = GetNowFunction(); | |
|
willchan no longer on Chromium
2014/08/25 23:07:25
FYI: this results in a static initializer. This ma
M-A Ruel
2014/08/26 02:03:19
Furthermore, the static initializer is unneeded:
| |
| 462 | |
| 463 } // namespace | 463 } // namespace |
| 464 | 464 |
| 465 // static | 465 // static |
| 466 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 466 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
| 467 TickFunctionType ticker) { | 467 TickFunctionType ticker) { |
| 468 base::AutoLock locked(rollover_lock); | 468 base::AutoLock locked(rollover_lock); |
| 469 TickFunctionType old = tick_function; | 469 TickFunctionType old = tick_function; |
| 470 tick_function = ticker; | 470 tick_function = ticker; |
| 471 rollover_ms = 0; | 471 rollover_ms = 0; |
| 472 last_seen_now = 0; | 472 last_seen_now = 0; |
| 473 return old; | 473 return old; |
| 474 } | 474 } |
| 475 | 475 |
| 476 // static | 476 // static |
| 477 bool TimeTicks::SetNowIsHighResNowIfSupported() { | |
| 478 if (!CPUReliablySupportsHighResTime()) { | |
| 479 return false; | |
| 480 } | |
| 481 | |
| 482 now_function = HighResNowWrapper; | |
| 483 return true; | |
| 484 } | |
| 485 | |
| 486 // static | |
| 487 TimeTicks TimeTicks::Now() { | 477 TimeTicks TimeTicks::Now() { |
| 488 return TimeTicks() + now_function(); | 478 return TimeTicks() + now_function(); |
| 489 } | 479 } |
| 490 | 480 |
| 491 // static | 481 // static |
| 492 TimeTicks TimeTicks::HighResNow() { | 482 TimeTicks TimeTicks::HighResNow() { |
| 493 return TimeTicks() + HighResNowWrapper(); | 483 return TimeTicks() + HighResNowWrapper(); |
| 494 } | 484 } |
| 495 | 485 |
| 496 // static | 486 // static |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 531 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); | 521 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); |
| 532 } | 522 } |
| 533 } | 523 } |
| 534 | 524 |
| 535 // TimeDelta ------------------------------------------------------------------ | 525 // TimeDelta ------------------------------------------------------------------ |
| 536 | 526 |
| 537 // static | 527 // static |
| 538 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 539 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); | 529 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); |
| 540 } | 530 } |
| OLD | NEW |