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(); |
364 | 365 |
365 base::CPU cpu; | 366 base::CPU cpu; |
366 if (IsBuggyAthlon(cpu)) | 367 if (IsBuggyAthlon(cpu)) |
367 return; | 368 DisableHighResClock(); |
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(); | |
376 } | 369 } |
377 | 370 |
378 bool IsUsingHighResClock() { | 371 bool IsUsingHighResClock() { |
379 return ticks_per_second_ != 0; | 372 return ticks_per_second_ != 0.0; |
| 373 } |
| 374 |
| 375 void DisableHighResClock() { |
| 376 ticks_per_second_ = 0.0; |
380 } | 377 } |
381 | 378 |
382 TimeDelta Now() { | 379 TimeDelta Now() { |
383 if (IsUsingHighResClock()) | 380 if (IsUsingHighResClock()) |
384 return TimeDelta::FromMicroseconds(UnreliableNow()); | 381 return TimeDelta::FromMicroseconds(UnreliableNow()); |
385 | 382 |
386 // Just fallback to the slower clock. | 383 // Just fallback to the slower clock. |
387 return RolloverProtectedNow(); | 384 return RolloverProtectedNow(); |
388 } | 385 } |
389 | 386 |
(...skipping 14 matching lines...) Expand all Loading... |
404 // overflow and precision issues. | 401 // overflow and precision issues. |
405 int64 whole_seconds = qpc_value / ticks_per_second_; | 402 int64 whole_seconds = qpc_value / ticks_per_second_; |
406 int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_); | 403 int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_); |
407 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + | 404 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + |
408 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 405 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
409 ticks_per_second_); | 406 ticks_per_second_); |
410 return microseconds; | 407 return microseconds; |
411 } | 408 } |
412 | 409 |
413 private: | 410 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 |
414 // Get the number of microseconds since boot in an unreliable fashion. | 421 // Get the number of microseconds since boot in an unreliable fashion. |
415 int64 UnreliableNow() { | 422 int64 UnreliableNow() { |
416 LARGE_INTEGER now; | 423 LARGE_INTEGER now; |
417 QueryPerformanceCounter(&now); | 424 QueryPerformanceCounter(&now); |
418 return QPCValueToMicroseconds(now.QuadPart); | 425 return QPCValueToMicroseconds(now.QuadPart); |
419 } | 426 } |
420 | 427 |
421 // Get the number of microseconds since boot in a reliable fashion. | 428 // Get the number of microseconds since boot in a reliable fashion. |
422 int64 ReliableNow() { | 429 int64 ReliableNow() { |
423 return RolloverProtectedNow().InMicroseconds(); | 430 return RolloverProtectedNow().InMicroseconds(); |
424 } | 431 } |
425 | 432 |
426 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. | 433 int64 ticks_per_second_; // 0 indicates QPF failed and we're broken. |
427 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). | 434 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). |
428 }; | 435 }; |
429 | 436 |
430 static base::LazyInstance<HighResNowSingleton>::Leaky | 437 static base::LazyInstance<HighResNowSingleton>::Leaky |
431 leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER; | 438 leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER; |
432 | 439 |
433 HighResNowSingleton* GetHighResNowSingleton() { | 440 HighResNowSingleton* GetHighResNowSingleton() { |
434 return leaky_high_res_now_singleton.Pointer(); | 441 return leaky_high_res_now_singleton.Pointer(); |
435 } | 442 } |
436 | 443 |
437 TimeDelta HighResNowWrapper() { | 444 TimeDelta HighResNowWrapper() { |
438 return GetHighResNowSingleton()->Now(); | 445 return GetHighResNowSingleton()->Now(); |
439 } | 446 } |
440 | 447 |
441 typedef TimeDelta (*NowFunction)(void); | 448 typedef TimeDelta (*NowFunction)(void); |
| 449 NowFunction now_function = RolloverProtectedNow; |
442 | 450 |
443 bool CPUReliablySupportsHighResTime() { | 451 bool CPUReliablySupportsHighResTime() { |
444 base::CPU cpu; | 452 base::CPU cpu; |
445 if (!cpu.has_non_stop_time_stamp_counter() || | 453 if (!cpu.has_non_stop_time_stamp_counter() || |
446 !GetHighResNowSingleton()->IsUsingHighResClock()) | 454 !GetHighResNowSingleton()->IsUsingHighResClock()) |
447 return false; | 455 return false; |
448 | 456 |
449 if (IsBuggyAthlon(cpu)) | 457 if (IsBuggyAthlon(cpu)) |
450 return false; | 458 return false; |
451 | 459 |
452 return true; | 460 return true; |
453 } | 461 } |
454 | 462 |
455 NowFunction GetNowFunction() { | |
456 if (!CPUReliablySupportsHighResTime()) | |
457 return RolloverProtectedNow; | |
458 return HighResNowWrapper; | |
459 } | |
460 | |
461 NowFunction now_function = GetNowFunction(); | |
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 |
477 TimeTicks TimeTicks::Now() { | 487 TimeTicks TimeTicks::Now() { |
478 return TimeTicks() + now_function(); | 488 return TimeTicks() + now_function(); |
479 } | 489 } |
480 | 490 |
481 // static | 491 // static |
482 TimeTicks TimeTicks::HighResNow() { | 492 TimeTicks TimeTicks::HighResNow() { |
483 return TimeTicks() + HighResNowWrapper(); | 493 return TimeTicks() + HighResNowWrapper(); |
484 } | 494 } |
485 | 495 |
486 // static | 496 // static |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); | 531 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); |
522 } | 532 } |
523 } | 533 } |
524 | 534 |
525 // TimeDelta ------------------------------------------------------------------ | 535 // TimeDelta ------------------------------------------------------------------ |
526 | 536 |
527 // static | 537 // static |
528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 538 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
529 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); | 539 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); |
530 } | 540 } |
OLD | NEW |