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
3 // found in the LICENSE file.
6 // Windows Timer Primer
8 // A good article: http://www.ddj.com/windows/184416651
9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
11 // The default windows timer, GetSystemTimeAsFileTime is not very precise.
12 // It is only good to ~15.5ms.
14 // QueryPerformanceCounter is the logical choice for a high-precision timer.
15 // However, it is known to be buggy on some hardware. Specifically, it can
16 // sometimes "jump". On laptops, QPC can also be very expensive to call.
17 // It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
18 // on laptops. A unittest exists which will show the relative cost of various
19 // timers on any system.
21 // The next logical choice is timeGetTime(). timeGetTime has a precision of
22 // 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
23 // applications on the system. By default, precision is only 15.5ms.
24 // Unfortunately, we don't want to call timeBeginPeriod because we don't
25 // want to affect other applications. Further, on mobile platforms, use of
26 // faster multimedia timers can hurt battery life. See the intel
27 // article about this here:
28 // http://softwarecommunity.intel.com/articles/eng/1086.htm
30 // To work around all this, we're going to generally use timeGetTime(). We
31 // will only increase the system-wide timer if we're not running on battery
32 // power. Using timeBeginPeriod(1) is a requirement in order to make our
33 // message loop waits have the same resolution that our time measurements
34 // do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
35 // there is nothing else to waken the Wait.
37 #include "base/time.h"
39 #pragma comment(lib, "winmm.lib")
43 #include "base/basictypes.h"
44 #include "base/logging.h"
46 #include "base/memory/singleton.h"
47 #include "base/synchronization/lock.h"
50 using base::TimeDelta
;
51 using base::TimeTicks
;
55 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
56 // 100-nanosecond intervals since January 1, 1601 (UTC)."
57 int64
FileTimeToMicroseconds(const FILETIME
& ft
) {
58 // Need to bit_cast to fix alignment, then divide by 10 to convert
59 // 100-nanoseconds to milliseconds. This only works on little-endian
61 return bit_cast
<int64
, FILETIME
>(ft
) / 10;
64 void MicrosecondsToFileTime(int64 us
, FILETIME
* ft
) {
65 DCHECK_GE(us
, 0LL) << "Time is less than 0, negative values are not "
66 "representable in FILETIME";
68 // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
69 // handle alignment problems. This only works on little-endian machines.
70 *ft
= bit_cast
<FILETIME
, int64
>(us
* 10);
73 int64
CurrentWallclockMicroseconds() {
75 ::GetSystemTimeAsFileTime(&ft
);
76 return FileTimeToMicroseconds(ft
);
79 // Time between resampling the un-granular clock for this API. 60 seconds.
80 const int kMaxMillisecondsToAvoidDrift
= 60 * Time::kMillisecondsPerSecond
;
82 int64 initial_time
= 0;
83 TimeTicks initial_ticks
;
85 void InitializeClock() {
86 initial_ticks
= TimeTicks::Now();
87 initial_time
= CurrentWallclockMicroseconds();
92 // Time -----------------------------------------------------------------------
94 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
95 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
96 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
97 // 1700, 1800, and 1900.
99 const int64
Time::kTimeTToMicrosecondsOffset
= GG_INT64_C(11644473600000000);
101 bool Time::high_resolution_timer_enabled_
= false;
102 int Time::high_resolution_timer_activated_
= 0;
106 if (initial_time
== 0)
109 // We implement time using the high-resolution timers so that we can get
110 // timeouts which are smaller than 10-15ms. If we just used
111 // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
113 // To make this work, we initialize the clock (initial_time) and the
114 // counter (initial_ctr). To compute the initial time, we can check
115 // the number of ticks that have elapsed, and compute the delta.
117 // To avoid any drift, we periodically resync the counters to the system
120 TimeTicks ticks
= TimeTicks::Now();
122 // Calculate the time elapsed since we started our timer
123 TimeDelta elapsed
= ticks
- initial_ticks
;
125 // Check if enough time has elapsed that we need to resync the clock.
126 if (elapsed
.InMilliseconds() > kMaxMillisecondsToAvoidDrift
) {
131 return Time(elapsed
+ Time(initial_time
));
136 Time
Time::NowFromSystemTime() {
139 return Time(initial_time
);
143 Time
Time::FromFileTime(FILETIME ft
) {
144 return Time(FileTimeToMicroseconds(ft
));
147 FILETIME
Time::ToFileTime() const {
149 MicrosecondsToFileTime(us_
, &utc_ft
);
154 void Time::EnableHighResolutionTimer(bool enable
) {
155 // Test for single-threaded access.
156 static PlatformThreadId my_thread
= PlatformThread::CurrentId();
157 DCHECK(PlatformThread::CurrentId() == my_thread
);
159 if (high_resolution_timer_enabled_
== enable
)
162 high_resolution_timer_enabled_
= enable
;
166 bool Time::ActivateHighResolutionTimer(bool activating
) {
167 if (!high_resolution_timer_enabled_
&& activating
)
170 // Using anything other than 1ms makes timers granular
172 const int kMinTimerIntervalMs
= 1;
175 result
= timeBeginPeriod(kMinTimerIntervalMs
);
176 high_resolution_timer_activated_
++;
178 result
= timeEndPeriod(kMinTimerIntervalMs
);
179 high_resolution_timer_activated_
--;
181 return result
== TIMERR_NOERROR
;
185 bool Time::IsHighResolutionTimerInUse() {
186 // Note: we should track the high_resolution_timer_activated_ value
187 // under a lock if we want it to be accurate in a system with multiple
188 // message loops. We don't do that - because we don't want to take the
189 // expense of a lock for this. We *only* track this value so that unit
190 // tests can see if the high resolution timer is on or off.
191 return high_resolution_timer_enabled_
&&
192 high_resolution_timer_activated_
> 0;
196 Time
Time::FromExploded(bool is_local
, const Exploded
& exploded
) {
197 // Create the system struct representing our exploded time. It will either be
198 // in local time or UTC.
200 st
.wYear
= exploded
.year
;
201 st
.wMonth
= exploded
.month
;
202 st
.wDayOfWeek
= exploded
.day_of_week
;
203 st
.wDay
= exploded
.day_of_month
;
204 st
.wHour
= exploded
.hour
;
205 st
.wMinute
= exploded
.minute
;
206 st
.wSecond
= exploded
.second
;
207 st
.wMilliseconds
= exploded
.millisecond
;
211 // Ensure that it's in UTC.
214 success
= TzSpecificLocalTimeToSystemTime(NULL
, &st
, &utc_st
) &&
215 SystemTimeToFileTime(&utc_st
, &ft
);
217 success
= !!SystemTimeToFileTime(&st
, &ft
);
221 NOTREACHED() << "Unable to convert time";
224 return Time(FileTimeToMicroseconds(ft
));
227 void Time::Explode(bool is_local
, Exploded
* exploded
) const {
229 // We are not able to convert it to FILETIME.
230 ZeroMemory(exploded
, sizeof(*exploded
));
236 MicrosecondsToFileTime(us_
, &utc_ft
);
238 // FILETIME in local time if necessary.
240 // FILETIME in SYSTEMTIME (exploded).
244 // We don't use FileTimeToLocalFileTime here, since it uses the current
245 // settings for the time zone and daylight saving time. Therefore, if it is
246 // daylight saving time, it will take daylight saving time into account,
247 // even if the time you are converting is in standard time.
248 success
= FileTimeToSystemTime(&utc_ft
, &utc_st
) &&
249 SystemTimeToTzSpecificLocalTime(NULL
, &utc_st
, &st
);
251 success
= !!FileTimeToSystemTime(&utc_ft
, &st
);
255 NOTREACHED() << "Unable to convert time, don't know why";
256 ZeroMemory(exploded
, sizeof(*exploded
));
260 exploded
->year
= st
.wYear
;
261 exploded
->month
= st
.wMonth
;
262 exploded
->day_of_week
= st
.wDayOfWeek
;
263 exploded
->day_of_month
= st
.wDay
;
264 exploded
->hour
= st
.wHour
;
265 exploded
->minute
= st
.wMinute
;
266 exploded
->second
= st
.wSecond
;
267 exploded
->millisecond
= st
.wMilliseconds
;
270 // TimeTicks ------------------------------------------------------------------
273 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
274 // mock function, and to avoid a static constructor. Assigning an import to a
275 // function pointer directly would require setup code to fetch from the IAT.
276 DWORD
timeGetTimeWrapper() {
277 return timeGetTime();
280 DWORD (*tick_function
)(void) = &timeGetTimeWrapper
;
282 // Accumulation of time lost due to rollover (in milliseconds).
283 int64 rollover_ms
= 0;
285 // The last timeGetTime value we saw, to detect rollover.
286 DWORD last_seen_now
= 0;
288 // Lock protecting rollover_ms and last_seen_now.
289 // Note: this is a global object, and we usually avoid these. However, the time
290 // code is low-level, and we don't want to use Singletons here (it would be too
291 // easy to use a Singleton without even knowing it, and that may lead to many
292 // gotchas). Its impact on startup time should be negligible due to low-level
293 // nature of time code.
294 base::Lock rollover_lock
;
296 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
297 // because it returns the number of milliseconds since Windows has started,
298 // which will roll over the 32-bit value every ~49 days. We try to track
299 // rollover ourselves, which works if TimeTicks::Now() is called at least every
301 TimeDelta
RolloverProtectedNow() {
302 base::AutoLock
locked(rollover_lock
);
303 // We should hold the lock while calling tick_function to make sure that
304 // we keep last_seen_now stay correctly in sync.
305 DWORD now
= tick_function();
306 if (now
< last_seen_now
)
307 rollover_ms
+= 0x100000000I
64; // ~49.7 days.
309 return TimeDelta::FromMilliseconds(now
+ rollover_ms
);
312 // Overview of time counters:
313 // (1) CPU cycle counter. (Retrieved via RDTSC)
314 // The CPU counter provides the highest resolution time stamp and is the least
315 // expensive to retrieve. However, the CPU counter is unreliable and should not
316 // be used in production. Its biggest issue is that it is per processor and it
317 // is not synchronized between processors. Also, on some computers, the counters
318 // will change frequency due to thermal and power changes, and stop in some
321 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
322 // resolution (100 nanoseconds) time stamp but is comparatively more expensive
323 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
324 // (with some help from ACPI).
325 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
326 // in the worst case, it gets the counter from the rollover interrupt on the
327 // programmable interrupt timer. In best cases, the HAL may conclude that the
328 // RDTSC counter runs at a constant frequency, then it uses that instead. On
329 // multiprocessor machines, it will try to verify the values returned from
330 // RDTSC on each processor are consistent with each other, and apply a handful
331 // of workarounds for known buggy hardware. In other words, QPC is supposed to
332 // give consistent result on a multiprocessor computer, but it is unreliable in
333 // reality due to bugs in BIOS or HAL on some, especially old computers.
334 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
335 // it should be used with caution.
337 // (3) System time. The system time provides a low-resolution (typically 10ms
338 // to 55 milliseconds) time stamp but is comparatively less expensive to
339 // retrieve and more reliable.
340 class HighResNowSingleton
{
342 static HighResNowSingleton
* GetInstance() {
343 return Singleton
<HighResNowSingleton
>::get();
346 bool IsUsingHighResClock() {
347 return ticks_per_microsecond_
!= 0.0;
350 void DisableHighResClock() {
351 ticks_per_microsecond_
= 0.0;
355 if (IsUsingHighResClock())
356 return TimeDelta::FromMicroseconds(UnreliableNow());
358 // Just fallback to the slower clock.
359 return RolloverProtectedNow();
362 int64
GetQPCDriftMicroseconds() {
363 if (!IsUsingHighResClock())
366 // The static_cast<long> is needed as a hint to VS 2008 to tell it
367 // which version of abs() to use. Other compilers don't seem to
368 // need it, including VS 2010, but to keep code identical we use it
370 // TODO(joi): Remove the hint if/when we no longer support VS 2008.
371 return abs(static_cast<long>((UnreliableNow() - ReliableNow()) - skew_
));
375 HighResNowSingleton()
376 : ticks_per_microsecond_(0.0),
380 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
381 // unreliable. Fallback to low-res clock.
383 if (cpu
.vendor_name() == "AuthenticAMD" && cpu
.family() == 15)
384 DisableHighResClock();
387 // Synchronize the QPC clock with GetSystemTimeAsFileTime.
388 void InitializeClock() {
389 LARGE_INTEGER ticks_per_sec
= {0};
390 if (!QueryPerformanceFrequency(&ticks_per_sec
))
391 return; // Broken, we don't guarantee this function works.
392 ticks_per_microsecond_
= static_cast<float>(ticks_per_sec
.QuadPart
) /
393 static_cast<float>(Time::kMicrosecondsPerSecond
);
395 skew_
= UnreliableNow() - ReliableNow();
398 // Get the number of microseconds since boot in an unreliable fashion.
399 int64
UnreliableNow() {
401 QueryPerformanceCounter(&now
);
402 return static_cast<int64
>(now
.QuadPart
/ ticks_per_microsecond_
);
405 // Get the number of microseconds since boot in a reliable fashion.
406 int64
ReliableNow() {
407 return RolloverProtectedNow().InMicroseconds();
410 // Cached clock frequency -> microseconds. This assumes that the clock
411 // frequency is faster than one microsecond (which is 1MHz, should be OK).
412 float ticks_per_microsecond_
; // 0 indicates QPF failed and we're broken.
413 int64 skew_
; // Skew between lo-res and hi-res clocks (for debugging).
415 friend struct DefaultSingletonTraits
<HighResNowSingleton
>;
421 TimeTicks::TickFunctionType
TimeTicks::SetMockTickFunction(
422 TickFunctionType ticker
) {
423 TickFunctionType old
= tick_function
;
424 tick_function
= ticker
;
429 TimeTicks
TimeTicks::Now() {
430 return TimeTicks() + RolloverProtectedNow();
434 TimeTicks
TimeTicks::HighResNow() {
435 return TimeTicks() + HighResNowSingleton::GetInstance()->Now();
439 TimeTicks
TimeTicks::NowFromSystemTraceTime() {
444 int64
TimeTicks::GetQPCDriftMicroseconds() {
445 return HighResNowSingleton::GetInstance()->GetQPCDriftMicroseconds();
449 bool TimeTicks::IsHighResClockWorking() {
450 return HighResNowSingleton::GetInstance()->IsUsingHighResClock();