OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 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 |
5 #include "base/time.h" | 37 #include "base/time.h" |
6 | 38 |
7 #pragma comment(lib, "winmm.lib") | 39 #pragma comment(lib, "winmm.lib") |
8 #include <windows.h> | 40 #include <windows.h> |
9 #include <mmsystem.h> | 41 #include <mmsystem.h> |
10 | 42 |
11 #include "base/basictypes.h" | 43 #include "base/basictypes.h" |
12 #include "base/lock.h" | 44 #include "base/lock.h" |
13 #include "base/logging.h" | 45 #include "base/logging.h" |
| 46 #include "base/cpu.h" |
14 #include "base/singleton.h" | 47 #include "base/singleton.h" |
| 48 #include "base/system_monitor.h" |
15 | 49 |
16 namespace { | 50 namespace { |
17 | 51 |
18 // From MSDN, FILETIME "Contains a 64-bit value representing the number of | 52 // From MSDN, FILETIME "Contains a 64-bit value representing the number of |
19 // 100-nanosecond intervals since January 1, 1601 (UTC)." | 53 // 100-nanosecond intervals since January 1, 1601 (UTC)." |
20 int64 FileTimeToMicroseconds(const FILETIME& ft) { | 54 int64 FileTimeToMicroseconds(const FILETIME& ft) { |
21 // Need to bit_cast to fix alignment, then divide by 10 to convert | 55 // Need to bit_cast to fix alignment, then divide by 10 to convert |
22 // 100-nanoseconds to milliseconds. This only works on little-endian | 56 // 100-nanoseconds to milliseconds. This only works on little-endian |
23 // machines. | 57 // machines. |
24 return bit_cast<int64, FILETIME>(ft) / 10; | 58 return bit_cast<int64, FILETIME>(ft) / 10; |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 // TimeTicks ------------------------------------------------------------------ | 201 // TimeTicks ------------------------------------------------------------------ |
168 namespace { | 202 namespace { |
169 | 203 |
170 // We define a wrapper to adapt between the __stdcall and __cdecl call of the | 204 // We define a wrapper to adapt between the __stdcall and __cdecl call of the |
171 // mock function, and to avoid a static constructor. Assigning an import to a | 205 // mock function, and to avoid a static constructor. Assigning an import to a |
172 // function pointer directly would require setup code to fetch from the IAT. | 206 // function pointer directly would require setup code to fetch from the IAT. |
173 DWORD timeGetTimeWrapper() { | 207 DWORD timeGetTimeWrapper() { |
174 return timeGetTime(); | 208 return timeGetTime(); |
175 } | 209 } |
176 | 210 |
| 211 |
177 DWORD (*tick_function)(void) = &timeGetTimeWrapper; | 212 DWORD (*tick_function)(void) = &timeGetTimeWrapper; |
178 | 213 |
179 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic | 214 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic |
180 // because it returns the number of milliseconds since Windows has started, | 215 // because it returns the number of milliseconds since Windows has started, |
181 // which will roll over the 32-bit value every ~49 days. We try to track | 216 // which will roll over the 32-bit value every ~49 days. We try to track |
182 // rollover ourselves, which works if TimeTicks::Now() is called at least every | 217 // rollover ourselves, which works if TimeTicks::Now() is called at least every |
183 // 49 days. | 218 // 49 days. |
184 class NowSingleton { | 219 class NowSingleton : public base::SystemMonitor::PowerObserver { |
185 public: | 220 public: |
186 NowSingleton() | 221 NowSingleton() |
187 : rollover_(TimeDelta::FromMilliseconds(0)), last_seen_(0) { | 222 : rollover_(TimeDelta::FromMilliseconds(0)), |
188 // Request a resolution of 1ms from timeGetTime(). This can have some | 223 last_seen_(0), |
189 // consequences on other applications (see MSDN), but we've found that it | 224 hi_res_clock_enabled_(false) { |
190 // is very common in other applications (Flash, Media Player, etc), so it | 225 base::SystemMonitor* system = base::SystemMonitor::Get(); |
191 // is not really a dangerous thing to do. We need this because the default | 226 system->AddObserver(this); |
192 // resolution of ~15ms is much too low for accurate timing and timers. | 227 UseHiResClock(!system->BatteryPower()); |
193 ::timeBeginPeriod(1); | |
194 } | 228 } |
195 | 229 |
196 ~NowSingleton() { | 230 ~NowSingleton() { |
197 ::timeEndPeriod(1); | 231 UseHiResClock(false); |
| 232 base::SystemMonitor::Get()->RemoveObserver(this); |
198 } | 233 } |
199 | 234 |
200 TimeDelta Now() { | 235 TimeDelta Now() { |
201 AutoLock locked(lock_); | 236 AutoLock locked(lock_); |
202 // We should hold the lock while calling tick_function to make sure that | 237 // We should hold the lock while calling tick_function to make sure that |
203 // we keep our last_seen_ stay correctly in sync. | 238 // we keep our last_seen_ stay correctly in sync. |
204 DWORD now = tick_function(); | 239 DWORD now = tick_function(); |
205 if (now < last_seen_) | 240 if (now < last_seen_) |
206 rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days. | 241 rollover_ += TimeDelta::FromMilliseconds(0x100000000I64); // ~49.7 days. |
207 last_seen_ = now; | 242 last_seen_ = now; |
208 return TimeDelta::FromMilliseconds(now) + rollover_; | 243 return TimeDelta::FromMilliseconds(now) + rollover_; |
209 } | 244 } |
210 | 245 |
| 246 // Interfaces for monitoring Power changes. |
| 247 void OnPowerStateChange(base::SystemMonitor* system) { |
| 248 UseHiResClock(!system->BatteryPower()); |
| 249 } |
| 250 |
| 251 void OnSuspend(base::SystemMonitor* system) {} |
| 252 void OnResume(base::SystemMonitor* system) {} |
| 253 |
211 private: | 254 private: |
| 255 // Enable or disable the faster multimedia timer. |
| 256 void UseHiResClock(bool enabled) { |
| 257 if (enabled == hi_res_clock_enabled_) |
| 258 return; |
| 259 if (enabled) |
| 260 timeBeginPeriod(1); |
| 261 else |
| 262 timeEndPeriod(1); |
| 263 hi_res_clock_enabled_ = enabled; |
| 264 } |
| 265 |
212 Lock lock_; // To protected last_seen_ and rollover_. | 266 Lock lock_; // To protected last_seen_ and rollover_. |
213 TimeDelta rollover_; // Accumulation of time lost due to rollover. | 267 TimeDelta rollover_; // Accumulation of time lost due to rollover. |
214 DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover. | 268 DWORD last_seen_; // The last timeGetTime value we saw, to detect rollover. |
| 269 bool hi_res_clock_enabled_; |
215 | 270 |
216 DISALLOW_COPY_AND_ASSIGN(NowSingleton); | 271 DISALLOW_COPY_AND_ASSIGN(NowSingleton); |
217 }; | 272 }; |
218 | 273 |
219 // Overview of time counters: | 274 // Overview of time counters: |
220 // (1) CPU cycle counter. (Retrieved via RDTSC) | 275 // (1) CPU cycle counter. (Retrieved via RDTSC) |
221 // The CPU counter provides the highest resolution time stamp and is the least | 276 // The CPU counter provides the highest resolution time stamp and is the least |
222 // expensive to retrieve. However, the CPU counter is unreliable and should not | 277 // expensive to retrieve. However, the CPU counter is unreliable and should not |
223 // be used in production. Its biggest issue is that it is per processor and it | 278 // be used in production. Its biggest issue is that it is per processor and it |
224 // is not synchronized between processors. Also, on some computers, the counters | 279 // is not synchronized between processors. Also, on some computers, the counters |
(...skipping 12 matching lines...) Expand all Loading... |
237 // RDTSC on each processor are consistent with each other, and apply a handful | 292 // RDTSC on each processor are consistent with each other, and apply a handful |
238 // of workarounds for known buggy hardware. In other words, QPC is supposed to | 293 // of workarounds for known buggy hardware. In other words, QPC is supposed to |
239 // give consistent result on a multiprocessor computer, but it is unreliable in | 294 // give consistent result on a multiprocessor computer, but it is unreliable in |
240 // reality due to bugs in BIOS or HAL on some, especially old computers. | 295 // reality due to bugs in BIOS or HAL on some, especially old computers. |
241 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but | 296 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but |
242 // it should be used with caution. | 297 // it should be used with caution. |
243 // | 298 // |
244 // (3) System time. The system time provides a low-resolution (typically 10ms | 299 // (3) System time. The system time provides a low-resolution (typically 10ms |
245 // to 55 milliseconds) time stamp but is comparatively less expensive to | 300 // to 55 milliseconds) time stamp but is comparatively less expensive to |
246 // retrieve and more reliable. | 301 // retrieve and more reliable. |
247 class UnreliableHighResNowSingleton { | 302 class HighResNowSingleton { |
248 public: | 303 public: |
249 UnreliableHighResNowSingleton() : ticks_per_microsecond_(0) { | 304 HighResNowSingleton() |
| 305 : ticks_per_microsecond_(0.0), |
| 306 skew_(0) { |
| 307 InitializeClock(); |
| 308 |
| 309 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is |
| 310 // unreliable. Fallback to low-res clock. |
| 311 base::CPU cpu; |
| 312 if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15) |
| 313 DisableHighResClock(); |
| 314 } |
| 315 |
| 316 bool IsUsingHighResClock() { |
| 317 return ticks_per_microsecond_ != 0.0; |
| 318 } |
| 319 |
| 320 void DisableHighResClock() { |
| 321 ticks_per_microsecond_ = 0.0; |
| 322 } |
| 323 |
| 324 TimeDelta Now() { |
| 325 // Our maximum tolerance for QPC drifting. |
| 326 const int kMaxTimeDrift = 50 * Time::kMicrosecondsPerMillisecond; |
| 327 |
| 328 if (IsUsingHighResClock()) { |
| 329 int64 now = UnreliableNow(); |
| 330 |
| 331 // Verify that QPC does not seem to drift. |
| 332 DCHECK(now - ReliableNow() - skew_ < kMaxTimeDrift); |
| 333 |
| 334 return TimeDelta::FromMicroseconds(now); |
| 335 } |
| 336 |
| 337 // Just fallback to the slower clock. |
| 338 return Singleton<NowSingleton>::get()->Now(); |
| 339 } |
| 340 |
| 341 private: |
| 342 // Synchronize the QPC clock with GetSystemTimeAsFileTime. |
| 343 void InitializeClock() { |
250 LARGE_INTEGER ticks_per_sec = {0}; | 344 LARGE_INTEGER ticks_per_sec = {0}; |
251 if (!QueryPerformanceFrequency(&ticks_per_sec)) | 345 if (!QueryPerformanceFrequency(&ticks_per_sec)) |
252 return; // Broken, we don't guarantee this function works. | 346 return; // Broken, we don't guarantee this function works. |
253 ticks_per_microsecond_ = | 347 ticks_per_microsecond_ = static_cast<float>(ticks_per_sec.QuadPart) / |
254 ticks_per_sec.QuadPart / Time::kMicrosecondsPerSecond; | 348 static_cast<float>(Time::kMicrosecondsPerSecond); |
| 349 |
| 350 skew_ = UnreliableNow() - ReliableNow(); |
255 } | 351 } |
256 | 352 |
257 bool IsBroken() { | 353 // Get the number of microseconds since boot in a reliable fashion |
258 return ticks_per_microsecond_ == 0; | 354 int64 UnreliableNow() { |
| 355 LARGE_INTEGER now; |
| 356 QueryPerformanceCounter(&now); |
| 357 return static_cast<int64>(now.QuadPart / ticks_per_microsecond_); |
259 } | 358 } |
260 | 359 |
261 TimeDelta Now() { | 360 // Get the number of microseconds since boot in a reliable fashion |
262 LARGE_INTEGER now; | 361 int64 ReliableNow() { |
263 QueryPerformanceCounter(&now); | 362 return Singleton<NowSingleton>::get()->Now().InMicroseconds(); |
264 return TimeDelta::FromMicroseconds(now.QuadPart / ticks_per_microsecond_); | |
265 } | 363 } |
266 | 364 |
267 private: | |
268 // Cached clock frequency -> microseconds. This assumes that the clock | 365 // Cached clock frequency -> microseconds. This assumes that the clock |
269 // frequency is faster than one microsecond (which is 1MHz, should be OK). | 366 // frequency is faster than one microsecond (which is 1MHz, should be OK). |
270 int64 ticks_per_microsecond_; // 0 indicates QPF failed and we're broken. | 367 float ticks_per_microsecond_; // 0 indicates QPF failed and we're broken. |
| 368 int64 skew_; // Skew between lo-res and hi-res clocks (for debugging). |
271 | 369 |
272 DISALLOW_COPY_AND_ASSIGN(UnreliableHighResNowSingleton); | 370 DISALLOW_COPY_AND_ASSIGN(HighResNowSingleton); |
273 }; | 371 }; |
274 | 372 |
275 } // namespace | 373 } // namespace |
276 | 374 |
277 // static | 375 // static |
278 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( | 376 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction( |
279 TickFunctionType ticker) { | 377 TickFunctionType ticker) { |
280 TickFunctionType old = tick_function; | 378 TickFunctionType old = tick_function; |
281 tick_function = ticker; | 379 tick_function = ticker; |
282 return old; | 380 return old; |
283 } | 381 } |
284 | 382 |
285 // static | 383 // static |
286 TimeTicks TimeTicks::Now() { | 384 TimeTicks TimeTicks::Now() { |
287 return TimeTicks() + Singleton<NowSingleton>::get()->Now(); | 385 return TimeTicks() + Singleton<NowSingleton>::get()->Now(); |
288 } | 386 } |
289 | 387 |
290 // static | 388 // static |
291 TimeTicks TimeTicks::UnreliableHighResNow() { | 389 TimeTicks TimeTicks::HighResNow() { |
292 UnreliableHighResNowSingleton* now = | 390 return TimeTicks() + Singleton<HighResNowSingleton>::get()->Now(); |
293 Singleton<UnreliableHighResNowSingleton>::get(); | |
294 | |
295 if (now->IsBroken()) { | |
296 NOTREACHED() << "QueryPerformanceCounter is broken."; | |
297 return TimeTicks(0); | |
298 } | |
299 | |
300 return TimeTicks() + now->Now(); | |
301 } | 391 } |
OLD | NEW |