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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
72 | 72 |
73 int64 CurrentWallclockMicroseconds() { | 73 int64 CurrentWallclockMicroseconds() { |
74 FILETIME ft; | 74 FILETIME ft; |
75 ::GetSystemTimeAsFileTime(&ft); | 75 ::GetSystemTimeAsFileTime(&ft); |
76 return FileTimeToMicroseconds(ft); | 76 return FileTimeToMicroseconds(ft); |
77 } | 77 } |
78 | 78 |
79 // Time between resampling the un-granular clock for this API. 60 seconds. | 79 // Time between resampling the un-granular clock for this API. 60 seconds. |
80 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; | 80 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; |
81 | 81 |
82 base::Lock initialize_clock_lock; | |
jar (doing other things)
2014/08/15 17:40:39
nit: We're not allowed to have such items at globa
fmeawad
2014/08/15 21:50:50
I copied the lock from rollover_lock in the same f
| |
82 int64 initial_time = 0; | 83 int64 initial_time = 0; |
83 TimeTicks initial_ticks; | 84 TimeTicks initial_ticks; |
84 | 85 |
85 void InitializeClock() { | 86 void InitializeClock() { |
87 base::AutoLock locked(initialize_clock_lock); | |
86 initial_ticks = TimeTicks::Now(); | 88 initial_ticks = TimeTicks::Now(); |
87 initial_time = CurrentWallclockMicroseconds(); | 89 initial_time = CurrentWallclockMicroseconds(); |
88 } | 90 } |
89 | 91 |
90 } // namespace | 92 } // namespace |
91 | 93 |
92 // Time ----------------------------------------------------------------------- | 94 // Time ----------------------------------------------------------------------- |
93 | 95 |
94 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 | 96 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 |
95 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the | 97 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the |
(...skipping 16 matching lines...) Expand all Loading... | |
112 // | 114 // |
113 // To make this work, we initialize the clock (initial_time) and the | 115 // To make this work, we initialize the clock (initial_time) and the |
114 // counter (initial_ctr). To compute the initial time, we can check | 116 // counter (initial_ctr). To compute the initial time, we can check |
115 // the number of ticks that have elapsed, and compute the delta. | 117 // the number of ticks that have elapsed, and compute the delta. |
116 // | 118 // |
117 // To avoid any drift, we periodically resync the counters to the system | 119 // To avoid any drift, we periodically resync the counters to the system |
118 // clock. | 120 // clock. |
119 while (true) { | 121 while (true) { |
120 TimeTicks ticks = TimeTicks::Now(); | 122 TimeTicks ticks = TimeTicks::Now(); |
121 | 123 |
124 int64 start_time = 0; | |
125 TimeTicks start_ticks; | |
126 { | |
127 base::AutoLock locked(initialize_clock_lock); | |
128 start_time = initial_time; | |
129 start_ticks = initial_ticks; | |
130 } | |
131 | |
122 // Calculate the time elapsed since we started our timer | 132 // Calculate the time elapsed since we started our timer |
123 TimeDelta elapsed = ticks - initial_ticks; | 133 TimeDelta elapsed = ticks - start_ticks; |
124 | 134 |
125 // Check if enough time has elapsed that we need to resync the clock. | 135 // Check if enough time has elapsed that we need to resync the clock. |
126 if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) { | 136 if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) { |
127 InitializeClock(); | 137 InitializeClock(); |
128 continue; | 138 continue; |
129 } | 139 } |
130 | 140 |
131 return Time(elapsed + Time(initial_time)); | 141 return Time(elapsed + Time(start_time)); |
132 } | 142 } |
133 } | 143 } |
134 | 144 |
135 // static | 145 // static |
136 Time Time::NowFromSystemTime() { | 146 Time Time::NowFromSystemTime() { |
137 // Force resync. | 147 // Force resync. |
138 InitializeClock(); | 148 InitializeClock(); |
139 return Time(initial_time); | 149 return Time(initial_time); |
140 } | 150 } |
141 | 151 |
(...skipping 210 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. | 362 // 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 | 363 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but |
354 // it should be used with caution. | 364 // it should be used with caution. |
355 // | 365 // |
356 // (3) System time. The system time provides a low-resolution (typically 10ms | 366 // (3) System time. The system time provides a low-resolution (typically 10ms |
357 // to 55 milliseconds) time stamp but is comparatively less expensive to | 367 // to 55 milliseconds) time stamp but is comparatively less expensive to |
358 // retrieve and more reliable. | 368 // retrieve and more reliable. |
359 class HighResNowSingleton { | 369 class HighResNowSingleton { |
360 public: | 370 public: |
361 HighResNowSingleton() | 371 HighResNowSingleton() |
362 : ticks_per_second_(0), | 372 : ticks_per_second_(0), |
363 skew_(0) { | 373 skew_(0) { |
364 InitializeClock(); | |
365 | 374 |
366 base::CPU cpu; | 375 base::CPU cpu; |
367 if (IsBuggyAthlon(cpu)) | 376 if (IsBuggyAthlon(cpu)) |
368 DisableHighResClock(); | 377 return; |
378 | |
379 // Synchronize the QPC clock with GetSystemTimeAsFileTime. | |
380 LARGE_INTEGER ticks_per_sec = {0}; | |
381 if (!QueryPerformanceFrequency(&ticks_per_sec)) | |
382 return; // QPC is not available. | |
383 ticks_per_second_ = ticks_per_sec.QuadPart; | |
384 | |
385 skew_ = UnreliableNow() - ReliableNow(); | |
369 } | 386 } |
370 | 387 |
371 bool IsUsingHighResClock() { | 388 bool IsUsingHighResClock() { |
372 return ticks_per_second_ != 0.0; | 389 return ticks_per_second_ != 0; |
373 } | |
374 | |
375 void DisableHighResClock() { | |
376 ticks_per_second_ = 0.0; | |
377 } | 390 } |
378 | 391 |
379 TimeDelta Now() { | 392 TimeDelta Now() { |
380 if (IsUsingHighResClock()) | 393 if (IsUsingHighResClock()) |
381 return TimeDelta::FromMicroseconds(UnreliableNow()); | 394 return TimeDelta::FromMicroseconds(UnreliableNow()); |
382 | 395 |
383 // Just fallback to the slower clock. | 396 // Just fallback to the slower clock. |
384 return RolloverProtectedNow(); | 397 return RolloverProtectedNow(); |
385 } | 398 } |
386 | 399 |
(...skipping 14 matching lines...) Expand all Loading... | |
401 // overflow and precision issues. | 414 // overflow and precision issues. |
402 int64 whole_seconds = qpc_value / ticks_per_second_; | 415 int64 whole_seconds = qpc_value / ticks_per_second_; |
403 int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_); | 416 int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_); |
404 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + | 417 int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) + |
405 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 418 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
406 ticks_per_second_); | 419 ticks_per_second_); |
407 return microseconds; | 420 return microseconds; |
408 } | 421 } |
409 | 422 |
410 private: | 423 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 | |
421 // Get the number of microseconds since boot in an unreliable fashion. | 424 // Get the number of microseconds since boot in an unreliable fashion. |
422 int64 UnreliableNow() { | 425 int64 UnreliableNow() { |
423 LARGE_INTEGER now; | 426 LARGE_INTEGER now; |
424 QueryPerformanceCounter(&now); | 427 QueryPerformanceCounter(&now); |
425 return QPCValueToMicroseconds(now.QuadPart); | 428 return QPCValueToMicroseconds(now.QuadPart); |
426 } | 429 } |
427 | 430 |
428 // Get the number of microseconds since boot in a reliable fashion. | 431 // Get the number of microseconds since boot in a reliable fashion. |
429 int64 ReliableNow() { | 432 int64 ReliableNow() { |
430 return RolloverProtectedNow().InMicroseconds(); | 433 return RolloverProtectedNow().InMicroseconds(); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
473 return old; | 476 return old; |
474 } | 477 } |
475 | 478 |
476 // static | 479 // static |
477 bool TimeTicks::SetNowIsHighResNowIfSupported() { | 480 bool TimeTicks::SetNowIsHighResNowIfSupported() { |
478 if (!CPUReliablySupportsHighResTime()) { | 481 if (!CPUReliablySupportsHighResTime()) { |
479 return false; | 482 return false; |
480 } | 483 } |
481 | 484 |
482 now_function = HighResNowWrapper; | 485 now_function = HighResNowWrapper; |
486 InitializeClock(); | |
483 return true; | 487 return true; |
484 } | 488 } |
485 | 489 |
486 // static | 490 // static |
487 TimeTicks TimeTicks::Now() { | 491 TimeTicks TimeTicks::Now() { |
488 return TimeTicks() + now_function(); | 492 return TimeTicks() + now_function(); |
489 } | 493 } |
490 | 494 |
491 // static | 495 // static |
492 TimeTicks TimeTicks::HighResNow() { | 496 TimeTicks TimeTicks::HighResNow() { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); | 535 return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime()); |
532 } | 536 } |
533 } | 537 } |
534 | 538 |
535 // TimeDelta ------------------------------------------------------------------ | 539 // TimeDelta ------------------------------------------------------------------ |
536 | 540 |
537 // static | 541 // static |
538 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 542 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
539 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); | 543 return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value)); |
540 } | 544 } |
OLD | NEW |