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