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 24 matching lines...) Expand all Loading... |
35 // there is nothing else to waken the Wait. | 35 // there is nothing else to waken the Wait. |
36 | 36 |
37 #include "base/time/time.h" | 37 #include "base/time/time.h" |
38 | 38 |
39 #pragma comment(lib, "winmm.lib") | 39 #pragma comment(lib, "winmm.lib") |
40 #include <windows.h> | 40 #include <windows.h> |
41 #include <mmsystem.h> | 41 #include <mmsystem.h> |
42 | 42 |
43 #include "base/basictypes.h" | 43 #include "base/basictypes.h" |
44 #include "base/cpu.h" | 44 #include "base/cpu.h" |
| 45 #include "base/lazy_instance.h" |
45 #include "base/logging.h" | 46 #include "base/logging.h" |
46 #include "base/memory/singleton.h" | |
47 #include "base/synchronization/lock.h" | 47 #include "base/synchronization/lock.h" |
48 | 48 |
49 using base::Time; | 49 using base::Time; |
50 using base::TimeDelta; | 50 using base::TimeDelta; |
51 using base::TimeTicks; | 51 using base::TimeTicks; |
52 | 52 |
53 namespace { | 53 namespace { |
54 | 54 |
55 // From MSDN, FILETIME "Contains a 64-bit value representing the number of | 55 // From MSDN, FILETIME "Contains a 64-bit value representing the number of |
56 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 56 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 // give consistent result on a multiprocessor computer, but it is unreliable in | 351 // give consistent result on a multiprocessor computer, but it is unreliable in |
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 static HighResNowSingleton* GetInstance() { | 361 HighResNowSingleton() |
362 return Singleton<HighResNowSingleton>::get(); | 362 : ticks_per_second_(0), |
| 363 skew_(0) { |
| 364 InitializeClock(); |
| 365 |
| 366 base::CPU cpu; |
| 367 if (IsBuggyAthlon(cpu)) |
| 368 DisableHighResClock(); |
363 } | 369 } |
364 | 370 |
365 bool IsUsingHighResClock() { | 371 bool IsUsingHighResClock() { |
366 return ticks_per_second_ != 0.0; | 372 return ticks_per_second_ != 0.0; |
367 } | 373 } |
368 | 374 |
369 void DisableHighResClock() { | 375 void DisableHighResClock() { |
370 ticks_per_second_ = 0.0; | 376 ticks_per_second_ = 0.0; |
371 } | 377 } |
372 | 378 |
(...skipping 19 matching lines...) Expand all Loading... |
392 // overflow and precision issues. Think twice before simplifying! | 398 // overflow and precision issues. Think twice before simplifying! |
393 int64 whole_seconds = qpc_value / ticks_per_second_; | 399 int64 whole_seconds = qpc_value / ticks_per_second_; |
394 int64 leftover_ticks = qpc_value % ticks_per_second_; | 400 int64 leftover_ticks = qpc_value % ticks_per_second_; |
395 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + | 401 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + |
396 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 402 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
397 ticks_per_second_); | 403 ticks_per_second_); |
398 return microseconds; | 404 return microseconds; |
399 } | 405 } |
400 | 406 |
401 private: | 407 private: |
402 HighResNowSingleton() | |
403 : ticks_per_second_(0), | |
404 skew_(0) { | |
405 InitializeClock(); | |
406 | |
407 base::CPU cpu; | |
408 if (IsBuggyAthlon(cpu)) | |
409 DisableHighResClock(); | |
410 } | |
411 | |
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 |
419 skew_ = UnreliableNow() - ReliableNow(); | 415 skew_ = UnreliableNow() - ReliableNow(); |
420 } | 416 } |
421 | 417 |
422 // Get the number of microseconds since boot in an unreliable fashion. | 418 // Get the number of microseconds since boot in an unreliable fashion. |
423 int64 UnreliableNow() { | 419 int64 UnreliableNow() { |
424 LARGE_INTEGER now; | 420 LARGE_INTEGER now; |
425 QueryPerformanceCounter(&now); | 421 QueryPerformanceCounter(&now); |
426 return QPCValueToMicroseconds(now.QuadPart); | 422 return QPCValueToMicroseconds(now.QuadPart); |
427 } | 423 } |
428 | 424 |
429 // Get the number of microseconds since boot in a reliable fashion. | 425 // Get the number of microseconds since boot in a reliable fashion. |
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 | |
437 friend struct DefaultSingletonTraits<HighResNowSingleton>; | |
438 }; | 432 }; |
439 | 433 |
| 434 static base::LazyInstance<HighResNowSingleton>::Leaky |
| 435 leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER; |
| 436 |
| 437 HighResNowSingleton* GetHighResNowSingleton() { |
| 438 return leaky_high_res_now_singleton.Pointer(); |
| 439 } |
| 440 |
440 TimeDelta HighResNowWrapper() { | 441 TimeDelta HighResNowWrapper() { |
441 return HighResNowSingleton::GetInstance()->Now(); | 442 return GetHighResNowSingleton()->Now(); |
442 } | 443 } |
443 | 444 |
444 typedef TimeDelta (*NowFunction)(void); | 445 typedef TimeDelta (*NowFunction)(void); |
445 NowFunction now_function = RolloverProtectedNow; | 446 NowFunction now_function = RolloverProtectedNow; |
446 | 447 |
447 bool CPUReliablySupportsHighResTime() { | 448 bool CPUReliablySupportsHighResTime() { |
448 base::CPU cpu; | 449 base::CPU cpu; |
449 if (!cpu.has_non_stop_time_stamp_counter()) | 450 if (!cpu.has_non_stop_time_stamp_counter()) |
450 return false; | 451 return false; |
451 | 452 |
(...skipping 26 matching lines...) Expand all Loading... |
478 return true; | 479 return true; |
479 } | 480 } |
480 | 481 |
481 // static | 482 // static |
482 TimeTicks TimeTicks::Now() { | 483 TimeTicks TimeTicks::Now() { |
483 return TimeTicks() + now_function(); | 484 return TimeTicks() + now_function(); |
484 } | 485 } |
485 | 486 |
486 // static | 487 // static |
487 TimeTicks TimeTicks::HighResNow() { | 488 TimeTicks TimeTicks::HighResNow() { |
488 return TimeTicks() + HighResNowSingleton::GetInstance()->Now(); | 489 return TimeTicks() + HighResNowWrapper(); |
489 } | 490 } |
490 | 491 |
491 // static | 492 // static |
492 bool TimeTicks::IsHighResNowFastAndReliable() { | 493 bool TimeTicks::IsHighResNowFastAndReliable() { |
493 return CPUReliablySupportsHighResTime(); | 494 return CPUReliablySupportsHighResTime(); |
494 } | 495 } |
495 | 496 |
496 // static | 497 // static |
497 TimeTicks TimeTicks::ThreadNow() { | 498 TimeTicks TimeTicks::ThreadNow() { |
498 NOTREACHED(); | 499 NOTREACHED(); |
499 return TimeTicks(); | 500 return TimeTicks(); |
500 } | 501 } |
501 | 502 |
502 // static | 503 // static |
503 TimeTicks TimeTicks::NowFromSystemTraceTime() { | 504 TimeTicks TimeTicks::NowFromSystemTraceTime() { |
504 return HighResNow(); | 505 return HighResNow(); |
505 } | 506 } |
506 | 507 |
507 // static | 508 // static |
508 int64 TimeTicks::GetQPCDriftMicroseconds() { | 509 int64 TimeTicks::GetQPCDriftMicroseconds() { |
509 return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds(); | 510 return GetHighResNowSingleton()->GetQPCDriftMicroseconds(); |
510 } | 511 } |
511 | 512 |
512 // static | 513 // static |
513 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 514 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
514 return TimeTicks( | 515 return TimeTicks(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); |
515 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); | |
516 } | 516 } |
517 | 517 |
518 // static | 518 // static |
519 bool TimeTicks::IsHighResClockWorking() { | 519 bool TimeTicks::IsHighResClockWorking() { |
520 return HighResNowSingleton::GetInstance()->IsUsingHighResClock(); | 520 return GetHighResNowSingleton()->IsUsingHighResClock(); |
521 } | 521 } |
522 | 522 |
523 TimeTicks TimeTicks::UnprotectedNow() { | 523 TimeTicks TimeTicks::UnprotectedNow() { |
524 if (now_function == HighResNowWrapper) { | 524 if (now_function == HighResNowWrapper) { |
525 return Now(); | 525 return Now(); |
526 } else { | 526 } else { |
527 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); | 527 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); |
528 } | 528 } |
529 } | 529 } |
530 | 530 |
531 // TimeDelta ------------------------------------------------------------------ | 531 // TimeDelta ------------------------------------------------------------------ |
532 | 532 |
533 // static | 533 // static |
534 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 534 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
535 return TimeDelta( | 535 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); |
536 HighResNowSingleton::GetInstance()->QPCValueToMicroseconds(qpc_value)); | |
537 } | 536 } |
OLD | NEW |