Chromium Code Reviews| 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 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 // this timer; and also other Windows applications can alter it, affecting this | 396 // this timer; and also other Windows applications can alter it, affecting this |
| 397 // one. | 397 // one. |
| 398 | 398 |
| 399 using NowFunction = TimeDelta (*)(void); | 399 using NowFunction = TimeDelta (*)(void); |
| 400 | 400 |
| 401 TimeDelta InitialNowFunction(); | 401 TimeDelta InitialNowFunction(); |
| 402 | 402 |
| 403 // See "threading notes" in InitializeNowFunctionPointer() for details on how | 403 // See "threading notes" in InitializeNowFunctionPointer() for details on how |
| 404 // concurrent reads/writes to these globals has been made safe. | 404 // concurrent reads/writes to these globals has been made safe. |
| 405 NowFunction g_now_function = &InitialNowFunction; | 405 NowFunction g_now_function = &InitialNowFunction; |
| 406 TimeTicks::Clock g_now_clock = TimeTicks::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME; | |
| 407 | |
| 406 int64_t g_qpc_ticks_per_second = 0; | 408 int64_t g_qpc_ticks_per_second = 0; |
| 407 | 409 |
| 408 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is | 410 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is |
| 409 // what std::atomic_thread_fence does on Windows on all Intel architectures when | 411 // what std::atomic_thread_fence does on Windows on all Intel architectures when |
| 410 // the memory_order argument is anything but std::memory_order_seq_cst: | 412 // the memory_order argument is anything but std::memory_order_seq_cst: |
| 411 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); | 413 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); |
| 412 | 414 |
| 413 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { | 415 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { |
| 414 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in | 416 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in |
| 415 // InitializeNowFunctionPointer(), has happened by this point. | 417 // InitializeNowFunctionPointer(), has happened by this point. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 452 // | 454 // |
| 453 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() | 455 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
| 454 // will still use the low-resolution clock. A CPU lacking a non-stop time | 456 // will still use the low-resolution clock. A CPU lacking a non-stop time |
| 455 // counter will cause Windows to provide an alternate QPC implementation that | 457 // counter will cause Windows to provide an alternate QPC implementation that |
| 456 // works, but is expensive to use. Certain Athlon CPUs are known to make the | 458 // works, but is expensive to use. Certain Athlon CPUs are known to make the |
| 457 // QPC implementation unreliable. | 459 // QPC implementation unreliable. |
| 458 // | 460 // |
| 459 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, | 461 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, |
| 460 // ~72% of users fall within this category. | 462 // ~72% of users fall within this category. |
| 461 NowFunction now_function; | 463 NowFunction now_function; |
| 464 const char* now_clock; | |
| 462 base::CPU cpu; | 465 base::CPU cpu; |
| 463 if (ticks_per_sec.QuadPart <= 0 || | 466 if (ticks_per_sec.QuadPart <= 0 || |
| 464 !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { | 467 !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { |
| 465 now_function = &RolloverProtectedNow; | 468 now_function = &RolloverProtectedNow; |
| 469 now_clock = Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME; | |
| 466 } else { | 470 } else { |
| 467 now_function = &QPCNow; | 471 now_function = &QPCNow; |
| 472 now_clock = Clock::WIN_QPC; | |
| 468 } | 473 } |
| 469 | 474 |
| 470 // Threading note 1: In an unlikely race condition, it's possible for two or | 475 // Threading note 1: In an unlikely race condition, it's possible for two or |
| 471 // more threads to enter InitializeNowFunctionPointer() in parallel. This is | 476 // more threads to enter InitializeNowFunctionPointer() in parallel. This is |
| 472 // not a problem since all threads should end up writing out the same values | 477 // not a problem since all threads should end up writing out the same values |
| 473 // to the global variables. | 478 // to the global variables. |
| 474 // | 479 // |
| 475 // Threading note 2: A release fence is placed here to ensure, from the | 480 // Threading note 2: A release fence is placed here to ensure, from the |
| 476 // perspective of other threads using the function pointers, that the | 481 // perspective of other threads using the function pointers, that the |
| 477 // assignment to |g_qpc_ticks_per_second| happens before the function pointers | 482 // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
| 478 // are changed. | 483 // are changed. |
| 484 g_now_clock = now_clock; | |
| 479 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 485 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
| 480 ATOMIC_THREAD_FENCE(memory_order_release); | 486 ATOMIC_THREAD_FENCE(memory_order_release); |
| 481 g_now_function = now_function; | 487 g_now_function = now_function; |
| 482 } | 488 } |
| 483 | 489 |
| 484 TimeDelta InitialNowFunction() { | 490 TimeDelta InitialNowFunction() { |
| 485 InitializeNowFunctionPointer(); | 491 InitializeNowFunctionPointer(); |
| 486 return g_now_function(); | 492 return g_now_function(); |
| 487 } | 493 } |
| 488 | 494 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 505 } | 511 } |
| 506 | 512 |
| 507 // static | 513 // static |
| 508 bool TimeTicks::IsHighResolution() { | 514 bool TimeTicks::IsHighResolution() { |
| 509 if (g_now_function == &InitialNowFunction) | 515 if (g_now_function == &InitialNowFunction) |
| 510 InitializeNowFunctionPointer(); | 516 InitializeNowFunctionPointer(); |
| 511 return g_now_function == &QPCNow; | 517 return g_now_function == &QPCNow; |
| 512 } | 518 } |
| 513 | 519 |
| 514 // static | 520 // static |
| 521 TimeTicks::Clock TimeTicks::GetClock() { | |
|
fmeawad
2016/03/30 20:25:19
nit: I might be confused, but why not something li
danakj
2016/03/30 20:26:29
Oh, that's pretty nice yah.
charliea (OOO until 10-5)
2016/03/31 15:38:38
Agreed. That's a much nicer way of doing this. Don
| |
| 522 if (g_now_function == &InitialNowFunction) | |
| 523 InitializeNowFunctionPointer(); | |
| 524 return g_now_clock; | |
| 525 } | |
| 526 | |
| 527 // static | |
| 515 ThreadTicks ThreadTicks::Now() { | 528 ThreadTicks ThreadTicks::Now() { |
| 516 DCHECK(IsSupported()); | 529 DCHECK(IsSupported()); |
| 517 | 530 |
| 518 // Get the number of TSC ticks used by the current thread. | 531 // Get the number of TSC ticks used by the current thread. |
| 519 ULONG64 thread_cycle_time = 0; | 532 ULONG64 thread_cycle_time = 0; |
| 520 GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time); | 533 GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time); |
| 521 | 534 |
| 522 // Get the frequency of the TSC. | 535 // Get the frequency of the TSC. |
| 523 double tsc_ticks_per_second = TSCTicksPerSecond(); | 536 double tsc_ticks_per_second = TSCTicksPerSecond(); |
| 524 if (tsc_ticks_per_second == 0) | 537 if (tsc_ticks_per_second == 0) |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 607 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 620 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 608 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 621 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
| 609 } | 622 } |
| 610 | 623 |
| 611 // TimeDelta ------------------------------------------------------------------ | 624 // TimeDelta ------------------------------------------------------------------ |
| 612 | 625 |
| 613 // static | 626 // static |
| 614 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 627 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 615 return QPCValueToTimeDelta(qpc_value); | 628 return QPCValueToTimeDelta(qpc_value); |
| 616 } | 629 } |
| OLD | NEW |