| 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 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 base::AutoLock locked(rollover_lock); | 315 base::AutoLock locked(rollover_lock); |
| 316 // We should hold the lock while calling tick_function to make sure that | 316 // We should hold the lock while calling tick_function to make sure that |
| 317 // we keep last_seen_now stay correctly in sync. | 317 // we keep last_seen_now stay correctly in sync. |
| 318 DWORD now = tick_function(); | 318 DWORD now = tick_function(); |
| 319 if (now < last_seen_now) | 319 if (now < last_seen_now) |
| 320 rollover_ms += 0x100000000I64; // ~49.7 days. | 320 rollover_ms += 0x100000000I64; // ~49.7 days. |
| 321 last_seen_now = now; | 321 last_seen_now = now; |
| 322 return TimeDelta::FromMilliseconds(now + rollover_ms); | 322 return TimeDelta::FromMilliseconds(now + rollover_ms); |
| 323 } | 323 } |
| 324 | 324 |
| 325 bool IsBuggyAthlon(const base::CPU& cpu) { |
| 326 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is |
| 327 // unreliable. Fallback to low-res clock. |
| 328 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
| 329 } |
| 330 |
| 325 // Overview of time counters: | 331 // Overview of time counters: |
| 326 // (1) CPU cycle counter. (Retrieved via RDTSC) | 332 // (1) CPU cycle counter. (Retrieved via RDTSC) |
| 327 // The CPU counter provides the highest resolution time stamp and is the least | 333 // The CPU counter provides the highest resolution time stamp and is the least |
| 328 // expensive to retrieve. However, the CPU counter is unreliable and should not | 334 // expensive to retrieve. However, the CPU counter is unreliable and should not |
| 329 // be used in production. Its biggest issue is that it is per processor and it | 335 // be used in production. Its biggest issue is that it is per processor and it |
| 330 // is not synchronized between processors. Also, on some computers, the counters | 336 // is not synchronized between processors. Also, on some computers, the counters |
| 331 // will change frequency due to thermal and power changes, and stop in some | 337 // will change frequency due to thermal and power changes, and stop in some |
| 332 // states. | 338 // states. |
| 333 // | 339 // |
| 334 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- | 340 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 ticks_per_second_); | 397 ticks_per_second_); |
| 392 return microseconds; | 398 return microseconds; |
| 393 } | 399 } |
| 394 | 400 |
| 395 private: | 401 private: |
| 396 HighResNowSingleton() | 402 HighResNowSingleton() |
| 397 : ticks_per_second_(0), | 403 : ticks_per_second_(0), |
| 398 skew_(0) { | 404 skew_(0) { |
| 399 InitializeClock(); | 405 InitializeClock(); |
| 400 | 406 |
| 401 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is | |
| 402 // unreliable. Fallback to low-res clock. | |
| 403 base::CPU cpu; | 407 base::CPU cpu; |
| 404 if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) | 408 if (IsBuggyAthlon(cpu)) |
| 405 DisableHighResClock(); | 409 DisableHighResClock(); |
| 406 } | 410 } |
| 407 | 411 |
| 408 // Synchronize the QPC clock with GetSystemTimeAsFileTime. | 412 // Synchronize the QPC clock with GetSystemTimeAsFileTime. |
| 409 void InitializeClock() { | 413 void InitializeClock() { |
| 410 LARGE_INTEGER ticks_per_sec = {0}; | 414 LARGE_INTEGER ticks_per_sec = {0}; |
| 411 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 415 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
| 412 return; // Broken, we don't guarantee this function works. | 416 return; // Broken, we don't guarantee this function works. |
| 413 ticks_per_second_ = ticks_per_sec.QuadPart; | 417 ticks_per_second_ = ticks_per_sec.QuadPart; |
| 414 | 418 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 426 int64 ReliableNow() { | 430 int64 ReliableNow() { |
| 427 return RolloverProtectedNow().InMicroseconds(); | 431 return RolloverProtectedNow().InMicroseconds(); |
| 428 } | 432 } |
| 429 | 433 |
| 430 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. | 434 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. |
| 431 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). | 435 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). |
| 432 | 436 |
| 433 friend struct DefaultSingletonTraits<HighResNowSingleton>; | 437 friend struct DefaultSingletonTraits<HighResNowSingleton>; |
| 434 }; | 438 }; |
| 435 | 439 |
| 440 TimeDelta HighResNowWrapper() { |
| 441 return HighResNowSingleton::GetInstance()->Now(); |
| 442 } |
| 443 |
| 444 typedef TimeDelta (*NowFunction)(void); |
| 445 NowFunction now_function = RolloverProtectedNow; |
| 446 |
| 447 bool CPUReliablySupportsHighResTime() { |
| 448 base::CPU cpu; |
| 449 if (!cpu.has_non_stop_time_stamp_counter()) |
| 450 return false; |
| 451 |
| 452 if (IsBuggyAthlon(cpu)) |
| 453 return false; |
| 454 |
| 455 return true; |
| 456 } |
| 457 |
| 436 } // namespace | 458 } // namespace |
| 437 | 459 |
| 438 // static | 460 // static |
| 439 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 461 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
| 440 TickFunctionType ticker) { | 462 TickFunctionType ticker) { |
| 441 base::AutoLock locked(rollover_lock); | 463 base::AutoLock locked(rollover_lock); |
| 442 TickFunctionType old = tick_function; | 464 TickFunctionType old = tick_function; |
| 443 tick_function = ticker; | 465 tick_function = ticker; |
| 444 rollover_ms = 0; | 466 rollover_ms = 0; |
| 445 last_seen_now = 0; | 467 last_seen_now = 0; |
| 446 return old; | 468 return old; |
| 447 } | 469 } |
| 448 | 470 |
| 449 // static | 471 // static |
| 472 bool TimeTicks::SetNowIsHighResNowIfSupported() { |
| 473 if (!CPUReliablySupportsHighResTime()) { |
| 474 return false; |
| 475 } |
| 476 |
| 477 now_function = HighResNowWrapper; |
| 478 return true; |
| 479 } |
| 480 |
| 481 // static |
| 450 TimeTicks TimeTicks::Now() { | 482 TimeTicks TimeTicks::Now() { |
| 451 return TimeTicks() + RolloverProtectedNow(); | 483 return TimeTicks() + now_function(); |
| 452 } | 484 } |
| 453 | 485 |
| 454 // static | 486 // static |
| 455 TimeTicks TimeTicks::HighResNow() { | 487 TimeTicks TimeTicks::HighResNow() { |
| 456 return TimeTicks() + HighResNowSingleton::GetInstance()->Now(); | 488 return TimeTicks() + HighResNowSingleton::GetInstance()->Now(); |
| 457 } | 489 } |
| 458 | 490 |
| 459 // static | 491 // static |
| 460 TimeTicks TimeTicks::ThreadNow() { | 492 TimeTicks TimeTicks::ThreadNow() { |
| 461 NOTREACHED(); | 493 NOTREACHED(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 476 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 508 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 477 return TimeTicks( | 509 return TimeTicks( |
| 478 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); | 510 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); |
| 479 } | 511 } |
| 480 | 512 |
| 481 // static | 513 // static |
| 482 bool TimeTicks::IsHighResClockWorking() { | 514 bool TimeTicks::IsHighResClockWorking() { |
| 483 return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); | 515 return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); |
| 484 } | 516 } |
| 485 | 517 |
| 518 TimeTicks TimeTicks::UnprotectedNow() { |
| 519 if (now_function == HighResNowWrapper) { |
| 520 return Now(); |
| 521 } else { |
| 522 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); |
| 523 } |
| 524 } |
| 525 |
| 486 // TimeDelta ------------------------------------------------------------------ | 526 // TimeDelta ------------------------------------------------------------------ |
| 487 | 527 |
| 488 // static | 528 // static |
| 489 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 529 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 490 return TimeDelta( | 530 return TimeDelta( |
| 491 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); | 531 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); |
| 492 } | 532 } |
| OLD | NEW |