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 19 matching lines...) Expand all Loading... |
30 // To work around all this, we're going to generally use timeGetTime(). We | 30 // To work around all this, we're going to generally use timeGetTime(). We |
31 // will only increase the system-wide timer if we're not running on battery | 31 // will only increase the system-wide timer if we're not running on battery |
32 // power. | 32 // power. |
33 | 33 |
34 #include "base/time/time.h" | 34 #include "base/time/time.h" |
35 | 35 |
36 #include <windows.h> | 36 #include <windows.h> |
37 #include <mmsystem.h> | 37 #include <mmsystem.h> |
38 #include <stdint.h> | 38 #include <stdint.h> |
39 | 39 |
| 40 #include "base/atomicops.h" |
40 #include "base/bit_cast.h" | 41 #include "base/bit_cast.h" |
41 #include "base/cpu.h" | 42 #include "base/cpu.h" |
42 #include "base/lazy_instance.h" | 43 #include "base/lazy_instance.h" |
43 #include "base/logging.h" | 44 #include "base/logging.h" |
44 #include "base/synchronization/lock.h" | 45 #include "base/synchronization/lock.h" |
45 #include "base/threading/platform_thread.h" | 46 #include "base/threading/platform_thread.h" |
46 | 47 |
47 using base::ThreadTicks; | 48 using base::ThreadTicks; |
48 using base::Time; | 49 using base::Time; |
49 using base::TimeDelta; | 50 using base::TimeDelta; |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 | 317 |
317 // We define a wrapper to adapt between the __stdcall and __cdecl call of the | 318 // We define a wrapper to adapt between the __stdcall and __cdecl call of the |
318 // mock function, and to avoid a static constructor. Assigning an import to a | 319 // mock function, and to avoid a static constructor. Assigning an import to a |
319 // function pointer directly would require setup code to fetch from the IAT. | 320 // function pointer directly would require setup code to fetch from the IAT. |
320 DWORD timeGetTimeWrapper() { | 321 DWORD timeGetTimeWrapper() { |
321 return timeGetTime(); | 322 return timeGetTime(); |
322 } | 323 } |
323 | 324 |
324 DWORD (*g_tick_function)(void) = &timeGetTimeWrapper; | 325 DWORD (*g_tick_function)(void) = &timeGetTimeWrapper; |
325 | 326 |
326 // Accumulation of time lost due to rollover (in milliseconds). | 327 // A structure holding the most significant bits of "last seen" and a |
327 int64_t g_rollover_ms = 0; | 328 // "rollover" counter. |
| 329 union LastTimeAndRolloversState { |
| 330 // The state as a single 32-bit opaque value. |
| 331 base::subtle::Atomic32 as_opaque_32; |
328 | 332 |
329 // The last timeGetTime value we saw, to detect rollover. | 333 // The state as usable values. |
330 DWORD g_last_seen_now = 0; | 334 struct { |
331 | 335 // The top 8-bits of the "last" time. This is enough to check for rollovers |
332 // Lock protecting rollover_ms and last_seen_now. | 336 // and the small bit-size means fewer CompareAndSwap operations to store |
333 // Note: this is a global object, and we usually avoid these. However, the time | 337 // changes in state, which in turn makes for fewer retries. |
334 // code is low-level, and we don't want to use Singletons here (it would be too | 338 uint8_t last_8; |
335 // easy to use a Singleton without even knowing it, and that may lead to many | 339 // A count of the number of detected rollovers. Using this as bits 47-32 |
336 // gotchas). Its impact on startup time should be negligible due to low-level | 340 // of the upper half of a 64-bit value results in a 48-bit tick counter. |
337 // nature of time code. | 341 // This extends the total rollover period from about 49 days to about 8800 |
338 base::Lock g_rollover_lock; | 342 // years while still allowing it to be stored with last_8 in a single |
| 343 // 32-bit value. |
| 344 uint16_t rollovers; |
| 345 } as_values; |
| 346 }; |
| 347 base::subtle::Atomic32 g_last_time_and_rollovers = 0; |
| 348 static_assert( |
| 349 sizeof(LastTimeAndRolloversState) <= sizeof(g_last_time_and_rollovers), |
| 350 "LastTimeAndRolloversState does not fit in a single atomic word"); |
339 | 351 |
340 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic | 352 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
341 // because it returns the number of milliseconds since Windows has started, | 353 // because it returns the number of milliseconds since Windows has started, |
342 // which will roll over the 32-bit value every ~49 days. We try to track | 354 // which will roll over the 32-bit value every ~49 days. We try to track |
343 // rollover ourselves, which works if TimeTicks::Now() is called at least every | 355 // rollover ourselves, which works if TimeTicks::Now() is called at least every |
344 // 49 days. | 356 // 48.8 days (not 49 days because only changes in the top 8 bits get noticed). |
345 TimeDelta RolloverProtectedNow() { | 357 TimeDelta RolloverProtectedNow() { |
346 base::AutoLock locked(g_rollover_lock); | 358 LastTimeAndRolloversState state; |
347 // We should hold the lock while calling tick_function to make sure that | 359 DWORD now; // DWORD is always unsigned 32 bits. |
348 // we keep last_seen_now stay correctly in sync. | 360 |
349 DWORD now = g_tick_function(); | 361 while (true) { |
350 if (now < g_last_seen_now) | 362 // Fetch the "now" and "last" tick values, updating "last" with "now" and |
351 g_rollover_ms += 0x100000000I64; // ~49.7 days. | 363 // incrementing the "rollovers" counter if the tick-value has wrapped back |
352 g_last_seen_now = now; | 364 // around. Atomic operations ensure that both "last" and "rollovers" are |
353 return TimeDelta::FromMilliseconds(now + g_rollover_ms); | 365 // always updated together. |
| 366 int32_t original = base::subtle::Acquire_Load(&g_last_time_and_rollovers); |
| 367 state.as_opaque_32 = original; |
| 368 now = g_tick_function(); |
| 369 uint8_t now_8 = static_cast<uint8_t>(now >> 24); |
| 370 if (now_8 < state.as_values.last_8) |
| 371 ++state.as_values.rollovers; |
| 372 state.as_values.last_8 = now_8; |
| 373 |
| 374 // If the state hasn't changed, exit the loop. |
| 375 if (state.as_opaque_32 == original) |
| 376 break; |
| 377 |
| 378 // Save the changed state. If the existing value is unchanged from the |
| 379 // original, exit the loop. |
| 380 int32_t check = base::subtle::Release_CompareAndSwap( |
| 381 &g_last_time_and_rollovers, original, state.as_opaque_32); |
| 382 if (check == original) |
| 383 break; |
| 384 |
| 385 // Another thread has done something in between so retry from the top. |
| 386 } |
| 387 |
| 388 return TimeDelta::FromMilliseconds( |
| 389 now + (static_cast<uint64_t>(state.as_values.rollovers) << 32)); |
354 } | 390 } |
355 | 391 |
356 // Discussion of tick counter options on Windows: | 392 // Discussion of tick counter options on Windows: |
357 // | 393 // |
358 // (1) CPU cycle counter. (Retrieved via RDTSC) | 394 // (1) CPU cycle counter. (Retrieved via RDTSC) |
359 // The CPU counter provides the highest resolution time stamp and is the least | 395 // The CPU counter provides the highest resolution time stamp and is the least |
360 // expensive to retrieve. However, on older CPUs, two issues can affect its | 396 // expensive to retrieve. However, on older CPUs, two issues can affect its |
361 // reliability: First it is maintained per processor and not synchronized | 397 // reliability: First it is maintained per processor and not synchronized |
362 // between processors. Also, the counters will change frequency due to thermal | 398 // between processors. Also, the counters will change frequency due to thermal |
363 // and power changes, and stop in some states. | 399 // and power changes, and stop in some states. |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 TimeDelta InitialNowFunction() { | 512 TimeDelta InitialNowFunction() { |
477 InitializeNowFunctionPointer(); | 513 InitializeNowFunctionPointer(); |
478 return g_now_function(); | 514 return g_now_function(); |
479 } | 515 } |
480 | 516 |
481 } // namespace | 517 } // namespace |
482 | 518 |
483 // static | 519 // static |
484 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 520 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
485 TickFunctionType ticker) { | 521 TickFunctionType ticker) { |
486 base::AutoLock locked(g_rollover_lock); | |
487 TickFunctionType old = g_tick_function; | 522 TickFunctionType old = g_tick_function; |
488 g_tick_function = ticker; | 523 g_tick_function = ticker; |
489 g_rollover_ms = 0; | 524 base::subtle::NoBarrier_Store(&g_last_time_and_rollovers, 0); |
490 g_last_seen_now = 0; | |
491 return old; | 525 return old; |
492 } | 526 } |
493 | 527 |
494 // static | 528 // static |
495 TimeTicks TimeTicks::Now() { | 529 TimeTicks TimeTicks::Now() { |
496 return TimeTicks() + g_now_function(); | 530 return TimeTicks() + g_now_function(); |
497 } | 531 } |
498 | 532 |
499 // static | 533 // static |
500 bool TimeTicks::IsHighResolution() { | 534 bool TimeTicks::IsHighResolution() { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 664 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
631 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 665 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
632 } | 666 } |
633 | 667 |
634 // TimeDelta ------------------------------------------------------------------ | 668 // TimeDelta ------------------------------------------------------------------ |
635 | 669 |
636 // static | 670 // static |
637 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 671 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
638 return QPCValueToTimeDelta(qpc_value); | 672 return QPCValueToTimeDelta(qpc_value); |
639 } | 673 } |
OLD | NEW |