Index: base/time/time_win.cc |
diff --git a/base/time/time_win.cc b/base/time/time_win.cc |
deleted file mode 100644 |
index 91444830009097bed18067285cdb50ca7e9771a7..0000000000000000000000000000000000000000 |
--- a/base/time/time_win.cc |
+++ /dev/null |
@@ -1,530 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
- |
-// Windows Timer Primer |
-// |
-// A good article: http://www.ddj.com/windows/184416651 |
-// A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 |
-// |
-// The default windows timer, GetSystemTimeAsFileTime is not very precise. |
-// It is only good to ~15.5ms. |
-// |
-// QueryPerformanceCounter is the logical choice for a high-precision timer. |
-// However, it is known to be buggy on some hardware. Specifically, it can |
-// sometimes "jump". On laptops, QPC can also be very expensive to call. |
-// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower |
-// on laptops. A unittest exists which will show the relative cost of various |
-// timers on any system. |
-// |
-// The next logical choice is timeGetTime(). timeGetTime has a precision of |
-// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other |
-// applications on the system. By default, precision is only 15.5ms. |
-// Unfortunately, we don't want to call timeBeginPeriod because we don't |
-// want to affect other applications. Further, on mobile platforms, use of |
-// faster multimedia timers can hurt battery life. See the intel |
-// article about this here: |
-// http://softwarecommunity.intel.com/articles/eng/1086.htm |
-// |
-// To work around all this, we're going to generally use timeGetTime(). We |
-// will only increase the system-wide timer if we're not running on battery |
-// power. |
- |
-#include "base/time/time.h" |
- |
-#pragma comment(lib, "winmm.lib") |
-#include <windows.h> |
-#include <mmsystem.h> |
-#include <stdint.h> |
- |
-#include "base/basictypes.h" |
-#include "base/cpu.h" |
-#include "base/lazy_instance.h" |
-#include "base/logging.h" |
-#include "base/synchronization/lock.h" |
- |
-using base::ThreadTicks; |
-using base::Time; |
-using base::TimeDelta; |
-using base::TimeTicks; |
-using base::TraceTicks; |
- |
-namespace { |
- |
-// From MSDN, FILETIME "Contains a 64-bit value representing the number of |
-// 100-nanosecond intervals since January 1, 1601 (UTC)." |
-int64 FileTimeToMicroseconds(const FILETIME& ft) { |
- // Need to bit_cast to fix alignment, then divide by 10 to convert |
- // 100-nanoseconds to milliseconds. This only works on little-endian |
- // machines. |
- return bit_cast<int64, FILETIME>(ft) / 10; |
-} |
- |
-void MicrosecondsToFileTime(int64 us, FILETIME* ft) { |
- DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not " |
- "representable in FILETIME"; |
- |
- // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will |
- // handle alignment problems. This only works on little-endian machines. |
- *ft = bit_cast<FILETIME, int64>(us * 10); |
-} |
- |
-int64 CurrentWallclockMicroseconds() { |
- FILETIME ft; |
- ::GetSystemTimeAsFileTime(&ft); |
- return FileTimeToMicroseconds(ft); |
-} |
- |
-// Time between resampling the un-granular clock for this API. 60 seconds. |
-const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; |
- |
-int64 initial_time = 0; |
-TimeTicks initial_ticks; |
- |
-void InitializeClock() { |
- initial_ticks = TimeTicks::Now(); |
- initial_time = CurrentWallclockMicroseconds(); |
-} |
- |
-// The two values that ActivateHighResolutionTimer uses to set the systemwide |
-// timer interrupt frequency on Windows. It controls how precise timers are |
-// but also has a big impact on battery life. |
-const int kMinTimerIntervalHighResMs = 1; |
-const int kMinTimerIntervalLowResMs = 4; |
-// Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active. |
-bool g_high_res_timer_enabled = false; |
-// How many times the high resolution timer has been called. |
-uint32_t g_high_res_timer_count = 0; |
-// The lock to control access to the above two variables. |
-base::LazyInstance<base::Lock>::Leaky g_high_res_lock = |
- LAZY_INSTANCE_INITIALIZER; |
- |
-} // namespace |
- |
-// Time ----------------------------------------------------------------------- |
- |
-// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 |
-// 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the |
-// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding |
-// 1700, 1800, and 1900. |
-// static |
-const int64 Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000); |
- |
-// static |
-Time Time::Now() { |
- if (initial_time == 0) |
- InitializeClock(); |
- |
- // We implement time using the high-resolution timers so that we can get |
- // timeouts which are smaller than 10-15ms. If we just used |
- // CurrentWallclockMicroseconds(), we'd have the less-granular timer. |
- // |
- // To make this work, we initialize the clock (initial_time) and the |
- // counter (initial_ctr). To compute the initial time, we can check |
- // the number of ticks that have elapsed, and compute the delta. |
- // |
- // To avoid any drift, we periodically resync the counters to the system |
- // clock. |
- while (true) { |
- TimeTicks ticks = TimeTicks::Now(); |
- |
- // Calculate the time elapsed since we started our timer |
- TimeDelta elapsed = ticks - initial_ticks; |
- |
- // Check if enough time has elapsed that we need to resync the clock. |
- if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) { |
- InitializeClock(); |
- continue; |
- } |
- |
- return Time(elapsed + Time(initial_time)); |
- } |
-} |
- |
-// static |
-Time Time::NowFromSystemTime() { |
- // Force resync. |
- InitializeClock(); |
- return Time(initial_time); |
-} |
- |
-// static |
-Time Time::FromFileTime(FILETIME ft) { |
- if (bit_cast<int64, FILETIME>(ft) == 0) |
- return Time(); |
- if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() && |
- ft.dwLowDateTime == std::numeric_limits<DWORD>::max()) |
- return Max(); |
- return Time(FileTimeToMicroseconds(ft)); |
-} |
- |
-FILETIME Time::ToFileTime() const { |
- if (is_null()) |
- return bit_cast<FILETIME, int64>(0); |
- if (is_max()) { |
- FILETIME result; |
- result.dwHighDateTime = std::numeric_limits<DWORD>::max(); |
- result.dwLowDateTime = std::numeric_limits<DWORD>::max(); |
- return result; |
- } |
- FILETIME utc_ft; |
- MicrosecondsToFileTime(us_, &utc_ft); |
- return utc_ft; |
-} |
- |
-// static |
-void Time::EnableHighResolutionTimer(bool enable) { |
- base::AutoLock lock(g_high_res_lock.Get()); |
- if (g_high_res_timer_enabled == enable) |
- return; |
- g_high_res_timer_enabled = enable; |
- if (!g_high_res_timer_count) |
- return; |
- // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true) |
- // was called which called timeBeginPeriod with g_high_res_timer_enabled |
- // with a value which is the opposite of |enable|. With that information we |
- // call timeEndPeriod with the same value used in timeBeginPeriod and |
- // therefore undo the period effect. |
- if (enable) { |
- timeEndPeriod(kMinTimerIntervalLowResMs); |
- timeBeginPeriod(kMinTimerIntervalHighResMs); |
- } else { |
- timeEndPeriod(kMinTimerIntervalHighResMs); |
- timeBeginPeriod(kMinTimerIntervalLowResMs); |
- } |
-} |
- |
-// static |
-bool Time::ActivateHighResolutionTimer(bool activating) { |
- // We only do work on the transition from zero to one or one to zero so we |
- // can easily undo the effect (if necessary) when EnableHighResolutionTimer is |
- // called. |
- const uint32_t max = std::numeric_limits<uint32_t>::max(); |
- |
- base::AutoLock lock(g_high_res_lock.Get()); |
- UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs |
- : kMinTimerIntervalLowResMs; |
- if (activating) { |
- DCHECK_NE(g_high_res_timer_count, max); |
- ++g_high_res_timer_count; |
- if (g_high_res_timer_count == 1) |
- timeBeginPeriod(period); |
- } else { |
- DCHECK_NE(g_high_res_timer_count, 0u); |
- --g_high_res_timer_count; |
- if (g_high_res_timer_count == 0) |
- timeEndPeriod(period); |
- } |
- return (period == kMinTimerIntervalHighResMs); |
-} |
- |
-// static |
-bool Time::IsHighResolutionTimerInUse() { |
- base::AutoLock lock(g_high_res_lock.Get()); |
- return g_high_res_timer_enabled && g_high_res_timer_count > 0; |
-} |
- |
-// static |
-Time Time::FromExploded(bool is_local, const Exploded& exploded) { |
- // Create the system struct representing our exploded time. It will either be |
- // in local time or UTC. |
- SYSTEMTIME st; |
- st.wYear = static_cast<WORD>(exploded.year); |
- st.wMonth = static_cast<WORD>(exploded.month); |
- st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week); |
- st.wDay = static_cast<WORD>(exploded.day_of_month); |
- st.wHour = static_cast<WORD>(exploded.hour); |
- st.wMinute = static_cast<WORD>(exploded.minute); |
- st.wSecond = static_cast<WORD>(exploded.second); |
- st.wMilliseconds = static_cast<WORD>(exploded.millisecond); |
- |
- FILETIME ft; |
- bool success = true; |
- // Ensure that it's in UTC. |
- if (is_local) { |
- SYSTEMTIME utc_st; |
- success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) && |
- SystemTimeToFileTime(&utc_st, &ft); |
- } else { |
- success = !!SystemTimeToFileTime(&st, &ft); |
- } |
- |
- if (!success) { |
- NOTREACHED() << "Unable to convert time"; |
- return Time(0); |
- } |
- return Time(FileTimeToMicroseconds(ft)); |
-} |
- |
-void Time::Explode(bool is_local, Exploded* exploded) const { |
- if (us_ < 0LL) { |
- // We are not able to convert it to FILETIME. |
- ZeroMemory(exploded, sizeof(*exploded)); |
- return; |
- } |
- |
- // FILETIME in UTC. |
- FILETIME utc_ft; |
- MicrosecondsToFileTime(us_, &utc_ft); |
- |
- // FILETIME in local time if necessary. |
- bool success = true; |
- // FILETIME in SYSTEMTIME (exploded). |
- SYSTEMTIME st = {0}; |
- if (is_local) { |
- SYSTEMTIME utc_st; |
- // We don't use FileTimeToLocalFileTime here, since it uses the current |
- // settings for the time zone and daylight saving time. Therefore, if it is |
- // daylight saving time, it will take daylight saving time into account, |
- // even if the time you are converting is in standard time. |
- success = FileTimeToSystemTime(&utc_ft, &utc_st) && |
- SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st); |
- } else { |
- success = !!FileTimeToSystemTime(&utc_ft, &st); |
- } |
- |
- if (!success) { |
- NOTREACHED() << "Unable to convert time, don't know why"; |
- ZeroMemory(exploded, sizeof(*exploded)); |
- return; |
- } |
- |
- exploded->year = st.wYear; |
- exploded->month = st.wMonth; |
- exploded->day_of_week = st.wDayOfWeek; |
- exploded->day_of_month = st.wDay; |
- exploded->hour = st.wHour; |
- exploded->minute = st.wMinute; |
- exploded->second = st.wSecond; |
- exploded->millisecond = st.wMilliseconds; |
-} |
- |
-// TimeTicks ------------------------------------------------------------------ |
-namespace { |
- |
-// We define a wrapper to adapt between the __stdcall and __cdecl call of the |
-// mock function, and to avoid a static constructor. Assigning an import to a |
-// function pointer directly would require setup code to fetch from the IAT. |
-DWORD timeGetTimeWrapper() { |
- return timeGetTime(); |
-} |
- |
-DWORD (*g_tick_function)(void) = &timeGetTimeWrapper; |
- |
-// Accumulation of time lost due to rollover (in milliseconds). |
-int64 g_rollover_ms = 0; |
- |
-// The last timeGetTime value we saw, to detect rollover. |
-DWORD g_last_seen_now = 0; |
- |
-// Lock protecting rollover_ms and last_seen_now. |
-// Note: this is a global object, and we usually avoid these. However, the time |
-// code is low-level, and we don't want to use Singletons here (it would be too |
-// easy to use a Singleton without even knowing it, and that may lead to many |
-// gotchas). Its impact on startup time should be negligible due to low-level |
-// nature of time code. |
-base::Lock g_rollover_lock; |
- |
-// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
-// because it returns the number of milliseconds since Windows has started, |
-// which will roll over the 32-bit value every ~49 days. We try to track |
-// rollover ourselves, which works if TimeTicks::Now() is called at least every |
-// 49 days. |
-TimeDelta RolloverProtectedNow() { |
- base::AutoLock locked(g_rollover_lock); |
- // We should hold the lock while calling tick_function to make sure that |
- // we keep last_seen_now stay correctly in sync. |
- DWORD now = g_tick_function(); |
- if (now < g_last_seen_now) |
- g_rollover_ms += 0x100000000I64; // ~49.7 days. |
- g_last_seen_now = now; |
- return TimeDelta::FromMilliseconds(now + g_rollover_ms); |
-} |
- |
-// Discussion of tick counter options on Windows: |
-// |
-// (1) CPU cycle counter. (Retrieved via RDTSC) |
-// The CPU counter provides the highest resolution time stamp and is the least |
-// expensive to retrieve. However, on older CPUs, two issues can affect its |
-// reliability: First it is maintained per processor and not synchronized |
-// between processors. Also, the counters will change frequency due to thermal |
-// and power changes, and stop in some states. |
-// |
-// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- |
-// resolution (<1 microsecond) time stamp. On most hardware running today, it |
-// auto-detects and uses the constant-rate RDTSC counter to provide extremely |
-// efficient and reliable time stamps. |
-// |
-// On older CPUs where RDTSC is unreliable, it falls back to using more |
-// expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI |
-// PM timer, and can involve system calls; and all this is up to the HAL (with |
-// some help from ACPI). According to |
-// http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the |
-// worst case, it gets the counter from the rollover interrupt on the |
-// programmable interrupt timer. In best cases, the HAL may conclude that the |
-// RDTSC counter runs at a constant frequency, then it uses that instead. On |
-// multiprocessor machines, it will try to verify the values returned from |
-// RDTSC on each processor are consistent with each other, and apply a handful |
-// of workarounds for known buggy hardware. In other words, QPC is supposed to |
-// give consistent results on a multiprocessor computer, but for older CPUs it |
-// can be unreliable due bugs in BIOS or HAL. |
-// |
-// (3) System time. The system time provides a low-resolution (from ~1 to ~15.6 |
-// milliseconds) time stamp but is comparatively less expensive to retrieve and |
-// more reliable. Time::EnableHighResolutionTimer() and |
-// Time::ActivateHighResolutionTimer() can be called to alter the resolution of |
-// this timer; and also other Windows applications can alter it, affecting this |
-// one. |
- |
-using NowFunction = TimeDelta (*)(void); |
- |
-TimeDelta InitialNowFunction(); |
-TimeDelta InitialSystemTraceNowFunction(); |
- |
-// See "threading notes" in InitializeNowFunctionPointers() for details on how |
-// concurrent reads/writes to these globals has been made safe. |
-NowFunction g_now_function = &InitialNowFunction; |
-NowFunction g_system_trace_now_function = &InitialSystemTraceNowFunction; |
-int64 g_qpc_ticks_per_second = 0; |
- |
-// As of January 2015, use of <atomic> is forbidden in Chromium code. This is |
-// what std::atomic_thread_fence does on Windows on all Intel architectures when |
-// the memory_order argument is anything but std::memory_order_seq_cst: |
-#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier(); |
- |
-TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) { |
- // Ensure that the assignment to |g_qpc_ticks_per_second|, made in |
- // InitializeNowFunctionPointers(), has happened by this point. |
- ATOMIC_THREAD_FENCE(memory_order_acquire); |
- |
- DCHECK_GT(g_qpc_ticks_per_second, 0); |
- |
- // If the QPC Value is below the overflow threshold, we proceed with |
- // simple multiply and divide. |
- if (qpc_value < Time::kQPCOverflowThreshold) { |
- return TimeDelta::FromMicroseconds( |
- qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second); |
- } |
- // Otherwise, calculate microseconds in a round about manner to avoid |
- // overflow and precision issues. |
- int64 whole_seconds = qpc_value / g_qpc_ticks_per_second; |
- int64 leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second); |
- return TimeDelta::FromMicroseconds( |
- (whole_seconds * Time::kMicrosecondsPerSecond) + |
- ((leftover_ticks * Time::kMicrosecondsPerSecond) / |
- g_qpc_ticks_per_second)); |
-} |
- |
-TimeDelta QPCNow() { |
- LARGE_INTEGER now; |
- QueryPerformanceCounter(&now); |
- return QPCValueToTimeDelta(now.QuadPart); |
-} |
- |
-bool IsBuggyAthlon(const base::CPU& cpu) { |
- // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. |
- return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15; |
-} |
- |
-void InitializeNowFunctionPointers() { |
- LARGE_INTEGER ticks_per_sec = {0}; |
- if (!QueryPerformanceFrequency(&ticks_per_sec)) |
- ticks_per_sec.QuadPart = 0; |
- |
- // If Windows cannot provide a QPC implementation, both TimeTicks::Now() and |
- // TraceTicks::Now() must use the low-resolution clock. |
- // |
- // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now() |
- // will use the low-resolution clock, but TraceTicks::Now() will use the QPC |
- // (in the hope that it is still useful for tracing purposes). A CPU lacking a |
- // non-stop time counter will cause Windows to provide an alternate QPC |
- // implementation that works, but is expensive to use. Certain Athlon CPUs are |
- // known to make the QPC implementation unreliable. |
- // |
- // Otherwise, both Now functions can use the high-resolution QPC clock. As of |
- // 4 January 2015, ~68% of users fall within this category. |
- NowFunction now_function; |
- NowFunction system_trace_now_function; |
- base::CPU cpu; |
- if (ticks_per_sec.QuadPart <= 0) { |
- now_function = system_trace_now_function = &RolloverProtectedNow; |
- } else if (!cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) { |
- now_function = &RolloverProtectedNow; |
- system_trace_now_function = &QPCNow; |
- } else { |
- now_function = system_trace_now_function = &QPCNow; |
- } |
- |
- // Threading note 1: In an unlikely race condition, it's possible for two or |
- // more threads to enter InitializeNowFunctionPointers() in parallel. This is |
- // not a problem since all threads should end up writing out the same values |
- // to the global variables. |
- // |
- // Threading note 2: A release fence is placed here to ensure, from the |
- // perspective of other threads using the function pointers, that the |
- // assignment to |g_qpc_ticks_per_second| happens before the function pointers |
- // are changed. |
- g_qpc_ticks_per_second = ticks_per_sec.QuadPart; |
- ATOMIC_THREAD_FENCE(memory_order_release); |
- g_now_function = now_function; |
- g_system_trace_now_function = system_trace_now_function; |
-} |
- |
-TimeDelta InitialNowFunction() { |
- InitializeNowFunctionPointers(); |
- return g_now_function(); |
-} |
- |
-TimeDelta InitialSystemTraceNowFunction() { |
- InitializeNowFunctionPointers(); |
- return g_system_trace_now_function(); |
-} |
- |
-} // namespace |
- |
-// static |
-TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
- TickFunctionType ticker) { |
- base::AutoLock locked(g_rollover_lock); |
- TickFunctionType old = g_tick_function; |
- g_tick_function = ticker; |
- g_rollover_ms = 0; |
- g_last_seen_now = 0; |
- return old; |
-} |
- |
-// static |
-TimeTicks TimeTicks::Now() { |
- return TimeTicks() + g_now_function(); |
-} |
- |
-// static |
-bool TimeTicks::IsHighResolution() { |
- if (g_now_function == &InitialNowFunction) |
- InitializeNowFunctionPointers(); |
- return g_now_function == &QPCNow; |
-} |
- |
-// static |
-ThreadTicks ThreadTicks::Now() { |
- NOTREACHED(); |
- return ThreadTicks(); |
-} |
- |
-// static |
-TraceTicks TraceTicks::Now() { |
- return TraceTicks() + g_system_trace_now_function(); |
-} |
- |
-// static |
-TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) { |
- return TimeTicks() + QPCValueToTimeDelta(qpc_value); |
-} |
- |
-// TimeDelta ------------------------------------------------------------------ |
- |
-// static |
-TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) { |
- return QPCValueToTimeDelta(qpc_value); |
-} |