| 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 |