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 |