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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; | 79 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; |
80 | 80 |
81 int64_t initial_time = 0; | 81 int64_t initial_time = 0; |
82 TimeTicks initial_ticks; | 82 TimeTicks initial_ticks; |
83 | 83 |
84 void InitializeClock() { | 84 void InitializeClock() { |
85 initial_ticks = TimeTicks::Now(); | 85 initial_ticks = TimeTicks::Now(); |
86 initial_time = CurrentWallclockMicroseconds(); | 86 initial_time = CurrentWallclockMicroseconds(); |
87 } | 87 } |
88 | 88 |
89 const char* kTimeGetTimeClockId = "WIN_ROLLOVER_PROTECTED_TIME_GET_TIME_MICROS"; | |
90 const char* kQPCClockId = "WIN_QPC_MICROS"; | |
91 | |
89 // The two values that ActivateHighResolutionTimer uses to set the systemwide | 92 // The two values that ActivateHighResolutionTimer uses to set the systemwide |
90 // timer interrupt frequency on Windows. It controls how precise timers are | 93 // timer interrupt frequency on Windows. It controls how precise timers are |
91 // but also has a big impact on battery life. | 94 // but also has a big impact on battery life. |
92 const int kMinTimerIntervalHighResMs = 1; | 95 const int kMinTimerIntervalHighResMs = 1; |
93 const int kMinTimerIntervalLowResMs = 4; | 96 const int kMinTimerIntervalLowResMs = 4; |
94 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. | 97 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. |
95 bool g_high_res_timer_enabled = false; | 98 bool g_high_res_timer_enabled = false; |
96 // How many times the high resolution timer has been called. | 99 // How many times the high resolution timer has been called. |
97 uint32_t g_high_res_timer_count = 0; | 100 uint32_t g_high_res_timer_count = 0; |
98 // The lock to control access to the above two variables. | 101 // The lock to control access to the above two variables. |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
396 // this timer; and also other Windows applications can alter it, affecting this | 399 // this timer; and also other Windows applications can alter it, affecting this |
397 // one. | 400 // one. |
398 | 401 |
399 using NowFunction = TimeDelta (*)(void); | 402 using NowFunction = TimeDelta (*)(void); |
400 | 403 |
401 TimeDelta InitialNowFunction(); | 404 TimeDelta InitialNowFunction(); |
402 | 405 |
403 // See "threading notes" in InitializeNowFunctionPointer() for details on how | 406 // See "threading notes" in InitializeNowFunctionPointer() for details on how |
404 // concurrent reads/writes to these globals has been made safe. | 407 // concurrent reads/writes to these globals has been made safe. |
405 NowFunction g_now_function = &InitialNowFunction; | 408 NowFunction g_now_function = &InitialNowFunction; |
409 const char* g_now_clock_id = ""; | |
410 | |
406 int64_t g_qpc_ticks_per_second = 0; | 411 int64_t g_qpc_ticks_per_second = 0; |
407 | 412 |
408 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is | 413 // 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 | 414 // 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: | 415 // the memory_order argument is anything but std::memory_order_seq_cst: |
411 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); | 416 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); |
412 | 417 |
413 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { | 418 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { |
414 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in | 419 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in |
415 // InitializeNowFunctionPointer(), has happened by this point. | 420 // InitializeNowFunctionPointer(), has happened by this point. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 // | 457 // |
453 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() | 458 // 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 | 459 // 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 | 460 // 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 | 461 // works, but is expensive to use. Certain Athlon CPUs are known to make the |
457 // QPC implementation unreliable. | 462 // QPC implementation unreliable. |
458 // | 463 // |
459 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, | 464 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015, |
460 // ~72% of users fall within this category. | 465 // ~72% of users fall within this category. |
461 NowFunction now_function; | 466 NowFunction now_function; |
467 const char* now_clock_id; | |
462 base::CPU cpu; | 468 base::CPU cpu; |
463 if (ticks_per_sec.QuadPart <= 0 || | 469 if (ticks_per_sec.QuadPart <= 0 || |
464 !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { | 470 !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { |
465 now_function = &RolloverProtectedNow; | 471 now_function = &RolloverProtectedNow; |
472 now_clock_id = kTimeGetTimeClockId; | |
466 } else { | 473 } else { |
467 now_function = &QPCNow; | 474 now_function = &QPCNow; |
475 now_clock_id = kQPCClockId; | |
468 } | 476 } |
469 | 477 |
470 // Threading note 1: In an unlikely race condition, it's possible for two or | 478 // Threading note 1: In an unlikely race condition, it's possible for two or |
471 // more threads to enter InitializeNowFunctionPointer() in parallel. This is | 479 // more threads to enter InitializeNowFunctionPointer() in parallel. This is |
472 // not a problem since all threads should end up writing out the same values | 480 // not a problem since all threads should end up writing out the same values |
473 // to the global variables. | 481 // to the global variables. |
474 // | 482 // |
475 // Threading note 2: A release fence is placed here to ensure, from the | 483 // Threading note 2: A release fence is placed here to ensure, from the |
476 // perspective of other threads using the function pointers, that the | 484 // perspective of other threads using the function pointers, that the |
477 // assignment to |g_qpc_ticks_per_second| happens before the function pointers | 485 // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
478 // are changed. | 486 // are changed. |
479 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; | 487 g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
480 ATOMIC_THREAD_FENCE(memory_order_release); | 488 ATOMIC_THREAD_FENCE(memory_order_release); |
481 g_now_function = now_function; | 489 g_now_function = now_function; |
490 g_now_clock_id = now_clock_id; | |
danakj
2016/03/26 00:40:33
Why is this after the fence?
charliea (OOO until 10-5)
2016/03/28 15:40:51
I'm not sure, but if the above comment is any indi
danakj
2016/03/28 17:53:50
Yeah, I stared at this for a while, and AFAICT the
charliea (OOO until 10-5)
2016/03/28 21:07:36
Done.
| |
482 } | 491 } |
483 | 492 |
484 TimeDelta InitialNowFunction() { | 493 TimeDelta InitialNowFunction() { |
485 InitializeNowFunctionPointer(); | 494 InitializeNowFunctionPointer(); |
486 return g_now_function(); | 495 return g_now_function(); |
487 } | 496 } |
488 | 497 |
489 } // namespace | 498 } // namespace |
490 | 499 |
491 // static | 500 // static |
(...skipping 13 matching lines...) Expand all Loading... | |
505 } | 514 } |
506 | 515 |
507 // static | 516 // static |
508 bool TimeTicks::IsHighResolution() { | 517 bool TimeTicks::IsHighResolution() { |
509 if (g_now_function == &InitialNowFunction) | 518 if (g_now_function == &InitialNowFunction) |
510 InitializeNowFunctionPointer(); | 519 InitializeNowFunctionPointer(); |
511 return g_now_function == &QPCNow; | 520 return g_now_function == &QPCNow; |
512 } | 521 } |
513 | 522 |
514 // static | 523 // static |
524 std::string TimeTicks::ClockId() { | |
525 if (g_now_function == &InitialNowFunction) | |
526 InitializeNowFunctionPointer(); | |
527 return g_now_clock_id; | |
528 } | |
529 | |
530 // static | |
515 ThreadTicks ThreadTicks::Now() { | 531 ThreadTicks ThreadTicks::Now() { |
516 DCHECK(IsSupported()); | 532 DCHECK(IsSupported()); |
517 | 533 |
518 // Get the number of TSC ticks used by the current thread. | 534 // Get the number of TSC ticks used by the current thread. |
519 ULONG64 thread_cycle_time = 0; | 535 ULONG64 thread_cycle_time = 0; |
520 GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time); | 536 GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time); |
521 | 537 |
522 // Get the frequency of the TSC. | 538 // Get the frequency of the TSC. |
523 double tsc_ticks_per_second = TSCTicksPerSecond(); | 539 double tsc_ticks_per_second = TSCTicksPerSecond(); |
524 if (tsc_ticks_per_second == 0) | 540 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) { | 623 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
608 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 624 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
609 } | 625 } |
610 | 626 |
611 // TimeDelta ------------------------------------------------------------------ | 627 // TimeDelta ------------------------------------------------------------------ |
612 | 628 |
613 // static | 629 // static |
614 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 630 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
615 return QPCValueToTimeDelta(qpc_value); | 631 return QPCValueToTimeDelta(qpc_value); |
616 } | 632 } |
OLD | NEW |