Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Unified Diff: base/time/time_win.cc

Issue 1446363003: Deleted OS_WIN and all Windows specific files from base. (Closed) Base URL: https://github.com/domokit/mojo.git@base_tests
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/time/time_unittest.cc ('k') | base/time/time_win_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
-}
« no previous file with comments | « base/time/time_unittest.cc ('k') | base/time/time_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698