| 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 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 // (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 |
| 374 // milliseconds) time stamp but is comparatively less expensive to retrieve and | 374 // milliseconds) time stamp but is comparatively less expensive to retrieve and |
| 375 // more reliable. Time::EnableHighResolutionTimer() and | 375 // more reliable. Time::EnableHighResolutionTimer() and |
| 376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of | 376 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of |
| 377 // 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 |
| 378 // one. | 378 // one. |
| 379 | 379 |
| 380 using NowFunction = TimeDelta (*)(void); | 380 using NowFunction = TimeDelta (*)(void); |
| 381 | 381 |
| 382 TimeDelta InitialNowFunction(); | 382 TimeDelta InitialNowFunction(); |
| 383 TimeDelta InitialSystemTraceNowFunction(); | |
| 384 | 383 |
| 385 // See "threading notes" in InitializeNowFunctionPointers() for details on how | 384 // See "threading notes" in InitializeNowFunctionPointer() for details on how |
| 386 // concurrent reads/writes to these globals has been made safe. | 385 // concurrent reads/writes to these globals has been made safe. |
| 387 NowFunction g_now_function = &InitialNowFunction; | 386 NowFunction g_now_function = &InitialNowFunction; |
| 388 NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; | |
| 389 int64 g_qpc_ticks_per_second = 0; | 387 int64 g_qpc_ticks_per_second = 0; |
| 390 | 388 |
| 391 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is | 389 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is |
| 392 // what std::atomic_thread_fence does on Windows on all Intel architectures when | 390 // what std::atomic_thread_fence does on Windows on all Intel architectures when |
| 393 // the memory_order argument is anything but std::memory_order_seq_cst: | 391 // the memory_order argument is anything but std::memory_order_seq_cst: |
| 394 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); | 392 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); |
| 395 | 393 |
| 396 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { | 394 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { |
| 397 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in | 395 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in |
| 398 // InitializeNowFunctionPointers(), has happened by this point. | 396 // InitializeNowFunctionPointer(), has happened by this point. |
| 399 ATOMIC_THREAD_FENCE(memory_order_acquire); | 397 ATOMIC_THREAD_FENCE(memory_order_acquire); |
| 400 | 398 |
| 401 DCHECK_GT(g_qpc_ticks_per_second, 0); | 399 DCHECK_GT(g_qpc_ticks_per_second, 0); |
| 402 | 400 |
| 403 // If the QPC Value is below the overflow threshold, we proceed with | 401 // If the QPC Value is below the overflow threshold, we proceed with |
| 404 // simple multiply and divide. | 402 // simple multiply and divide. |
| 405 if (qpc_value < Time::kQPCOverflowThreshold) { | 403 if (qpc_value < Time::kQPCOverflowThreshold) { |
| 406 return TimeDelta::FromMicroseconds( | 404 return TimeDelta::FromMicroseconds( |
| 407 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second); | 405 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second); |
| 408 } | 406 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 420 LARGE_INTEGER now; | 418 LARGE_INTEGER now; |
| 421 QueryPerformanceCounter(&now); | 419 QueryPerformanceCounter(&now); |
| 422 return QPCValueToTimeDelta(now.QuadPart); | 420 return QPCValueToTimeDelta(now.QuadPart); |
| 423 } | 421 } |
| 424 | 422 |
| 425 bool IsBuggyAthlon(const base::CPU& cpu) { | 423 bool IsBuggyAthlon(const base::CPU& cpu) { |
| 426 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | 424 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. |
| 427 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; | 425 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
| 428 } | 426 } |
| 429 | 427 |
| 430 void InitializeNowFunctionPointers() { | 428 void InitializeNowFunctionPointer() { |
| 431 LARGE_INTEGER ticks_per_sec = {}; | 429 LARGE_INTEGER ticks_per_sec = {}; |
| 432 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 430 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
| 433 ticks_per_sec.QuadPart = 0; | 431 ticks_per_sec.QuadPart = 0; |
| 434 | 432 |
| 435 // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and | 433 // If Windows cannot provide a QPC implementation, TimeTicks::Now() must use |
| 436 // TraceTicks::Now() must use the low-resolution clock. | 434 // the low-resolution clock. |
| 437 // | 435 // |
| 438 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() | 436 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
| 439 // will use the low-resolution clock, but TraceTicks::Now() will use the QPC | 437 // will still use the low-resolution clock. A CPU lacking a non-stop time |
| 440 // (in the hope that it is still useful for tracing purposes). A CPU lacking a | 438 // counter will cause Windows to provide an alternate QPC implementation that |
| 441 // non-stop time counter will cause Windows to provide an alternate QPC | 439 // works, but is expensive to use. Certain Athlon CPUs are known to make the |
| 442 // implementation that works, but is expensive to use. Certain Athlon CPUs are | 440 // QPC implementation unreliable. |
| 443 // known to make the QPC implementation unreliable. | |
| 444 // | 441 // |
| 445 // Otherwise, both Now functions can use the high-resolution QPC clock. As of | 442 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, |
| 446 // 4 January 2015, ~68% of users fall within this category. | 443 // ~72% of users fall within this category. |
| 444 // |
| 445 // TraceTicks::Now() always uses the same clock as TimeTicks::Now(), even |
| 446 // when the QPC exists but is expensive or unreliable. This is because we'd |
| 447 // eventually like to merge TraceTicks and TimeTicks and have one type of |
| 448 // timestamp that is reliable, monotonic, and comparable. Also, while we could |
| 449 // use the high-resolution timer for TraceTicks even when it's unreliable or |
| 450 // slow, it's easier to make tracing tools accommodate a coarse timer than |
| 451 // one that's unreliable or slow. |
| 447 NowFunction now_function; | 452 NowFunction now_function; |
| 448 NowFunction system_trace_now_function; | |
| 449 base::CPU cpu; | 453 base::CPU cpu; |
| 450 if (ticks_per_sec.QuadPart <= 0) { | 454 if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter() || |
| 451 now_function = system_trace_now_function = &RolloverProtectedNow; | 455 IsBuggyAthlon(cpu)) { |
| 452 } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { | |
| 453 now_function = &RolloverProtectedNow; | 456 now_function = &RolloverProtectedNow; |
| 454 system_trace_now_function = &QPCNow; | |
| 455 } else { | 457 } else { |
| 456 now_function = system_trace_now_function = &QPCNow; | 458 now_function = &QPCNow; |
| 457 } | 459 } |
| 458 | 460 |
| 459 // Threading note 1: In an unlikely race condition, it's possible for two or | 461 // Threading note 1: In an unlikely race condition, it's possible for two or |
| 460 // more threads to enter InitializeNowFunctionPointers() in parallel. This is | 462 // more threads to enter InitializeNowFunctionPointer() in parallel. This is |
| 461 // not a problem since all threads should end up writing out the same values | 463 // not a problem since all threads should end up writing out the same values |
| 462 // to the global variables. | 464 // to the global variables. |
| 463 // | 465 // |
| 464 // Threading note 2: A release fence is placed here to ensure, from the | 466 // Threading note 2: A release fence is placed here to ensure, from the |
| 465 // perspective of other threads using the function pointers, that the | 467 // perspective of other threads using the function pointers, that the |
| 466 // assignment to |g_qpc_ticks_per_second| happens before the function pointers | 468 // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
| 467 // are changed. | 469 // are changed. |
| 468 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 470 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
| 469 ATOMIC_THREAD_FENCE(memory_order_release); | 471 ATOMIC_THREAD_FENCE(memory_order_release); |
| 470 g_now_function = now_function; | 472 g_now_function = now_function; |
| 471 g_system_trace_now_function = system_trace_now_function; | |
| 472 } | 473 } |
| 473 | 474 |
| 474 TimeDelta InitialNowFunction() { | 475 TimeDelta InitialNowFunction() { |
| 475 InitializeNowFunctionPointers(); | 476 InitializeNowFunctionPointer(); |
| 476 return g_now_function(); | 477 return g_now_function(); |
| 477 } | 478 } |
| 478 | 479 |
| 479 TimeDelta InitialSystemTraceNowFunction() { | |
| 480 InitializeNowFunctionPointers(); | |
| 481 return g_system_trace_now_function(); | |
| 482 } | |
| 483 | |
| 484 } // namespace | 480 } // namespace |
| 485 | 481 |
| 486 // static | 482 // static |
| 487 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 483 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
| 488 TickFunctionType ticker) { | 484 TickFunctionType ticker) { |
| 489 base::AutoLock locked(g_rollover_lock); | 485 base::AutoLock locked(g_rollover_lock); |
| 490 TickFunctionType old = g_tick_function; | 486 TickFunctionType old = g_tick_function; |
| 491 g_tick_function = ticker; | 487 g_tick_function = ticker; |
| 492 g_rollover_ms = 0; | 488 g_rollover_ms = 0; |
| 493 g_last_seen_now = 0; | 489 g_last_seen_now = 0; |
| 494 return old; | 490 return old; |
| 495 } | 491 } |
| 496 | 492 |
| 497 // static | 493 // static |
| 498 TimeTicks TimeTicks::Now() { | 494 TimeTicks TimeTicks::Now() { |
| 499 return TimeTicks() + g_now_function(); | 495 return TimeTicks() + g_now_function(); |
| 500 } | 496 } |
| 501 | 497 |
| 502 // static | 498 // static |
| 503 bool TimeTicks::IsHighResolution() { | 499 bool TimeTicks::IsHighResolution() { |
| 504 if (g_now_function == &InitialNowFunction) | 500 if (g_now_function == &InitialNowFunction) |
| 505 InitializeNowFunctionPointers(); | 501 InitializeNowFunctionPointer(); |
| 506 return g_now_function == &QPCNow; | 502 return g_now_function == &QPCNow; |
| 507 } | 503 } |
| 508 | 504 |
| 509 // static | 505 // static |
| 510 ThreadTicks ThreadTicks::Now() { | 506 ThreadTicks ThreadTicks::Now() { |
| 511 NOTREACHED(); | 507 NOTREACHED(); |
| 512 return ThreadTicks(); | 508 return ThreadTicks(); |
| 513 } | 509 } |
| 514 | 510 |
| 515 // static | 511 // static |
| 516 TraceTicks TraceTicks::Now() { | 512 TraceTicks TraceTicks::Now() { |
| 517 return TraceTicks() + g_system_trace_now_function(); | 513 return TraceTicks() + g_now_function(); |
| 518 } | 514 } |
| 519 | 515 |
| 520 // static | 516 // static |
| 521 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 517 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 522 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 518 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
| 523 } | 519 } |
| 524 | 520 |
| 525 // TimeDelta ------------------------------------------------------------------ | 521 // TimeDelta ------------------------------------------------------------------ |
| 526 | 522 |
| 527 // static | 523 // static |
| 528 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 524 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 529 return QPCValueToTimeDelta(qpc_value); | 525 return QPCValueToTimeDelta(qpc_value); |
| 530 } | 526 } |
| OLD | NEW |