| 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 25 matching lines...) Expand all Loading... |
| 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 | 39 |
| 40 #include "base/basictypes.h" | 40 #include "base/basictypes.h" |
| 41 #include "base/cpu.h" | 41 #include "base/cpu.h" |
| 42 #include "base/lazy_instance.h" | 42 #include "base/lazy_instance.h" |
| 43 #include "base/logging.h" | 43 #include "base/logging.h" |
| 44 #include "base/synchronization/lock.h" | 44 #include "base/synchronization/lock.h" |
| 45 | 45 |
| 46 using base::ThreadTicks; |
| 46 using base::Time; | 47 using base::Time; |
| 47 using base::TimeDelta; | 48 using base::TimeDelta; |
| 48 using base::TimeTicks; | 49 using base::TimeTicks; |
| 50 using base::TraceTicks; |
| 49 | 51 |
| 50 namespace { | 52 namespace { |
| 51 | 53 |
| 52 // From MSDN, FILETIME "Contains a 64-bit value representing the number of | 54 // From MSDN, FILETIME "Contains a 64-bit value representing the number of |
| 53 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 55 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
| 54 int64 FileTimeToMicroseconds(const FILETIME& ft) { | 56 int64 FileTimeToMicroseconds(const FILETIME& ft) { |
| 55 // Need to bit_cast to fix alignment, then divide by 10 to convert | 57 // Need to bit_cast to fix alignment, then divide by 10 to convert |
| 56 // 100-nanoseconds to milliseconds. This only works on little-endian | 58 // 100-nanoseconds to milliseconds. This only works on little-endian |
| 57 // machines. | 59 // machines. |
| 58 return bit_cast<int64, FILETIME>(ft) / 10; | 60 return bit_cast<int64, FILETIME>(ft) / 10; |
| (...skipping 262 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 | 323 // 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 | 324 // gotchas). Its impact on startup time should be negligible due to low-level |
| 323 // nature of time code. | 325 // nature of time code. |
| 324 base::Lock g_rollover_lock; | 326 base::Lock g_rollover_lock; |
| 325 | 327 |
| 326 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic | 328 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
| 327 // because it returns the number of milliseconds since Windows has started, | 329 // 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 | 330 // 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 | 331 // rollover ourselves, which works if TimeTicks::Now() is called at least every |
| 330 // 49 days. | 332 // 49 days. |
| 331 TimeTicks RolloverProtectedNow() { | 333 TimeDelta RolloverProtectedNow() { |
| 332 base::AutoLock locked(g_rollover_lock); | 334 base::AutoLock locked(g_rollover_lock); |
| 333 // We should hold the lock while calling tick_function to make sure that | 335 // We should hold the lock while calling tick_function to make sure that |
| 334 // we keep last_seen_now stay correctly in sync. | 336 // we keep last_seen_now stay correctly in sync. |
| 335 DWORD now = g_tick_function(); | 337 DWORD now = g_tick_function(); |
| 336 if (now < g_last_seen_now) | 338 if (now < g_last_seen_now) |
| 337 g_rollover_ms += 0x100000000I64; // ~49.7 days. | 339 g_rollover_ms += 0x100000000I64; // ~49.7 days. |
| 338 g_last_seen_now = now; | 340 g_last_seen_now = now; |
| 339 return TimeTicks() + TimeDelta::FromMilliseconds(now + g_rollover_ms); | 341 return TimeDelta::FromMilliseconds(now + g_rollover_ms); |
| 340 } | 342 } |
| 341 | 343 |
| 342 // Discussion of tick counter options on Windows: | 344 // Discussion of tick counter options on Windows: |
| 343 // | 345 // |
| 344 // (1) CPU cycle counter. (Retrieved via RDTSC) | 346 // (1) CPU cycle counter. (Retrieved via RDTSC) |
| 345 // The CPU counter provides the highest resolution time stamp and is the least | 347 // 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 | 348 // expensive to retrieve. However, on older CPUs, two issues can affect its |
| 347 // reliability: First it is maintained per processor and not synchronized | 349 // reliability: First it is maintained per processor and not synchronized |
| 348 // between processors. Also, the counters will change frequency due to thermal | 350 // between processors. Also, the counters will change frequency due to thermal |
| 349 // and power changes, and stop in some states. | 351 // 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 | 369 // give consistent results on a multiprocessor computer, but for older CPUs it |
| 368 // can be unreliable due bugs in BIOS or HAL. | 370 // can be unreliable due bugs in BIOS or HAL. |
| 369 // | 371 // |
| 370 // (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 | 372 // (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 | 373 // milliseconds) time stamp but is comparatively less expensive to retrieve and |
| 372 // more reliable. Time::EnableHighResolutionTimer() and | 374 // more reliable. Time::EnableHighResolutionTimer() and |
| 373 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of | 375 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of |
| 374 // this timer; and also other Windows applications can alter it, affecting this | 376 // this timer; and also other Windows applications can alter it, affecting this |
| 375 // one. | 377 // one. |
| 376 | 378 |
| 377 using NowFunction = TimeTicks (*)(void); | 379 using NowFunction = TimeDelta (*)(void); |
| 378 | 380 |
| 379 TimeTicks InitialNowFunction(); | 381 TimeDelta InitialNowFunction(); |
| 380 TimeTicks InitialSystemTraceNowFunction(); | 382 TimeDelta InitialSystemTraceNowFunction(); |
| 381 | 383 |
| 382 // See "threading notes" in InitializeNowFunctionPointers() for details on how | 384 // See "threading notes" in InitializeNowFunctionPointers() for details on how |
| 383 // concurrent reads/writes to these globals has been made safe. | 385 // concurrent reads/writes to these globals has been made safe. |
| 384 NowFunction g_now_function = &InitialNowFunction; | 386 NowFunction g_now_function = &InitialNowFunction; |
| 385 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; | 387 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; |
| 386 int64 g_qpc_ticks_per_second = 0; | 388 int64 g_qpc_ticks_per_second = 0; |
| 387 | 389 |
| 388 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is | 390 // 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 | 391 // 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: | 392 // 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 | 408 // Otherwise, calculate microseconds in a round about manner to avoid |
| 407 // overflow and precision issues. | 409 // overflow and precision issues. |
| 408 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; | 410 int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; |
| 409 int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); | 411 int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); |
| 410 return TimeDelta::FromMicroseconds( | 412 return TimeDelta::FromMicroseconds( |
| 411 (whole_seconds * Time::kMicrosecondsPerSecond) + | 413 (whole_seconds * Time::kMicrosecondsPerSecond) + |
| 412 ((leftover_ticks * Time::kMicrosecondsPerSecond) / | 414 ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
| 413 g_qpc_ticks_per_second)); | 415 g_qpc_ticks_per_second)); |
| 414 } | 416 } |
| 415 | 417 |
| 416 TimeTicks QPCNow() { | 418 TimeDelta QPCNow() { |
| 417 LARGE_INTEGER now; | 419 LARGE_INTEGER now; |
| 418 QueryPerformanceCounter(&now); | 420 QueryPerformanceCounter(&now); |
| 419 return TimeTicks() + QPCValueToTimeDelta(now.QuadPart); | 421 return QPCValueToTimeDelta(now.QuadPart); |
| 420 } | 422 } |
| 421 | 423 |
| 422 bool IsBuggyAthlon(const base::CPU& cpu) { | 424 bool IsBuggyAthlon(const base::CPU& cpu) { |
| 423 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | 425 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. |
| 424 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; | 426 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
| 425 } | 427 } |
| 426 | 428 |
| 427 void InitializeNowFunctionPointers() { | 429 void InitializeNowFunctionPointers() { |
| 428 LARGE_INTEGER ticks_per_sec = {0}; | 430 LARGE_INTEGER ticks_per_sec = {0}; |
| 429 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 431 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
| 430 ticks_per_sec.QuadPart = 0; | 432 ticks_per_sec.QuadPart = 0; |
| 431 | 433 |
| 432 // If Windows cannot provide a QPC implementation, both Now() and | 434 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and |
| 433 // NowFromSystemTraceTime() must use the low-resolution clock. | 435 // TraceTicks::Now() must use the low-resolution clock. |
| 434 // | 436 // |
| 435 // If the QPC implementation is expensive and/or unreliable, Now() will use | 437 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
| 436 // the low-resolution clock, but NowFromSystemTraceTime() will use the QPC (in | 438 // 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 | 439 // (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 | 440 // 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 | 441 // implementation that works, but is expensive to use. Certain Athlon CPUs are |
| 440 // known to make the QPC implementation unreliable. | 442 // known to make the QPC implementation unreliable. |
| 441 // | 443 // |
| 442 // Otherwise, both Now functions can use the high-resolution QPC clock. As of | 444 // Otherwise, both Now functions can use the high-resolution QPC clock. As of |
| 443 // 4 January 2015, ~68% of users fall within this category. | 445 // 4 January 2015, ~68% of users fall within this category. |
| 444 NowFunction now_function; | 446 NowFunction now_function; |
| 445 NowFunction system_trace_now_function; | 447 NowFunction system_trace_now_function; |
| 446 base::CPU cpu; | 448 base::CPU cpu; |
| 447 if (ticks_per_sec.QuadPart <= 0) { | 449 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 | 463 // Threading note 2: A release fence is placed here to ensure, from the |
| 462 // perspective of other threads using the function pointers, that the | 464 // perspective of other threads using the function pointers, that the |
| 463 // assignment to |g_qpc_ticks_per_second| happens before the function pointers | 465 // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
| 464 // are changed. | 466 // are changed. |
| 465 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 467 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
| 466 ATOMIC_THREAD_FENCE(memory_order_release); | 468 ATOMIC_THREAD_FENCE(memory_order_release); |
| 467 g_now_function = now_function; | 469 g_now_function = now_function; |
| 468 g_system_trace_now_function = system_trace_now_function; | 470 g_system_trace_now_function = system_trace_now_function; |
| 469 } | 471 } |
| 470 | 472 |
| 471 TimeTicks InitialNowFunction() { | 473 TimeDelta InitialNowFunction() { |
| 472 InitializeNowFunctionPointers(); | 474 InitializeNowFunctionPointers(); |
| 473 return g_now_function(); | 475 return g_now_function(); |
| 474 } | 476 } |
| 475 | 477 |
| 476 TimeTicks InitialSystemTraceNowFunction() { | 478 TimeDelta InitialSystemTraceNowFunction() { |
| 477 InitializeNowFunctionPointers(); | 479 InitializeNowFunctionPointers(); |
| 478 return g_system_trace_now_function(); | 480 return g_system_trace_now_function(); |
| 479 } | 481 } |
| 480 | 482 |
| 481 } // namespace | 483 } // namespace |
| 482 | 484 |
| 483 // static | 485 // static |
| 484 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 486 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
| 485 TickFunctionType ticker) { | 487 TickFunctionType ticker) { |
| 486 base::AutoLock locked(g_rollover_lock); | 488 base::AutoLock locked(g_rollover_lock); |
| 487 TickFunctionType old = g_tick_function; | 489 TickFunctionType old = g_tick_function; |
| 488 g_tick_function = ticker; | 490 g_tick_function = ticker; |
| 489 g_rollover_ms = 0; | 491 g_rollover_ms = 0; |
| 490 g_last_seen_now = 0; | 492 g_last_seen_now = 0; |
| 491 return old; | 493 return old; |
| 492 } | 494 } |
| 493 | 495 |
| 494 // static | 496 // static |
| 495 TimeTicks TimeTicks::Now() { | 497 TimeTicks TimeTicks::Now() { |
| 496 return g_now_function(); | 498 return TimeTicks() + g_now_function(); |
| 497 } | 499 } |
| 498 | 500 |
| 499 // static | 501 // static |
| 500 bool TimeTicks::IsHighResolution() { | 502 bool TimeTicks::IsHighResolution() { |
| 501 if (g_now_function == &InitialNowFunction) | 503 if (g_now_function == &InitialNowFunction) |
| 502 InitializeNowFunctionPointers(); | 504 InitializeNowFunctionPointers(); |
| 503 return g_now_function == &QPCNow; | 505 return g_now_function == &QPCNow; |
| 504 } | 506 } |
| 505 | 507 |
| 506 // static | 508 // static |
| 507 TimeTicks TimeTicks::ThreadNow() { | 509 ThreadTicks ThreadTicks::Now() { |
| 508 NOTREACHED(); | 510 NOTREACHED(); |
| 509 return TimeTicks(); | 511 return ThreadTicks(); |
| 510 } | 512 } |
| 511 | 513 |
| 512 // static | 514 // static |
| 513 TimeTicks TimeTicks::NowFromSystemTraceTime() { | 515 TraceTicks TraceTicks::Now() { |
| 514 return g_system_trace_now_function(); | 516 return TraceTicks() + g_system_trace_now_function(); |
| 515 } | 517 } |
| 516 | 518 |
| 517 // static | 519 // static |
| 518 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 520 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 519 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 521 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
| 520 } | 522 } |
| 521 | 523 |
| 522 // TimeDelta ------------------------------------------------------------------ | 524 // TimeDelta ------------------------------------------------------------------ |
| 523 | 525 |
| 524 // static | 526 // static |
| 525 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 527 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 526 return QPCValueToTimeDelta(qpc_value); | 528 return QPCValueToTimeDelta(qpc_value); |
| 527 } | 529 } |
| OLD | NEW |