1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6
7 // Windows Timer Primer
8 //
9 // A good article: http://www.ddj.com/windows/184416651
10 // A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
11 //
12 // The default windows timer, GetSystemTimeAsFileTime is not very precise.
13 // It is only good to ~15.5ms.
14 //
15 // QueryPerformanceCounter is the logical choice for a high-precision timer.
16 // However, it is known to be buggy on some hardware. Specifically, it can
17 // sometimes "jump". On laptops, QPC can also be very expensive to call.
18 // It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
19 // on laptops. A unittest exists which will show the relative cost of various
20 // timers on any system.
21 //
22 // The next logical choice is timeGetTime(). timeGetTime has a precision of
23 // 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
24 // applications on the system. By default, precision is only 15.5ms.
25 // Unfortunately, we don't want to call timeBeginPeriod because we don't
26 // want to affect other applications. Further, on mobile platforms, use of
27 // faster multimedia timers can hurt battery life. See the intel
28 // article about this here:
29 // http://softwarecommunity.intel.com/articles/eng/1086.htm
30 //
31 // To work around all this, we're going to generally use timeGetTime(). We
32 // will only increase the system-wide timer if we're not running on battery
33 // power. Using timeBeginPeriod(1) is a requirement in order to make our
34 // message loop waits have the same resolution that our time measurements
35 // do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
36 // there is nothing else to waken the Wait.
37
38 #include "base/time.h"
39
40 #ifndef __MINGW32__
41 # pragma comment(lib, "winmm.lib")
42 #endif
43 #include <windows.h>
44 #include <mmsystem.h>
45
46 #include "base/basictypes.h"
47 #include "base/logging.h"
48 #include "mozilla/Casting.h"
49 #include "mozilla/StaticMutex.h"
50
51 using base::Time;
52 using base::TimeDelta;
53 using base::TimeTicks;
54 using mozilla::BitwiseCast;
55
56 namespace {
57
58 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
59 // 100-nanosecond intervals since January 1, 1601 (UTC)."
FileTimeToMicroseconds(const FILETIME & ft)60 int64_t FileTimeToMicroseconds(const FILETIME& ft) {
61 // Need to BitwiseCast to fix alignment, then divide by 10 to convert
62 // 100-nanoseconds to milliseconds. This only works on little-endian
63 // machines.
64 return BitwiseCast<int64_t>(ft) / 10;
65 }
66
MicrosecondsToFileTime(int64_t us,FILETIME * ft)67 void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
68 DCHECK(us >= 0) << "Time is less than 0, negative values are not "
69 "representable in FILETIME";
70
71 // Multiply by 10 to convert milliseconds to 100-nanoseconds. BitwiseCast will
72 // handle alignment problems. This only works on little-endian machines.
73 *ft = BitwiseCast<FILETIME>(us * 10);
74 }
75
CurrentWallclockMicroseconds()76 int64_t CurrentWallclockMicroseconds() {
77 FILETIME ft;
78 ::GetSystemTimeAsFileTime(&ft);
79 return FileTimeToMicroseconds(ft);
80 }
81
82 // Time between resampling the un-granular clock for this API. 60 seconds.
83 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
84
85 int64_t initial_time = 0;
86 TimeTicks initial_ticks;
87
InitializeClock()88 void InitializeClock() {
89 initial_ticks = TimeTicks::Now();
90 initial_time = CurrentWallclockMicroseconds();
91 }
92
93 } // namespace
94
95 // Time -----------------------------------------------------------------------
96
97 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
98 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
99 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
100 // 1700, 1800, and 1900.
101 // static
102 const int64_t Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
103
104 // static
Now()105 Time Time::Now() {
106 if (initial_time == 0) InitializeClock();
107
108 // We implement time using the high-resolution timers so that we can get
109 // timeouts which are smaller than 10-15ms. If we just used
110 // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
111 //
112 // To make this work, we initialize the clock (initial_time) and the
113 // counter (initial_ctr). To compute the initial time, we can check
114 // the number of ticks that have elapsed, and compute the delta.
115 //
116 // To avoid any drift, we periodically resync the counters to the system
117 // clock.
118 while (true) {
119 TimeTicks ticks = TimeTicks::Now();
120
121 // Calculate the time elapsed since we started our timer
122 TimeDelta elapsed = ticks - initial_ticks;
123
124 // Check if enough time has elapsed that we need to resync the clock.
125 if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
126 InitializeClock();
127 continue;
128 }
129
130 return Time(elapsed + Time(initial_time));
131 }
132 }
133
134 // static
NowFromSystemTime()135 Time Time::NowFromSystemTime() {
136 // Force resync.
137 InitializeClock();
138 return Time(initial_time);
139 }
140
141 // static
FromExploded(bool is_local,const Exploded & exploded)142 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
143 // Create the system struct representing our exploded time. It will either be
144 // in local time or UTC.
145 SYSTEMTIME st;
146 st.wYear = exploded.year;
147 st.wMonth = exploded.month;
148 st.wDayOfWeek = exploded.day_of_week;
149 st.wDay = exploded.day_of_month;
150 st.wHour = exploded.hour;
151 st.wMinute = exploded.minute;
152 st.wSecond = exploded.second;
153 st.wMilliseconds = exploded.millisecond;
154
155 // Convert to FILETIME.
156 FILETIME ft;
157 if (!SystemTimeToFileTime(&st, &ft)) {
158 NOTREACHED() << "Unable to convert time";
159 return Time(0);
160 }
161
162 // Ensure that it's in UTC.
163 if (is_local) {
164 FILETIME utc_ft;
165 LocalFileTimeToFileTime(&ft, &utc_ft);
166 return Time(FileTimeToMicroseconds(utc_ft));
167 }
168 return Time(FileTimeToMicroseconds(ft));
169 }
170
Explode(bool is_local,Exploded * exploded) const171 void Time::Explode(bool is_local, Exploded* exploded) const {
172 // FILETIME in UTC.
173 FILETIME utc_ft;
174 MicrosecondsToFileTime(us_, &utc_ft);
175
176 // FILETIME in local time if necessary.
177 BOOL success = TRUE;
178 FILETIME ft;
179 if (is_local)
180 success = FileTimeToLocalFileTime(&utc_ft, &ft);
181 else
182 ft = utc_ft;
183
184 // FILETIME in SYSTEMTIME (exploded).
185 SYSTEMTIME st;
186 if (!success || !FileTimeToSystemTime(&ft, &st)) {
187 NOTREACHED() << "Unable to convert time, don't know why";
188 ZeroMemory(exploded, sizeof(*exploded));
189 return;
190 }
191
192 exploded->year = st.wYear;
193 exploded->month = st.wMonth;
194 exploded->day_of_week = st.wDayOfWeek;
195 exploded->day_of_month = st.wDay;
196 exploded->hour = st.wHour;
197 exploded->minute = st.wMinute;
198 exploded->second = st.wSecond;
199 exploded->millisecond = st.wMilliseconds;
200 }
201
202 // TimeTicks ------------------------------------------------------------------
203 namespace {
204
205 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
206 // mock function, and to avoid a static constructor. Assigning an import to a
207 // function pointer directly would require setup code to fetch from the IAT.
timeGetTimeWrapper()208 DWORD timeGetTimeWrapper() { return timeGetTime(); }
209
210 DWORD (*tick_function)(void) = &timeGetTimeWrapper;
211
212 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
213 // because it returns the number of milliseconds since Windows has started,
214 // which will roll over the 32-bit value every ~49 days. We try to track
215 // rollover ourselves, which works if TimeTicks::Now() is called at least every
216 // 49 days.
217 class NowSingleton {
218 public:
Now()219 TimeDelta Now() {
220 mozilla::StaticMutexAutoLock locked(lock_);
221 // We should hold the lock while calling tick_function to make sure that
222 // we keep our last_seen_ stay correctly in sync.
223 DWORD now = tick_function();
224 if (now < last_seen_)
225 rollover_ +=
226 TimeDelta::FromMilliseconds(GG_LONGLONG(0x100000000)); // ~49.7 days.
227 last_seen_ = now;
228 return TimeDelta::FromMilliseconds(now) + rollover_;
229 }
230
instance()231 static NowSingleton& instance() {
232 // This setup is a little gross: the `now` instance lives until libxul is
233 // unloaded, but leak checking runs prior to that, and would see a Mutex
234 // instance contained in NowSingleton as still live. Said instance would
235 // be reported as a leak...but it's not, really. To avoid that, we need
236 // to use StaticMutex (which is not leak-checked), but StaticMutex can't
237 // be a member variable. So we have to have this separate variable and
238 // pass it into the NowSingleton constructor.
239 static mozilla::StaticMutex mutex;
240 static NowSingleton now(mutex);
241 return now;
242 }
243
244 private:
NowSingleton(mozilla::StaticMutex & aMutex)245 explicit NowSingleton(mozilla::StaticMutex& aMutex)
246 : lock_(aMutex),
247 rollover_(TimeDelta::FromMilliseconds(0)),
248 last_seen_(0) {}
249 ~NowSingleton() = default;
250
251 mozilla::StaticMutex& lock_; // To protected last_seen_ and rollover_.
252 TimeDelta rollover_; // Accumulation of time lost due to rollover.
253 DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover.
254
255 DISALLOW_COPY_AND_ASSIGN(NowSingleton);
256 };
257
258 } // namespace
259
260 // static
Now()261 TimeTicks TimeTicks::Now() {
262 return TimeTicks() + NowSingleton::instance().Now();
263 }
264