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.
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.
33
34 #include "base/time/time.h"
35
36 #pragma comment(lib, "winmm.lib")
37 #include <windows.h>
38 #include <mmsystem.h>
39 #include <stdint.h>
40
41 #include "base/bit_cast.h"
42 #include "base/cpu.h"
43 #include "base/lazy_instance.h"
44 #include "base/logging.h"
45 #include "base/synchronization/lock.h"
46
47 using base::ThreadTicks;
48 using base::Time;
49 using base::TimeDelta;
50 using base::TimeTicks;
51
52 namespace {
53
54 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
55 // 100-nanosecond intervals since January 1, 1601 (UTC)."
FileTimeToMicroseconds(const FILETIME & ft)56 int64_t FileTimeToMicroseconds(const FILETIME& ft) {
57 // Need to bit_cast to fix alignment, then divide by 10 to convert
58 // 100-nanoseconds to microseconds. This only works on little-endian
59 // machines.
60 return bit_cast<int64_t, FILETIME>(ft) / 10;
61 }
62
MicrosecondsToFileTime(int64_t us,FILETIME * ft)63 void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
64 DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
65 "representable in FILETIME";
66
67 // Multiply by 10 to convert microseconds to 100-nanoseconds. Bit_cast will
68 // handle alignment problems. This only works on little-endian machines.
69 *ft = bit_cast<FILETIME, int64_t>(us * 10);
70 }
71
CurrentWallclockMicroseconds()72 int64_t CurrentWallclockMicroseconds() {
73 FILETIME ft;
74 ::GetSystemTimeAsFileTime(&ft);
75 return FileTimeToMicroseconds(ft);
76 }
77
78 // Time between resampling the un-granular clock for this API. 60 seconds.
79 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
80
81 int64_t initial_time = 0;
82 TimeTicks initial_ticks;
83
InitializeClock()84 void InitializeClock() {
85 initial_ticks = TimeTicks::Now();
86 initial_time = CurrentWallclockMicroseconds();
87 }
88
89 // The two values that ActivateHighResolutionTimer uses to set the systemwide
90 // timer interrupt frequency on Windows. It controls how precise timers are
91 // but also has a big impact on battery life.
92 const int kMinTimerIntervalHighResMs = 1;
93 const int kMinTimerIntervalLowResMs = 4;
94 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active.
95 bool g_high_res_timer_enabled = false;
96 // How many times the high resolution timer has been called.
97 uint32_t g_high_res_timer_count = 0;
98 // The lock to control access to the above two variables.
99 base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
100 LAZY_INSTANCE_INITIALIZER;
101
102 // Returns a pointer to the QueryThreadCycleTime() function from Windows.
103 // Can't statically link to it because it is not available on XP.
104 using QueryThreadCycleTimePtr = decltype(::QueryThreadCycleTime)*;
GetQueryThreadCycleTimeFunction()105 QueryThreadCycleTimePtr GetQueryThreadCycleTimeFunction() {
106 static const QueryThreadCycleTimePtr query_thread_cycle_time_fn =
107 reinterpret_cast<QueryThreadCycleTimePtr>(::GetProcAddress(
108 ::GetModuleHandle(L"kernel32.dll"), "QueryThreadCycleTime"));
109 return query_thread_cycle_time_fn;
110 }
111
112 // Returns the current value of the performance counter.
QPCNowRaw()113 uint64_t QPCNowRaw() {
114 LARGE_INTEGER perf_counter_now = {};
115 // According to the MSDN documentation for QueryPerformanceCounter(), this
116 // will never fail on systems that run XP or later.
117 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
118 ::QueryPerformanceCounter(&perf_counter_now);
119 return perf_counter_now.QuadPart;
120 }
121
122 } // namespace
123
124 // Time -----------------------------------------------------------------------
125
126 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
127 // 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
128 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
129 // 1700, 1800, and 1900.
130 // static
131 const int64_t Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000);
132
133 // static
Now()134 Time Time::Now() {
135 if (initial_time == 0)
136 InitializeClock();
137
138 // We implement time using the high-resolution timers so that we can get
139 // timeouts which are smaller than 10-15ms. If we just used
140 // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
141 //
142 // To make this work, we initialize the clock (initial_time) and the
143 // counter (initial_ctr). To compute the initial time, we can check
144 // the number of ticks that have elapsed, and compute the delta.
145 //
146 // To avoid any drift, we periodically resync the counters to the system
147 // clock.
148 while (true) {
149 TimeTicks ticks = TimeTicks::Now();
150
151 // Calculate the time elapsed since we started our timer
152 TimeDelta elapsed = ticks - initial_ticks;
153
154 // Check if enough time has elapsed that we need to resync the clock.
155 if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
156 InitializeClock();
157 continue;
158 }
159
160 return Time(elapsed + Time(initial_time));
161 }
162 }
163
164 // static
NowFromSystemTime()165 Time Time::NowFromSystemTime() {
166 // Force resync.
167 InitializeClock();
168 return Time(initial_time);
169 }
170
171 // static
FromFileTime(FILETIME ft)172 Time Time::FromFileTime(FILETIME ft) {
173 if (bit_cast<int64_t, FILETIME>(ft) == 0)
174 return Time();
175 if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
176 ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
177 return Max();
178 return Time(FileTimeToMicroseconds(ft));
179 }
180
ToFileTime() const181 FILETIME Time::ToFileTime() const {
182 if (is_null())
183 return bit_cast<FILETIME, int64_t>(0);
184 if (is_max()) {
185 FILETIME result;
186 result.dwHighDateTime = std::numeric_limits<DWORD>::max();
187 result.dwLowDateTime = std::numeric_limits<DWORD>::max();
188 return result;
189 }
190 FILETIME utc_ft;
191 MicrosecondsToFileTime(us_, &utc_ft);
192 return utc_ft;
193 }
194
195 // static
EnableHighResolutionTimer(bool enable)196 void Time::EnableHighResolutionTimer(bool enable) {
197 base::AutoLock lock(g_high_res_lock.Get());
198 if (g_high_res_timer_enabled == enable)
199 return;
200 g_high_res_timer_enabled = enable;
201 if (!g_high_res_timer_count)
202 return;
203 // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true)
204 // was called which called timeBeginPeriod with g_high_res_timer_enabled
205 // with a value which is the opposite of |enable|. With that information we
206 // call timeEndPeriod with the same value used in timeBeginPeriod and
207 // therefore undo the period effect.
208 if (enable) {
209 timeEndPeriod(kMinTimerIntervalLowResMs);
210 timeBeginPeriod(kMinTimerIntervalHighResMs);
211 } else {
212 timeEndPeriod(kMinTimerIntervalHighResMs);
213 timeBeginPeriod(kMinTimerIntervalLowResMs);
214 }
215 }
216
217 // static
ActivateHighResolutionTimer(bool activating)218 bool Time::ActivateHighResolutionTimer(bool activating) {
219 // We only do work on the transition from zero to one or one to zero so we
220 // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
221 // called.
222 const uint32_t max = std::numeric_limits<uint32_t>::max();
223
224 base::AutoLock lock(g_high_res_lock.Get());
225 UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
226 : kMinTimerIntervalLowResMs;
227 if (activating) {
228 DCHECK_NE(g_high_res_timer_count, max);
229 ++g_high_res_timer_count;
230 if (g_high_res_timer_count == 1)
231 timeBeginPeriod(period);
232 } else {
233 DCHECK_NE(g_high_res_timer_count, 0u);
234 --g_high_res_timer_count;
235 if (g_high_res_timer_count == 0)
236 timeEndPeriod(period);
237 }
238 return (period == kMinTimerIntervalHighResMs);
239 }
240
241 // static
IsHighResolutionTimerInUse()242 bool Time::IsHighResolutionTimerInUse() {
243 base::AutoLock lock(g_high_res_lock.Get());
244 return g_high_res_timer_enabled && g_high_res_timer_count > 0;
245 }
246
247 // static
FromExploded(bool is_local,const Exploded & exploded)248 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
249 // Create the system struct representing our exploded time. It will either be
250 // in local time or UTC.
251 SYSTEMTIME st;
252 st.wYear = static_cast<WORD>(exploded.year);
253 st.wMonth = static_cast<WORD>(exploded.month);
254 st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week);
255 st.wDay = static_cast<WORD>(exploded.day_of_month);
256 st.wHour = static_cast<WORD>(exploded.hour);
257 st.wMinute = static_cast<WORD>(exploded.minute);
258 st.wSecond = static_cast<WORD>(exploded.second);
259 st.wMilliseconds = static_cast<WORD>(exploded.millisecond);
260
261 FILETIME ft;
262 bool success = true;
263 // Ensure that it's in UTC.
264 if (is_local) {
265 SYSTEMTIME utc_st;
266 success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) &&
267 SystemTimeToFileTime(&utc_st, &ft);
268 } else {
269 success = !!SystemTimeToFileTime(&st, &ft);
270 }
271
272 if (!success) {
273 NOTREACHED() << "Unable to convert time";
274 return Time(0);
275 }
276 return Time(FileTimeToMicroseconds(ft));
277 }
278
Explode(bool is_local,Exploded * exploded) const279 void Time::Explode(bool is_local, Exploded* exploded) const {
280 if (us_ < 0LL) {
281 // We are not able to convert it to FILETIME.
282 ZeroMemory(exploded, sizeof(*exploded));
283 return;
284 }
285
286 // FILETIME in UTC.
287 FILETIME utc_ft;
288 MicrosecondsToFileTime(us_, &utc_ft);
289
290 // FILETIME in local time if necessary.
291 bool success = true;
292 // FILETIME in SYSTEMTIME (exploded).
293 SYSTEMTIME st = {0};
294 if (is_local) {
295 SYSTEMTIME utc_st;
296 // We don't use FileTimeToLocalFileTime here, since it uses the current
297 // settings for the time zone and daylight saving time. Therefore, if it is
298 // daylight saving time, it will take daylight saving time into account,
299 // even if the time you are converting is in standard time.
300 success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
301 SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st);
302 } else {
303 success = !!FileTimeToSystemTime(&utc_ft, &st);
304 }
305
306 if (!success) {
307 NOTREACHED() << "Unable to convert time, don't know why";
308 ZeroMemory(exploded, sizeof(*exploded));
309 return;
310 }
311
312 exploded->year = st.wYear;
313 exploded->month = st.wMonth;
314 exploded->day_of_week = st.wDayOfWeek;
315 exploded->day_of_month = st.wDay;
316 exploded->hour = st.wHour;
317 exploded->minute = st.wMinute;
318 exploded->second = st.wSecond;
319 exploded->millisecond = st.wMilliseconds;
320 }
321
322 // TimeTicks ------------------------------------------------------------------
323 namespace {
324
325 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
326 // mock function, and to avoid a static constructor. Assigning an import to a
327 // function pointer directly would require setup code to fetch from the IAT.
timeGetTimeWrapper()328 DWORD timeGetTimeWrapper() {
329 return timeGetTime();
330 }
331
332 DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
333
334 // Accumulation of time lost due to rollover (in milliseconds).
335 int64_t g_rollover_ms = 0;
336
337 // The last timeGetTime value we saw, to detect rollover.
338 DWORD g_last_seen_now = 0;
339
340 // Lock protecting rollover_ms and last_seen_now.
341 // Note: this is a global object, and we usually avoid these. However, the time
342 // code is low-level, and we don't want to use Singletons here (it would be too
343 // easy to use a Singleton without even knowing it, and that may lead to many
344 // gotchas). Its impact on startup time should be negligible due to low-level
345 // nature of time code.
346 base::Lock g_rollover_lock;
347
348 // We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
349 // because it returns the number of milliseconds since Windows has started,
350 // which will roll over the 32-bit value every ~49 days. We try to track
351 // rollover ourselves, which works if TimeTicks::Now() is called at least every
352 // 49 days.
RolloverProtectedNow()353 TimeDelta RolloverProtectedNow() {
354 base::AutoLock locked(g_rollover_lock);
355 // We should hold the lock while calling tick_function to make sure that
356 // we keep last_seen_now stay correctly in sync.
357 DWORD now = g_tick_function();
358 if (now < g_last_seen_now)
359 g_rollover_ms += 0x100000000I64; // ~49.7 days.
360 g_last_seen_now = now;
361 return TimeDelta::FromMilliseconds(now + g_rollover_ms);
362 }
363
364 // Discussion of tick counter options on Windows:
365 //
366 // (1) CPU cycle counter. (Retrieved via RDTSC)
367 // The CPU counter provides the highest resolution time stamp and is the least
368 // expensive to retrieve. However, on older CPUs, two issues can affect its
369 // reliability: First it is maintained per processor and not synchronized
370 // between processors. Also, the counters will change frequency due to thermal
371 // and power changes, and stop in some states.
372 //
373 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
374 // resolution (<1 microsecond) time stamp. On most hardware running today, it
375 // auto-detects and uses the constant-rate RDTSC counter to provide extremely
376 // efficient and reliable time stamps.
377 //
378 // On older CPUs where RDTSC is unreliable, it falls back to using more
379 // expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI
380 // PM timer, and can involve system calls; and all this is up to the HAL (with
381 // some help from ACPI). According to
382 // http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the
383 // worst case, it gets the counter from the rollover interrupt on the
384 // programmable interrupt timer. In best cases, the HAL may conclude that the
385 // RDTSC counter runs at a constant frequency, then it uses that instead. On
386 // multiprocessor machines, it will try to verify the values returned from
387 // RDTSC on each processor are consistent with each other, and apply a handful
388 // of workarounds for known buggy hardware. In other words, QPC is supposed to
389 // give consistent results on a multiprocessor computer, but for older CPUs it
390 // can be unreliable due bugs in BIOS or HAL.
391 //
392 // (3) System time. The system time provides a low-resolution (from ~1 to ~15.6
393 // milliseconds) time stamp but is comparatively less expensive to retrieve and
394 // more reliable. Time::EnableHighResolutionTimer() and
395 // Time::ActivateHighResolutionTimer() can be called to alter the resolution of
396 // this timer; and also other Windows applications can alter it, affecting this
397 // one.
398
399 using NowFunction = TimeDelta (*)(void);
400
401 TimeDelta InitialNowFunction();
402
403 // See "threading notes" in InitializeNowFunctionPointer() for details on how
404 // concurrent reads/writes to these globals has been made safe.
405 NowFunction g_now_function = &InitialNowFunction;
406 int64_t g_qpc_ticks_per_second = 0;
407
408 // As of January 2015, use of <atomic> is forbidden in Chromium code. This is
409 // what std::atomic_thread_fence does on Windows on all Intel architectures when
410 // the memory_order argument is anything but std::memory_order_seq_cst:
411 #define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
412
QPCValueToTimeDelta(LONGLONG qpc_value)413 TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
414 // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
415 // InitializeNowFunctionPointer(), has happened by this point.
416 ATOMIC_THREAD_FENCE(memory_order_acquire);
417
418 DCHECK_GT(g_qpc_ticks_per_second, 0);
419
420 // If the QPC Value is below the overflow threshold, we proceed with
421 // simple multiply and divide.
422 if (qpc_value < Time::kQPCOverflowThreshold) {
423 return TimeDelta::FromMicroseconds(
424 qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
425 }
426 // Otherwise, calculate microseconds in a round about manner to avoid
427 // overflow and precision issues.
428 int64_t whole_seconds = qpc_value / g_qpc_ticks_per_second;
429 int64_t leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
430 return TimeDelta::FromMicroseconds(
431 (whole_seconds * Time::kMicrosecondsPerSecond) +
432 ((leftover_ticks * Time::kMicrosecondsPerSecond) /
433 g_qpc_ticks_per_second));
434 }
435
QPCNow()436 TimeDelta QPCNow() {
437 return QPCValueToTimeDelta(QPCNowRaw());
438 }
439
IsBuggyAthlon(const base::CPU & cpu)440 bool IsBuggyAthlon(const base::CPU& cpu) {
441 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
442 return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
443 }
444
InitializeNowFunctionPointer()445 void InitializeNowFunctionPointer() {
446 LARGE_INTEGER ticks_per_sec = {};
447 if (!QueryPerformanceFrequency(&ticks_per_sec))
448 ticks_per_sec.QuadPart = 0;
449
450 // If Windows cannot provide a QPC implementation, TimeTicks::Now() must use
451 // the low-resolution clock.
452 //
453 // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now()
454 // will still use the low-resolution clock. A CPU lacking a non-stop time
455 // counter will cause Windows to provide an alternate QPC implementation that
456 // works, but is expensive to use. Certain Athlon CPUs are known to make the
457 // QPC implementation unreliable.
458 //
459 // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
460 // ~72% of users fall within this category.
461 NowFunction now_function;
462 base::CPU cpu;
463 if (ticks_per_sec.QuadPart <= 0 ||
464 !cpu.has_non_stop_time_stamp_counter() || IsBuggyAthlon(cpu)) {
465 now_function = &RolloverProtectedNow;
466 } else {
467 now_function = &QPCNow;
468 }
469
470 // Threading note 1: In an unlikely race condition, it's possible for two or
471 // more threads to enter InitializeNowFunctionPointer() in parallel. This is
472 // not a problem since all threads should end up writing out the same values
473 // to the global variables.
474 //
475 // Threading note 2: A release fence is placed here to ensure, from the
476 // perspective of other threads using the function pointers, that the
477 // assignment to |g_qpc_ticks_per_second| happens before the function pointers
478 // are changed.
479 g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
480 ATOMIC_THREAD_FENCE(memory_order_release);
481 g_now_function = now_function;
482 }
483
InitialNowFunction()484 TimeDelta InitialNowFunction() {
485 InitializeNowFunctionPointer();
486 return g_now_function();
487 }
488
489 } // namespace
490
491 // static
SetMockTickFunction(TickFunctionType ticker)492 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
493 TickFunctionType ticker) {
494 base::AutoLock locked(g_rollover_lock);
495 TickFunctionType old = g_tick_function;
496 g_tick_function = ticker;
497 g_rollover_ms = 0;
498 g_last_seen_now = 0;
499 return old;
500 }
501
502 // static
Now()503 TimeTicks TimeTicks::Now() {
504 return TimeTicks() + g_now_function();
505 }
506
507 // static
IsHighResolution()508 bool TimeTicks::IsHighResolution() {
509 if (g_now_function == &InitialNowFunction)
510 InitializeNowFunctionPointer();
511 return g_now_function == &QPCNow;
512 }
513
514 // static
Now()515 ThreadTicks ThreadTicks::Now() {
516 DCHECK(IsSupported());
517
518 // Get the number of TSC ticks used by the current thread.
519 ULONG64 thread_cycle_time = 0;
520 GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time);
521
522 // Get the frequency of the TSC.
523 double tsc_ticks_per_second = TSCTicksPerSecond();
524 if (tsc_ticks_per_second == 0)
525 return ThreadTicks();
526
527 // Return the CPU time of the current thread.
528 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
529 return ThreadTicks(
530 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
531 }
532
533 // static
IsSupportedWin()534 bool ThreadTicks::IsSupportedWin() {
535 static bool is_supported = GetQueryThreadCycleTimeFunction() &&
536 base::CPU().has_non_stop_time_stamp_counter() &&
537 !IsBuggyAthlon(base::CPU());
538 return is_supported;
539 }
540
541 // static
WaitUntilInitializedWin()542 void ThreadTicks::WaitUntilInitializedWin() {
543 while (TSCTicksPerSecond() == 0)
544 ::Sleep(10);
545 }
546
TSCTicksPerSecond()547 double ThreadTicks::TSCTicksPerSecond() {
548 DCHECK(IsSupported());
549
550 // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
551 // frequency, because there is no guarantee that the TSC frequency is equal to
552 // the performance counter frequency.
553
554 // The TSC frequency is cached in a static variable because it takes some time
555 // to compute it.
556 static double tsc_ticks_per_second = 0;
557 if (tsc_ticks_per_second != 0)
558 return tsc_ticks_per_second;
559
560 // Increase the thread priority to reduces the chances of having a context
561 // switch during a reading of the TSC and the performance counter.
562 int previous_priority = ::GetThreadPriority(::GetCurrentThread());
563 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
564
565 // The first time that this function is called, make an initial reading of the
566 // TSC and the performance counter.
567 static const uint64_t tsc_initial = __rdtsc();
568 static const uint64_t perf_counter_initial = QPCNowRaw();
569
570 // Make a another reading of the TSC and the performance counter every time
571 // that this function is called.
572 uint64_t tsc_now = __rdtsc();
573 uint64_t perf_counter_now = QPCNowRaw();
574
575 // Reset the thread priority.
576 ::SetThreadPriority(::GetCurrentThread(), previous_priority);
577
578 // Make sure that at least 50 ms elapsed between the 2 readings. The first
579 // time that this function is called, we don't expect this to be the case.
580 // Note: The longer the elapsed time between the 2 readings is, the more
581 // accurate the computed TSC frequency will be. The 50 ms value was
582 // chosen because local benchmarks show that it allows us to get a
583 // stddev of less than 1 tick/us between multiple runs.
584 // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
585 // this will never fail on systems that run XP or later.
586 // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
587 LARGE_INTEGER perf_counter_frequency = {};
588 ::QueryPerformanceFrequency(&perf_counter_frequency);
589 DCHECK_GE(perf_counter_now, perf_counter_initial);
590 uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
591 double elapsed_time_seconds =
592 perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
593
594 const double kMinimumEvaluationPeriodSeconds = 0.05;
595 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
596 return 0;
597
598 // Compute the frequency of the TSC.
599 DCHECK_GE(tsc_now, tsc_initial);
600 uint64_t tsc_ticks = tsc_now - tsc_initial;
601 tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
602
603 return tsc_ticks_per_second;
604 }
605
606 // static
FromQPCValue(LONGLONG qpc_value)607 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
608 return TimeTicks() + QPCValueToTimeDelta(qpc_value);
609 }
610
611 // TimeDelta ------------------------------------------------------------------
612
613 // static
FromQPCValue(LONGLONG qpc_value)614 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
615 return QPCValueToTimeDelta(qpc_value);
616 }
617