• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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