1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/time_win.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,375 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 + 1.9 +// Windows Timer Primer 1.10 +// 1.11 +// A good article: http://www.ddj.com/windows/184416651 1.12 +// A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258 1.13 +// 1.14 +// The default windows timer, GetSystemTimeAsFileTime is not very precise. 1.15 +// It is only good to ~15.5ms. 1.16 +// 1.17 +// QueryPerformanceCounter is the logical choice for a high-precision timer. 1.18 +// However, it is known to be buggy on some hardware. Specifically, it can 1.19 +// sometimes "jump". On laptops, QPC can also be very expensive to call. 1.20 +// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower 1.21 +// on laptops. A unittest exists which will show the relative cost of various 1.22 +// timers on any system. 1.23 +// 1.24 +// The next logical choice is timeGetTime(). timeGetTime has a precision of 1.25 +// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other 1.26 +// applications on the system. By default, precision is only 15.5ms. 1.27 +// Unfortunately, we don't want to call timeBeginPeriod because we don't 1.28 +// want to affect other applications. Further, on mobile platforms, use of 1.29 +// faster multimedia timers can hurt battery life. See the intel 1.30 +// article about this here: 1.31 +// http://softwarecommunity.intel.com/articles/eng/1086.htm 1.32 +// 1.33 +// To work around all this, we're going to generally use timeGetTime(). We 1.34 +// will only increase the system-wide timer if we're not running on battery 1.35 +// power. Using timeBeginPeriod(1) is a requirement in order to make our 1.36 +// message loop waits have the same resolution that our time measurements 1.37 +// do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when 1.38 +// there is nothing else to waken the Wait. 1.39 + 1.40 +#include "base/time.h" 1.41 + 1.42 +#pragma comment(lib, "winmm.lib") 1.43 +#include <windows.h> 1.44 +#include <mmsystem.h> 1.45 + 1.46 +#include "base/basictypes.h" 1.47 +#include "base/lock.h" 1.48 +#include "base/logging.h" 1.49 +#include "base/cpu.h" 1.50 +#include "base/singleton.h" 1.51 +#include "base/system_monitor.h" 1.52 +#include "mozilla/Casting.h" 1.53 + 1.54 +using base::Time; 1.55 +using base::TimeDelta; 1.56 +using base::TimeTicks; 1.57 +using mozilla::BitwiseCast; 1.58 + 1.59 +namespace { 1.60 + 1.61 +// From MSDN, FILETIME "Contains a 64-bit value representing the number of 1.62 +// 100-nanosecond intervals since January 1, 1601 (UTC)." 1.63 +int64_t FileTimeToMicroseconds(const FILETIME& ft) { 1.64 + // Need to BitwiseCast to fix alignment, then divide by 10 to convert 1.65 + // 100-nanoseconds to milliseconds. This only works on little-endian 1.66 + // machines. 1.67 + return BitwiseCast<int64_t>(ft) / 10; 1.68 +} 1.69 + 1.70 +void MicrosecondsToFileTime(int64_t us, FILETIME* ft) { 1.71 + DCHECK(us >= 0) << "Time is less than 0, negative values are not " 1.72 + "representable in FILETIME"; 1.73 + 1.74 + // Multiply by 10 to convert milliseconds to 100-nanoseconds. BitwiseCast will 1.75 + // handle alignment problems. This only works on little-endian machines. 1.76 + *ft = BitwiseCast<FILETIME>(us * 10); 1.77 +} 1.78 + 1.79 +int64_t CurrentWallclockMicroseconds() { 1.80 + FILETIME ft; 1.81 + ::GetSystemTimeAsFileTime(&ft); 1.82 + return FileTimeToMicroseconds(ft); 1.83 +} 1.84 + 1.85 +// Time between resampling the un-granular clock for this API. 60 seconds. 1.86 +const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond; 1.87 + 1.88 +int64_t initial_time = 0; 1.89 +TimeTicks initial_ticks; 1.90 + 1.91 +void InitializeClock() { 1.92 + initial_ticks = TimeTicks::Now(); 1.93 + initial_time = CurrentWallclockMicroseconds(); 1.94 +} 1.95 + 1.96 +} // namespace 1.97 + 1.98 +// Time ----------------------------------------------------------------------- 1.99 + 1.100 +// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01 1.101 +// 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the 1.102 +// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding 1.103 +// 1700, 1800, and 1900. 1.104 +// static 1.105 +const int64_t Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000); 1.106 + 1.107 +// static 1.108 +Time Time::Now() { 1.109 + if (initial_time == 0) 1.110 + InitializeClock(); 1.111 + 1.112 + // We implement time using the high-resolution timers so that we can get 1.113 + // timeouts which are smaller than 10-15ms. If we just used 1.114 + // CurrentWallclockMicroseconds(), we'd have the less-granular timer. 1.115 + // 1.116 + // To make this work, we initialize the clock (initial_time) and the 1.117 + // counter (initial_ctr). To compute the initial time, we can check 1.118 + // the number of ticks that have elapsed, and compute the delta. 1.119 + // 1.120 + // To avoid any drift, we periodically resync the counters to the system 1.121 + // clock. 1.122 + while(true) { 1.123 + TimeTicks ticks = TimeTicks::Now(); 1.124 + 1.125 + // Calculate the time elapsed since we started our timer 1.126 + TimeDelta elapsed = ticks - initial_ticks; 1.127 + 1.128 + // Check if enough time has elapsed that we need to resync the clock. 1.129 + if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) { 1.130 + InitializeClock(); 1.131 + continue; 1.132 + } 1.133 + 1.134 + return Time(elapsed + initial_time); 1.135 + } 1.136 +} 1.137 + 1.138 +// static 1.139 +Time Time::NowFromSystemTime() { 1.140 + // Force resync. 1.141 + InitializeClock(); 1.142 + return Time(initial_time); 1.143 +} 1.144 + 1.145 +// static 1.146 +Time Time::FromFileTime(FILETIME ft) { 1.147 + return Time(FileTimeToMicroseconds(ft)); 1.148 +} 1.149 + 1.150 +FILETIME Time::ToFileTime() const { 1.151 + FILETIME utc_ft; 1.152 + MicrosecondsToFileTime(us_, &utc_ft); 1.153 + return utc_ft; 1.154 +} 1.155 + 1.156 +// static 1.157 +Time Time::FromExploded(bool is_local, const Exploded& exploded) { 1.158 + // Create the system struct representing our exploded time. It will either be 1.159 + // in local time or UTC. 1.160 + SYSTEMTIME st; 1.161 + st.wYear = exploded.year; 1.162 + st.wMonth = exploded.month; 1.163 + st.wDayOfWeek = exploded.day_of_week; 1.164 + st.wDay = exploded.day_of_month; 1.165 + st.wHour = exploded.hour; 1.166 + st.wMinute = exploded.minute; 1.167 + st.wSecond = exploded.second; 1.168 + st.wMilliseconds = exploded.millisecond; 1.169 + 1.170 + // Convert to FILETIME. 1.171 + FILETIME ft; 1.172 + if (!SystemTimeToFileTime(&st, &ft)) { 1.173 + NOTREACHED() << "Unable to convert time"; 1.174 + return Time(0); 1.175 + } 1.176 + 1.177 + // Ensure that it's in UTC. 1.178 + if (is_local) { 1.179 + FILETIME utc_ft; 1.180 + LocalFileTimeToFileTime(&ft, &utc_ft); 1.181 + return Time(FileTimeToMicroseconds(utc_ft)); 1.182 + } 1.183 + return Time(FileTimeToMicroseconds(ft)); 1.184 +} 1.185 + 1.186 +void Time::Explode(bool is_local, Exploded* exploded) const { 1.187 + // FILETIME in UTC. 1.188 + FILETIME utc_ft; 1.189 + MicrosecondsToFileTime(us_, &utc_ft); 1.190 + 1.191 + // FILETIME in local time if necessary. 1.192 + BOOL success = TRUE; 1.193 + FILETIME ft; 1.194 + if (is_local) 1.195 + success = FileTimeToLocalFileTime(&utc_ft, &ft); 1.196 + else 1.197 + ft = utc_ft; 1.198 + 1.199 + // FILETIME in SYSTEMTIME (exploded). 1.200 + SYSTEMTIME st; 1.201 + if (!success || !FileTimeToSystemTime(&ft, &st)) { 1.202 + NOTREACHED() << "Unable to convert time, don't know why"; 1.203 + ZeroMemory(exploded, sizeof(*exploded)); 1.204 + return; 1.205 + } 1.206 + 1.207 + exploded->year = st.wYear; 1.208 + exploded->month = st.wMonth; 1.209 + exploded->day_of_week = st.wDayOfWeek; 1.210 + exploded->day_of_month = st.wDay; 1.211 + exploded->hour = st.wHour; 1.212 + exploded->minute = st.wMinute; 1.213 + exploded->second = st.wSecond; 1.214 + exploded->millisecond = st.wMilliseconds; 1.215 +} 1.216 + 1.217 +// TimeTicks ------------------------------------------------------------------ 1.218 +namespace { 1.219 + 1.220 +// We define a wrapper to adapt between the __stdcall and __cdecl call of the 1.221 +// mock function, and to avoid a static constructor. Assigning an import to a 1.222 +// function pointer directly would require setup code to fetch from the IAT. 1.223 +DWORD timeGetTimeWrapper() { 1.224 + return timeGetTime(); 1.225 +} 1.226 + 1.227 + 1.228 +DWORD (*tick_function)(void) = &timeGetTimeWrapper; 1.229 + 1.230 +// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic 1.231 +// because it returns the number of milliseconds since Windows has started, 1.232 +// which will roll over the 32-bit value every ~49 days. We try to track 1.233 +// rollover ourselves, which works if TimeTicks::Now() is called at least every 1.234 +// 49 days. 1.235 +class NowSingleton { 1.236 + public: 1.237 + NowSingleton() 1.238 + : rollover_(TimeDelta::FromMilliseconds(0)), 1.239 + last_seen_(0) { 1.240 + } 1.241 + 1.242 + TimeDelta Now() { 1.243 + AutoLock locked(lock_); 1.244 + // We should hold the lock while calling tick_function to make sure that 1.245 + // we keep our last_seen_ stay correctly in sync. 1.246 + DWORD now = tick_function(); 1.247 + if (now < last_seen_) 1.248 + rollover_ += TimeDelta::FromMilliseconds(GG_LONGLONG(0x100000000)); // ~49.7 days. 1.249 + last_seen_ = now; 1.250 + return TimeDelta::FromMilliseconds(now) + rollover_; 1.251 + } 1.252 + 1.253 + private: 1.254 + Lock lock_; // To protected last_seen_ and rollover_. 1.255 + TimeDelta rollover_; // Accumulation of time lost due to rollover. 1.256 + DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover. 1.257 + 1.258 + DISALLOW_COPY_AND_ASSIGN(NowSingleton); 1.259 +}; 1.260 + 1.261 +// Overview of time counters: 1.262 +// (1) CPU cycle counter. (Retrieved via RDTSC) 1.263 +// The CPU counter provides the highest resolution time stamp and is the least 1.264 +// expensive to retrieve. However, the CPU counter is unreliable and should not 1.265 +// be used in production. Its biggest issue is that it is per processor and it 1.266 +// is not synchronized between processors. Also, on some computers, the counters 1.267 +// will change frequency due to thermal and power changes, and stop in some 1.268 +// states. 1.269 +// 1.270 +// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high- 1.271 +// resolution (100 nanoseconds) time stamp but is comparatively more expensive 1.272 +// to retrieve. What QueryPerformanceCounter actually does is up to the HAL. 1.273 +// (with some help from ACPI). 1.274 +// According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx 1.275 +// in the worst case, it gets the counter from the rollover interrupt on the 1.276 +// programmable interrupt timer. In best cases, the HAL may conclude that the 1.277 +// RDTSC counter runs at a constant frequency, then it uses that instead. On 1.278 +// multiprocessor machines, it will try to verify the values returned from 1.279 +// RDTSC on each processor are consistent with each other, and apply a handful 1.280 +// of workarounds for known buggy hardware. In other words, QPC is supposed to 1.281 +// give consistent result on a multiprocessor computer, but it is unreliable in 1.282 +// reality due to bugs in BIOS or HAL on some, especially old computers. 1.283 +// With recent updates on HAL and newer BIOS, QPC is getting more reliable but 1.284 +// it should be used with caution. 1.285 +// 1.286 +// (3) System time. The system time provides a low-resolution (typically 10ms 1.287 +// to 55 milliseconds) time stamp but is comparatively less expensive to 1.288 +// retrieve and more reliable. 1.289 +class HighResNowSingleton { 1.290 + public: 1.291 + HighResNowSingleton() 1.292 + : ticks_per_microsecond_(0.0), 1.293 + skew_(0) { 1.294 + InitializeClock(); 1.295 + 1.296 + // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is 1.297 + // unreliable. Fallback to low-res clock. 1.298 + base::CPU cpu; 1.299 + if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) 1.300 + DisableHighResClock(); 1.301 + } 1.302 + 1.303 + bool IsUsingHighResClock() { 1.304 + return ticks_per_microsecond_ != 0.0; 1.305 + } 1.306 + 1.307 + void DisableHighResClock() { 1.308 + ticks_per_microsecond_ = 0.0; 1.309 + } 1.310 + 1.311 + TimeDelta Now() { 1.312 + // Our maximum tolerance for QPC drifting. 1.313 + const int kMaxTimeDrift = 50 * Time::kMicrosecondsPerMillisecond; 1.314 + 1.315 + if (IsUsingHighResClock()) { 1.316 + int64_t now = UnreliableNow(); 1.317 + 1.318 + // Verify that QPC does not seem to drift. 1.319 + DCHECK(now - ReliableNow() - skew_ < kMaxTimeDrift); 1.320 + 1.321 + return TimeDelta::FromMicroseconds(now); 1.322 + } 1.323 + 1.324 + // Just fallback to the slower clock. 1.325 + return Singleton<NowSingleton>::get()->Now(); 1.326 + } 1.327 + 1.328 + private: 1.329 + // Synchronize the QPC clock with GetSystemTimeAsFileTime. 1.330 + void InitializeClock() { 1.331 + LARGE_INTEGER ticks_per_sec = {0}; 1.332 + if (!QueryPerformanceFrequency(&ticks_per_sec)) 1.333 + return; // Broken, we don't guarantee this function works. 1.334 + ticks_per_microsecond_ = static_cast<float>(ticks_per_sec.QuadPart) / 1.335 + static_cast<float>(Time::kMicrosecondsPerSecond); 1.336 + 1.337 + skew_ = UnreliableNow() - ReliableNow(); 1.338 + } 1.339 + 1.340 + // Get the number of microseconds since boot in a reliable fashion 1.341 + int64_t UnreliableNow() { 1.342 + LARGE_INTEGER now; 1.343 + QueryPerformanceCounter(&now); 1.344 + return static_cast<int64_t>(now.QuadPart / ticks_per_microsecond_); 1.345 + } 1.346 + 1.347 + // Get the number of microseconds since boot in a reliable fashion 1.348 + int64_t ReliableNow() { 1.349 + return Singleton<NowSingleton>::get()->Now().InMicroseconds(); 1.350 + } 1.351 + 1.352 + // Cached clock frequency -> microseconds. This assumes that the clock 1.353 + // frequency is faster than one microsecond (which is 1MHz, should be OK). 1.354 + float ticks_per_microsecond_; // 0 indicates QPF failed and we're broken. 1.355 + int64_t skew_; // Skew between lo-res and hi-res clocks (for debugging). 1.356 + 1.357 + DISALLOW_COPY_AND_ASSIGN(HighResNowSingleton); 1.358 +}; 1.359 + 1.360 +} // namespace 1.361 + 1.362 +// static 1.363 +TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( 1.364 + TickFunctionType ticker) { 1.365 + TickFunctionType old = tick_function; 1.366 + tick_function = ticker; 1.367 + return old; 1.368 +} 1.369 + 1.370 +// static 1.371 +TimeTicks TimeTicks::Now() { 1.372 + return TimeTicks() + Singleton<NowSingleton>::get()->Now(); 1.373 +} 1.374 + 1.375 +// static 1.376 +TimeTicks TimeTicks::HighResNow() { 1.377 + return TimeTicks() + Singleton<HighResNowSingleton>::get()->Now(); 1.378 +}