1 // Copyright (c) 2009 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.
4
5
6 // Windows Timer Primer
7 //
8 // A good article: http://www.ddj.com/windows/184416651
9 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
10 //
11 // The default windows timer, GetSystemTimeAsFileTime is not very precise.
12 // It is only good to ~15.5ms.
13 //
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.
20 //
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
29 //
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.
36
37 #include "base/time.h"
38
39 #pragma comment(lib, "winmm.lib")
40 #include <windows.h>
41 #include <mmsystem.h>
42
43 #include "base/basictypes.h"
44 #include "base/lock.h"
45 #include "base/logging.h"
46 #include "base/cpu.h"
47 #include "base/singleton.h"
48
49 using base::Time;
50 using base::TimeDelta;
51 using base::TimeTicks;
52
53 namespace {
54
55 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
56 // 100-nanosecond intervals since January 1, 1601 (UTC)."
FileTimeToMicroseconds(const FILETIME & ft)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
60 // machines.
61 return bit_cast<int64, FILETIME>(ft) / 10;
62 }
63
MicrosecondsToFileTime(int64 us,FILETIME * ft)64 void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
65 DCHECK(us >= 0) << "Time is less than 0, negative values are not "
66 "representable in FILETIME";
67
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);
71 }
72
CurrentWallclockMicroseconds()73 int64 CurrentWallclockMicroseconds() {
74 FILETIME ft;
75 ::GetSystemTimeAsFileTime(&ft);
76 return FileTimeToMicroseconds(ft);
77 }
78
79 // Time between resampling the un-granular clock for this API. 60 seconds.
80 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
81
82 int64 initial_time = 0;
83 TimeTicks initial_ticks;
84
InitializeClock()85 void InitializeClock() {
86 initial_ticks = TimeTicks::Now();
87 initial_time = CurrentWallclockMicroseconds();
88 }
89
90 } // namespace
91
92 // Time -----------------------------------------------------------------------
93
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.
98 // static
99 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
100
101 // static
Now()102 Time Time::Now() {
103 if (initial_time == 0)
104 InitializeClock();
105
106 // We implement time using the high-resolution timers so that we can get
107 // timeouts which are smaller than 10-15ms. If we just used
108 // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
109 //
110 // To make this work, we initialize the clock (initial_time) and the
111 // counter (initial_ctr). To compute the initial time, we can check
112 // the number of ticks that have elapsed, and compute the delta.
113 //
114 // To avoid any drift, we periodically resync the counters to the system
115 // clock.
116 while (true) {
117 TimeTicks ticks = TimeTicks::Now();
118
119 // Calculate the time elapsed since we started our timer
120 TimeDelta elapsed = ticks - initial_ticks;
121
122 // Check if enough time has elapsed that we need to resync the clock.
123 if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
124 InitializeClock();
125 continue;
126 }
127
128 return Time(elapsed + Time(initial_time));
129 }
130 }
131
132 // static
NowFromSystemTime()133 Time Time::NowFromSystemTime() {
134 // Force resync.
135 InitializeClock();
136 return Time(initial_time);
137 }
138
139 // static
FromFileTime(FILETIME ft)140 Time Time::FromFileTime(FILETIME ft) {
141 return Time(FileTimeToMicroseconds(ft));
142 }
143
ToFileTime() const144 FILETIME Time::ToFileTime() const {
145 FILETIME utc_ft;
146 MicrosecondsToFileTime(us_, &utc_ft);
147 return utc_ft;
148 }
149
150 // static
UseHighResolutionTimer(bool use)151 bool Time::UseHighResolutionTimer(bool use) {
152 // TODO(mbelshe): Make sure that switching the system timer resolution
153 // doesn't break Timer firing order etc. An example test would be to have
154 // two threads. One would have a bunch of timers, and another would turn the
155 // high resolution timer on and off.
156
157 MMRESULT result;
158 if (use)
159 result = timeBeginPeriod(1);
160 else
161 result = timeEndPeriod(1);
162 return (result == TIMERR_NOERROR);
163 }
164
165 // static
FromExploded(bool is_local,const Exploded & exploded)166 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
167 // Create the system struct representing our exploded time. It will either be
168 // in local time or UTC.
169 SYSTEMTIME st;
170 st.wYear = exploded.year;
171 st.wMonth = exploded.month;
172 st.wDayOfWeek = exploded.day_of_week;
173 st.wDay = exploded.day_of_month;
174 st.wHour = exploded.hour;
175 st.wMinute = exploded.minute;
176 st.wSecond = exploded.second;
177 st.wMilliseconds = exploded.millisecond;
178
179 // Convert to FILETIME.
180 FILETIME ft;
181 if (!SystemTimeToFileTime(&st, &ft)) {
182 NOTREACHED() << "Unable to convert time";
183 return Time(0);
184 }
185
186 // Ensure that it's in UTC.
187 if (is_local) {
188 FILETIME utc_ft;
189 LocalFileTimeToFileTime(&ft, &utc_ft);
190 return Time(FileTimeToMicroseconds(utc_ft));
191 }
192 return Time(FileTimeToMicroseconds(ft));
193 }
194
Explode(bool is_local,Exploded * exploded) const195 void Time::Explode(bool is_local, Exploded* exploded) const {
196 // FILETIME in UTC.
197 FILETIME utc_ft;
198 MicrosecondsToFileTime(us_, &utc_ft);
199
200 // FILETIME in local time if necessary.
201 BOOL success = TRUE;
202 FILETIME ft;
203 if (is_local)
204 success = FileTimeToLocalFileTime(&utc_ft, &ft);
205 else
206 ft = utc_ft;
207
208 // FILETIME in SYSTEMTIME (exploded).
209 SYSTEMTIME st;
210 if (!success || !FileTimeToSystemTime(&ft, &st)) {
211 NOTREACHED() << "Unable to convert time, don't know why";
212 ZeroMemory(exploded, sizeof(exploded));
213 return;
214 }
215
216 exploded->year = st.wYear;
217 exploded->month = st.wMonth;
218 exploded->day_of_week = st.wDayOfWeek;
219 exploded->day_of_month = st.wDay;
220 exploded->hour = st.wHour;
221 exploded->minute = st.wMinute;
222 exploded->second = st.wSecond;
223 exploded->millisecond = st.wMilliseconds;
224 }
225
226 // TimeTicks ------------------------------------------------------------------
227 namespace {
228
229 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
230 // mock function, and to avoid a static constructor. Assigning an import to a
231 // function pointer directly would require setup code to fetch from the IAT.
timeGetTimeWrapper()232 DWORD timeGetTimeWrapper() {
233 return timeGetTime();
234 }
235
236
237 DWORD (*tick_function)(void) = &timeGetTimeWrapper;
238
239 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
240 // because it returns the number of milliseconds since Windows has started,
241 // which will roll over the 32-bit value every ~49 days. We try to track
242 // rollover ourselves, which works if TimeTicks::Now() is called at least every
243 // 49 days.
244 class NowSingleton {
245 public:
NowSingleton()246 NowSingleton()
247 : rollover_(TimeDelta::FromMilliseconds(0)),
248 last_seen_(0) {
249 }
250
~NowSingleton()251 ~NowSingleton() {
252 }
253
Now()254 TimeDelta Now() {
255 AutoLock locked(lock_);
256 // We should hold the lock while calling tick_function to make sure that
257 // we keep our last_seen_ stay correctly in sync.
258 DWORD now = tick_function();
259 if (now < last_seen_)
260 rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days.
261 last_seen_ = now;
262 return TimeDelta::FromMilliseconds(now) + rollover_;
263 }
264
265 private:
266 Lock lock_; // To protected last_seen_ and rollover_.
267 TimeDelta rollover_; // Accumulation of time lost due to rollover.
268 DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover.
269
270 DISALLOW_COPY_AND_ASSIGN(NowSingleton);
271 };
272
273 // Overview of time counters:
274 // (1) CPU cycle counter. (Retrieved via RDTSC)
275 // The CPU counter provides the highest resolution time stamp and is the least
276 // expensive to retrieve. However, the CPU counter is unreliable and should not
277 // be used in production. Its biggest issue is that it is per processor and it
278 // is not synchronized between processors. Also, on some computers, the counters
279 // will change frequency due to thermal and power changes, and stop in some
280 // states.
281 //
282 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
283 // resolution (100 nanoseconds) time stamp but is comparatively more expensive
284 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
285 // (with some help from ACPI).
286 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
287 // in the worst case, it gets the counter from the rollover interrupt on the
288 // programmable interrupt timer. In best cases, the HAL may conclude that the
289 // RDTSC counter runs at a constant frequency, then it uses that instead. On
290 // multiprocessor machines, it will try to verify the values returned from
291 // RDTSC on each processor are consistent with each other, and apply a handful
292 // of workarounds for known buggy hardware. In other words, QPC is supposed to
293 // give consistent result on a multiprocessor computer, but it is unreliable in
294 // reality due to bugs in BIOS or HAL on some, especially old computers.
295 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
296 // it should be used with caution.
297 //
298 // (3) System time. The system time provides a low-resolution (typically 10ms
299 // to 55 milliseconds) time stamp but is comparatively less expensive to
300 // retrieve and more reliable.
301 class HighResNowSingleton {
302 public:
HighResNowSingleton()303 HighResNowSingleton()
304 : ticks_per_microsecond_(0.0),
305 skew_(0) {
306 InitializeClock();
307
308 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
309 // unreliable. Fallback to low-res clock.
310 base::CPU cpu;
311 if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15)
312 DisableHighResClock();
313 }
314
IsUsingHighResClock()315 bool IsUsingHighResClock() {
316 return ticks_per_microsecond_ != 0.0;
317 }
318
DisableHighResClock()319 void DisableHighResClock() {
320 ticks_per_microsecond_ = 0.0;
321 }
322
Now()323 TimeDelta Now() {
324 // Our maximum tolerance for QPC drifting.
325 const int kMaxTimeDrift = 50 * Time::kMicrosecondsPerMillisecond;
326
327 if (IsUsingHighResClock()) {
328 int64 now = UnreliableNow();
329
330 // Verify that QPC does not seem to drift.
331 DCHECK(now - ReliableNow() - skew_ < kMaxTimeDrift);
332
333 return TimeDelta::FromMicroseconds(now);
334 }
335
336 // Just fallback to the slower clock.
337 return Singleton<NowSingleton>::get()->Now();
338 }
339
340 private:
341 // Synchronize the QPC clock with GetSystemTimeAsFileTime.
InitializeClock()342 void InitializeClock() {
343 LARGE_INTEGER ticks_per_sec = {0};
344 if (!QueryPerformanceFrequency(&ticks_per_sec))
345 return; // Broken, we don't guarantee this function works.
346 ticks_per_microsecond_ = static_cast<float>(ticks_per_sec.QuadPart) /
347 static_cast<float>(Time::kMicrosecondsPerSecond);
348
349 skew_ = UnreliableNow() - ReliableNow();
350 }
351
352 // Get the number of microseconds since boot in a reliable fashion
UnreliableNow()353 int64 UnreliableNow() {
354 LARGE_INTEGER now;
355 QueryPerformanceCounter(&now);
356 return static_cast<int64>(now.QuadPart / ticks_per_microsecond_);
357 }
358
359 // Get the number of microseconds since boot in a reliable fashion
ReliableNow()360 int64 ReliableNow() {
361 return Singleton<NowSingleton>::get()->Now().InMicroseconds();
362 }
363
364 // Cached clock frequency -> microseconds. This assumes that the clock
365 // frequency is faster than one microsecond (which is 1MHz, should be OK).
366 float ticks_per_microsecond_; // 0 indicates QPF failed and we're broken.
367 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging).
368
369 DISALLOW_COPY_AND_ASSIGN(HighResNowSingleton);
370 };
371
372 } // namespace
373
374 // static
SetMockTickFunction(TickFunctionType ticker)375 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
376 TickFunctionType ticker) {
377 TickFunctionType old = tick_function;
378 tick_function = ticker;
379 return old;
380 }
381
382 // static
Now()383 TimeTicks TimeTicks::Now() {
384 return TimeTicks() + Singleton<NowSingleton>::get()->Now();
385 }
386
387 // static
HighResNow()388 TimeTicks TimeTicks::HighResNow() {
389 return TimeTicks() + Singleton<HighResNowSingleton>::get()->Now();
390 }
391