| 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 24 matching lines...) Expand all Loading... |
| 35 | 35 |
| 36 #include <windows.h> | 36 #include <windows.h> |
| 37 #include <mmsystem.h> | 37 #include <mmsystem.h> |
| 38 #include <stdint.h> | 38 #include <stdint.h> |
| 39 | 39 |
| 40 #include "base/bit_cast.h" | 40 #include "base/bit_cast.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 #include "base/threading/platform_thread.h" |
| 45 | 46 |
| 46 using base::ThreadTicks; | 47 using base::ThreadTicks; |
| 47 using base::Time; | 48 using base::Time; |
| 48 using base::TimeDelta; | 49 using base::TimeDelta; |
| 49 using base::TimeTicks; | 50 using base::TimeTicks; |
| 50 | 51 |
| 51 namespace { | 52 namespace { |
| 52 | 53 |
| 53 // 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 |
| 54 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 55 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 const int kMinTimerIntervalHighResMs = 1; | 92 const int kMinTimerIntervalHighResMs = 1; |
| 92 const int kMinTimerIntervalLowResMs = 4; | 93 const int kMinTimerIntervalLowResMs = 4; |
| 93 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. | 94 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. |
| 94 bool g_high_res_timer_enabled = false; | 95 bool g_high_res_timer_enabled = false; |
| 95 // How many times the high resolution timer has been called. | 96 // How many times the high resolution timer has been called. |
| 96 uint32_t g_high_res_timer_count = 0; | 97 uint32_t g_high_res_timer_count = 0; |
| 97 // The lock to control access to the above two variables. | 98 // The lock to control access to the above two variables. |
| 98 base::LazyInstance<base::Lock>::Leaky g_high_res_lock = | 99 base::LazyInstance<base::Lock>::Leaky g_high_res_lock = |
| 99 LAZY_INSTANCE_INITIALIZER; | 100 LAZY_INSTANCE_INITIALIZER; |
| 100 | 101 |
| 101 // Returns a pointer to the QueryThreadCycleTime() function from Windows. | |
| 102 // Can't statically link to it because it is not available on XP. | |
| 103 using QueryThreadCycleTimePtr = decltype(::QueryThreadCycleTime)*; | |
| 104 QueryThreadCycleTimePtr GetQueryThreadCycleTimeFunction() { | |
| 105 static const QueryThreadCycleTimePtr query_thread_cycle_time_fn = | |
| 106 reinterpret_cast<QueryThreadCycleTimePtr>(::GetProcAddress( | |
| 107 ::GetModuleHandle(L"kernel32.dll"), "QueryThreadCycleTime")); | |
| 108 return query_thread_cycle_time_fn; | |
| 109 } | |
| 110 | |
| 111 // Returns the current value of the performance counter. | 102 // Returns the current value of the performance counter. |
| 112 uint64_t QPCNowRaw() { | 103 uint64_t QPCNowRaw() { |
| 113 LARGE_INTEGER perf_counter_now = {}; | 104 LARGE_INTEGER perf_counter_now = {}; |
| 114 // According to the MSDN documentation for QueryPerformanceCounter(), this | 105 // According to the MSDN documentation for QueryPerformanceCounter(), this |
| 115 // will never fail on systems that run XP or later. | 106 // will never fail on systems that run XP or later. |
| 116 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx | 107 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx |
| 117 ::QueryPerformanceCounter(&perf_counter_now); | 108 ::QueryPerformanceCounter(&perf_counter_now); |
| 118 return perf_counter_now.QuadPart; | 109 return perf_counter_now.QuadPart; |
| 119 } | 110 } |
| 120 | 111 |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 } | 502 } |
| 512 | 503 |
| 513 // static | 504 // static |
| 514 TimeTicks::Clock TimeTicks::GetClock() { | 505 TimeTicks::Clock TimeTicks::GetClock() { |
| 515 return IsHighResolution() ? | 506 return IsHighResolution() ? |
| 516 Clock::WIN_QPC : Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME; | 507 Clock::WIN_QPC : Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME; |
| 517 } | 508 } |
| 518 | 509 |
| 519 // static | 510 // static |
| 520 ThreadTicks ThreadTicks::Now() { | 511 ThreadTicks ThreadTicks::Now() { |
| 512 return ThreadTicks::GetForThread(PlatformThread::CurrentHandle()); |
| 513 } |
| 514 |
| 515 // static |
| 516 ThreadTicks ThreadTicks::GetForThread( |
| 517 const base::PlatformThreadHandle& thread_handle) { |
| 521 DCHECK(IsSupported()); | 518 DCHECK(IsSupported()); |
| 522 | 519 |
| 523 // Get the number of TSC ticks used by the current thread. | 520 // Get the number of TSC ticks used by the current thread. |
| 524 ULONG64 thread_cycle_time = 0; | 521 ULONG64 thread_cycle_time = 0; |
| 525 GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time); | 522 ::QueryThreadCycleTime(thread_handle.platform_handle(), &thread_cycle_time); |
| 526 | 523 |
| 527 // Get the frequency of the TSC. | 524 // Get the frequency of the TSC. |
| 528 double tsc_ticks_per_second = TSCTicksPerSecond(); | 525 double tsc_ticks_per_second = TSCTicksPerSecond(); |
| 529 if (tsc_ticks_per_second == 0) | 526 if (tsc_ticks_per_second == 0) |
| 530 return ThreadTicks(); | 527 return ThreadTicks(); |
| 531 | 528 |
| 532 // Return the CPU time of the current thread. | 529 // Return the CPU time of the current thread. |
| 533 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; | 530 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; |
| 534 return ThreadTicks( | 531 return ThreadTicks( |
| 535 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond)); | 532 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond)); |
| 536 } | 533 } |
| 537 | 534 |
| 538 // static | 535 // static |
| 539 bool ThreadTicks::IsSupportedWin() { | 536 bool ThreadTicks::IsSupportedWin() { |
| 540 static bool is_supported = GetQueryThreadCycleTimeFunction() && | 537 static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() && |
| 541 base::CPU().has_non_stop_time_stamp_counter() && | |
| 542 !IsBuggyAthlon(base::CPU()); | 538 !IsBuggyAthlon(base::CPU()); |
| 543 return is_supported; | 539 return is_supported; |
| 544 } | 540 } |
| 545 | 541 |
| 546 // static | 542 // static |
| 547 void ThreadTicks::WaitUntilInitializedWin() { | 543 void ThreadTicks::WaitUntilInitializedWin() { |
| 548 while (TSCTicksPerSecond() == 0) | 544 while (TSCTicksPerSecond() == 0) |
| 549 ::Sleep(10); | 545 ::Sleep(10); |
| 550 } | 546 } |
| 551 | 547 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { | 608 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
| 613 return TimeTicks() + QPCValueToTimeDelta(qpc_value); | 609 return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
| 614 } | 610 } |
| 615 | 611 |
| 616 // TimeDelta ------------------------------------------------------------------ | 612 // TimeDelta ------------------------------------------------------------------ |
| 617 | 613 |
| 618 // static | 614 // static |
| 619 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { | 615 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
| 620 return QPCValueToTimeDelta(qpc_value); | 616 return QPCValueToTimeDelta(qpc_value); |
| 621 } | 617 } |
| OLD | NEW |