| 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 18 matching lines...) Expand all Loading... |
| 29 // | 29 // |
| 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 #pragma comment(lib, "winmm.lib") | 36 #pragma comment(lib, "winmm.lib") |
| 37 #include <windows.h> | 37 #include <windows.h> |
| 38 #include <mmsystem.h> | 38 #include <mmsystem.h> |
| 39 #include <stdint.h> |
| 39 | 40 |
| 40 #include "base/basictypes.h" | 41 #include "base/basictypes.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 | 46 |
| 47 using base::ThreadTicks; |
| 46 using base::Time; | 48 using base::Time; |
| 47 using base::TimeDelta; | 49 using base::TimeDelta; |
| 48 using base::TimeTicks; | 50 using base::TimeTicks; |
| 51 using base::TraceTicks; |
| 49 | 52 |
| 50 namespace { | 53 namespace { |
| 51 | 54 |
| 52 // 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 |
| 53 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 56 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
| 54 int64 FileTimeToMicroseconds(const FILETIME& ft) { | 57 int64 FileTimeToMicroseconds(const FILETIME& ft) { |
| 55 // Need to bit_cast to fix alignment, then divide by 10 to convert | 58 // Need to bit_cast to fix alignment, then divide by 10 to convert |
| 56 // 100-nanoseconds to milliseconds. This only works on little-endian | 59 // 100-nanoseconds to milliseconds. This only works on little-endian |
| 57 // machines. | 60 // machines. |
| 58 return bit_cast<int64, FILETIME>(ft) / 10; | 61 return bit_cast<int64, FILETIME>(ft) / 10; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 | 102 |
| 100 } // namespace | 103 } // namespace |
| 101 | 104 |
| 102 // Time ----------------------------------------------------------------------- | 105 // Time ----------------------------------------------------------------------- |
| 103 | 106 |
| 104 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 | 107 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 |
| 105 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the | 108 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the |
| 106 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding | 109 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding |
| 107 // 1700, 1800, and 1900. | 110 // 1700, 1800, and 1900. |
| 108 // static | 111 // static |
| 109 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000); | 112 const int64 Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000); |
| 110 | 113 |
| 111 // static | 114 // static |
| 112 Time Time::Now() { | 115 Time Time::Now() { |
| 113 if (initial_time == 0) | 116 if (initial_time == 0) |
| 114 InitializeClock(); | 117 InitializeClock(); |
| 115 | 118 |
| 116 // We implement time using the high-resolution timers so that we can get | 119 // We implement time using the high-resolution timers so that we can get |
| 117 // timeouts which are smaller than 10-15ms. If we just used | 120 // timeouts which are smaller than 10-15ms. If we just used |
| 118 // CurrentWallclockMicroseconds(), we'd have the less-granular timer. | 121 // CurrentWallclockMicroseconds(), we'd have the less-granular timer. |
| 119 // | 122 // |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 // easy to use a Singleton without even knowing it, and that may lead to many | 324 // easy to use a Singleton without even knowing it, and that may lead to many |
| 322 // gotchas). Its impact on startup time should be negligible due to low-level | 325 // gotchas). Its impact on startup time should be negligible due to low-level |
| 323 // nature of time code. | 326 // nature of time code. |
| 324 base::Lock g_rollover_lock; | 327 base::Lock g_rollover_lock; |
| 325 | 328 |
| 326 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic | 329 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
| 327 // because it returns the number of milliseconds since Windows has started, | 330 // because it returns the number of milliseconds since Windows has started, |
| 328 // which will roll over the 32-bit value every ~49 days. We try to track | 331 // which will roll over the 32-bit value every ~49 days. We try to track |
| 329 // rollover ourselves, which works if TimeTicks::Now() is called at least every | 332 // rollover ourselves, which works if TimeTicks::Now() is called at least every |
| 330 // 49 days. | 333 // 49 days. |
| 331 TimeTicks RolloverProtectedNow() { | 334 TimeDelta RolloverProtectedNow() { |
| 332 base::AutoLock locked(g_rollover_lock); | 335 base::AutoLock locked(g_rollover_lock); |
| 333 // We should hold the lock while calling tick_function to make sure that | 336 // We should hold the lock while calling tick_function to make sure that |
| 334 // we keep last_seen_now stay correctly in sync. | 337 // we keep last_seen_now stay correctly in sync. |
| 335 DWORD now = g_tick_function(); | 338 DWORD now = g_tick_function(); |
| 336 if (now < g_last_seen_now) | 339 if (now < g_last_seen_now) |
| 337 g_rollover_ms += 0x100000000I64; // ~49.7 days. | 340 g_rollover_ms += 0x100000000I64; // ~49.7 days. |
| 338 g_last_seen_now = now; | 341 g_last_seen_now = now; |
| 339 return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms); | 342 return TimeDelta::FromMilliseconds(now + g_rollover_ms); |
| 340 } | 343 } |
| 341 | 344 |
| 342 // Discussion of tick counter options on Windows: | 345 // Discussion of tick counter options on Windows: |
| 343 // | 346 // |
| 344 // (1) CPU cycle counter. (Retrieved via RDTSC) | 347 // (1) CPU cycle counter. (Retrieved via RDTSC) |
| 345 // The CPU counter provides the highest resolution time stamp and is the least | 348 // The CPU counter provides the highest resolution time stamp and is the least |
| 346 // expensive to retrieve. However, on older CPUs, two issues can affect its | 349 // expensive to retrieve. However, on older CPUs, two issues can affect its |
| 347 // reliability: First it is maintained per processor and not synchronized | 350 // reliability: First it is maintained per processor and not synchronized |
| 348 // between processors. Also, the counters will change frequency due to thermal | 351 // between processors. Also, the counters will change frequency due to thermal |
| 349 // and power changes, and stop in some states. | 352 // and power changes, and stop in some states. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 367 // give consistent results on a multiprocessor computer, but for older CPUs it | 370 // give consistent results on a multiprocessor computer, but for older CPUs it |
| 368 // can be unreliable due bugs in BIOS or HAL. | 371 // can be unreliable due bugs in BIOS or HAL. |
| 369 // | 372 // |
| 370 // (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 | 373 // (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 |
| 371 // milliseconds) time stamp but is comparatively less expensive to retrieve and | 374 // milliseconds) time stamp but is comparatively less expensive to retrieve and |
| 372 // more reliable. Time::EnableHighResolutionTimer() and | 375 // more reliable. Time::EnableHighResolutionTimer() and |
| 373 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of | 376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of |
| 374 // this timer; and also other Windows applications can alter it, affecting this | 377 // this timer; and also other Windows applications can alter it, affecting this |
| 375 // one. | 378 // one. |
| 376 | 379 |
| 377 using NowFunction = TimeTicks (*)(void); | 380 using NowFunction = TimeDelta (*)(void); |
| 378 | 381 |
| 379 TimeTicks InitialNowFunction(); | 382 TimeDelta InitialNowFunction(); |
| 380 TimeTicks InitialSystemTraceNowFunction(); | 383 TimeDelta InitialSystemTraceNowFunction(); |
| 381 | 384 |
| 382 // See "threading notes" in InitializeNowFunctionPointers() for details on how | 385 // See "threading notes" in InitializeNowFunctionPointers() for details on how |
| 383 // concurrent reads/writes to these globals has been made safe. | 386 // concurrent reads/writes to these globals has been made safe. |
| 384 NowFunction g_now_function = &InitialNowFunction; | 387 NowFunction g_now_function = &InitialNowFunction; |
| 385 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; | 388 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; |
| 386 int64 g_qpc_ticks_per_second = 0; | 389 int64 g_qpc_ticks_per_second = 0; |
| 387 | 390 |
| 388 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is | 391 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is |
| 389 // what std::atomic_thread_fence does on Windows on all Intel architectures when | 392 // what std::atomic_thread_fence does on Windows on all Intel architectures when |
| 390 // the memory_order argument is anything but std::memory_order_seq_cst: | 393 // the memory_order argument is anything but std::memory_order_seq_cst: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 406 // Otherwise, calculate microseconds in a round about manner to avoid | 409 // Otherwise, calculate microseconds in a round about manner to avoid |
| 407 // overflow and precision issues. | 410 // overflow and precision issues. |
| 408 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; | 411 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; |
| 409 int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); | 412 int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); |
| 410 return TimeDelta::FromMicroseconds( | 413 return TimeDelta::FromMicroseconds( |
| 411 (whole_seconds * Time::kMicrosecondsPerSecond) + | 414 (whole_seconds * Time::kMicrosecondsPerSecond) + |
| 412 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 415 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
| 413 g_qpc_ticks_per_second)); | 416 g_qpc_ticks_per_second)); |
| 414 } | 417 } |
| 415 | 418 |
| 416 TimeTicks QPCNow() { | 419 TimeDelta QPCNow() { |
| 417 LARGE_INTEGER now; | 420 LARGE_INTEGER now; |
| 418 QueryPerformanceCounter(&now); | 421 QueryPerformanceCounter(&now); |
| 419 return TimeTicks() + QPCValueToTimeDelta(now.QuadPart); | 422 return QPCValueToTimeDelta(now.QuadPart); |
| 420 } | 423 } |
| 421 | 424 |
| 422 bool IsBuggyAthlon(const base::CPU& cpu) { | 425 bool IsBuggyAthlon(const base::CPU& cpu) { |
| 423 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | 426 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. |
| 424 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; | 427 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
| 425 } | 428 } |
| 426 | 429 |
| 427 void InitializeNowFunctionPointers() { | 430 void InitializeNowFunctionPointers() { |
| 428 LARGE_INTEGER ticks_per_sec = {0}; | 431 LARGE_INTEGER ticks_per_sec = {0}; |
| 429 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 432 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
| 430 ticks_per_sec.QuadPart = 0; | 433 ticks_per_sec.QuadPart = 0; |
| 431 | 434 |
| 432 // If Windows cannot provide a QPC implementation, both Now() and | 435 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and |
| 433 // NowFromSystemTraceTime() must use the low-resolution clock. | 436 // TraceTicks::Now() must use the low-resolution clock. |
| 434 // | 437 // |
| 435 // If the QPC implementation is expensive and/or unreliable, Now() will use | 438 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
| 436 // the low-resolution clock, but NowFromSystemTraceTime() will use the QPC (in | 439 // will use the low-resolution clock, but TraceTicks::Now() will use the QPC |
| 437 // the hope that it is still useful for tracing purposes). A CPU lacking a | 440 // (in the hope that it is still useful for tracing purposes). A CPU lacking a |
| 438 // non-stop time counter will cause Windows to provide an alternate QPC | 441 // non-stop time counter will cause Windows to provide an alternate QPC |
| 439 // implementation that works, but is expensive to use. Certain Athlon CPUs are | 442 // implementation that works, but is expensive to use. Certain Athlon CPUs are |
| 440 // known to make the QPC implementation unreliable. | 443 // known to make the QPC implementation unreliable. |
| 441 // | 444 // |
| 442 // Otherwise, both Now functions can use the high-resolution QPC clock. As of | 445 // Otherwise, both Now functions can use the high-resolution QPC clock. As of |
| 443 // 4 January 2015, ~68% of users fall within this category. | 446 // 4 January 2015, ~68% of users fall within this category. |
| 444 NowFunction now_function; | 447 NowFunction now_function; |
| 445 NowFunction system_trace_now_function; | 448 NowFunction system_trace_now_function; |
| 446 base::CPU cpu; | 449 base::CPU cpu; |
| 447 if (ticks_per_sec.QuadPart <= 0) { | 450 if (ticks_per_sec.QuadPart <= 0) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 461 // Threading note 2: A release fence is placed here to ensure, from the | 464 // Threading note 2: A release fence is placed here to ensure, from the |
| 462 // perspective of other threads using the function pointers, that the | 465 // perspective of other threads using the function pointers, that the |
| 463 // assignment to |g_qpc_ticks_per_second| happens before the function pointers | 466 // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
| 464 // are changed. | 467 // are changed. |
| 465 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 468 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
| 466 ATOMIC_THREAD_FENCE(memory_order_release); | 469 ATOMIC_THREAD_FENCE(memory_order_release); |
| 467 g_now_function = now_function; | 470 g_now_function = now_function; |
| 468 g_system_trace_now_function = system_trace_now_function; | 471 g_system_trace_now_function = system_trace_now_function; |
| 469 } | 472 } |
| 470 | 473 |
| 471 TimeTicks InitialNowFunction() { | 474 TimeDelta InitialNowFunction() { |
| 472 InitializeNowFunctionPointers(); | 475 InitializeNowFunctionPointers(); |
| 473 return g_now_function(); | 476 return g_now_function(); |
| 474 } | 477 } |
| 475 | 478 |
| 476 TimeTicks InitialSystemTraceNowFunction() { | 479 TimeDelta InitialSystemTraceNowFunction() { |
| 477 InitializeNowFunctionPointers(); | 480 InitializeNowFunctionPointers(); |
| 478 return g_system_trace_now_function(); | 481 return g_system_trace_now_function(); |
| 479 } | 482 } |
| 480 | 483 |
| 481 } // namespace | 484 } // namespace |
| 482 | 485 |
| 483 // static | 486 // static |
| 484 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 487 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
| 485 TickFunctionType ticker) { | 488 TickFunctionType ticker) { |
| 486 base::AutoLock locked(g_rollover_lock); | 489 base::AutoLock locked(g_rollover_lock); |
| 487 TickFunctionType old = g_tick_function; | 490 TickFunctionType old = g_tick_function; |
| 488 g_tick_function = ticker; | 491 g_tick_function = ticker; |
| 489 g_rollover_ms = 0; | 492 g_rollover_ms = 0; |
| 490 g_last_seen_now = 0; | 493 g_last_seen_now = 0; |
| 491 return old; | 494 return old; |
| 492 } | 495 } |
| 493 | 496 |
| 494 // static | 497 // static |
| 495 TimeTicks TimeTicks::Now() { | 498 TimeTicks TimeTicks::Now() { |
| 496 return g_now_function(); | 499 return TimeTicks() + g_now_function(); |
| 497 } | 500 } |
| 498 | 501 |
| 499 // static | 502 // static |
| 500 bool TimeTicks::IsHighResolution() { | 503 bool TimeTicks::IsHighResolution() { |
| 501 if (g_now_function == &InitialNowFunction) | 504 if (g_now_function == &InitialNowFunction) |
| 502 InitializeNowFunctionPointers(); | 505 InitializeNowFunctionPointers(); |
| 503 return g_now_function == &QPCNow; | 506 return g_now_function == &QPCNow; |
| 504 } | 507 } |
| 505 | 508 |
| 506 // static | 509 // static |
| 507 TimeTicks TimeTicks::ThreadNow() { | 510 ThreadTicks ThreadTicks::Now() { |
| 508 NOTREACHED(); | 511 NOTREACHED(); |
| 509 return TimeTicks(); | 512 return ThreadTicks(); |
| 510 } | 513 } |
| 511 | 514 |
| 512 // static | 515 // static |
| 513 TimeTicks TimeTicks::NowFromSystemTraceTime() { | 516 TraceTicks TraceTicks::Now() { |
| 514 return g_system_trace_now_function(); | 517 return TraceTicks() + g_system_trace_now_function(); |
| 515 } | 518 } |
| 516 | 519 |
| 517 // static | 520 // static |
| 518 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 521 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 519 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 522 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
| 520 } | 523 } |
| 521 | 524 |
| 522 // TimeDelta ------------------------------------------------------------------ | 525 // TimeDelta ------------------------------------------------------------------ |
| 523 | 526 |
| 524 // static | 527 // static |
| 525 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 526 return QPCValueToTimeDelta(qpc_value); | 529 return QPCValueToTimeDelta(qpc_value); |
| 527 } | 530 } |
| OLD | NEW |