Home | History | Annotate | Download | only in time
      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 
     40 #include "base/basictypes.h"
     41 #include "base/cpu.h"
     42 #include "base/lazy_instance.h"
     43 #include "base/logging.h"
     44 #include "base/synchronization/lock.h"
     45 
     46 using base::Time;
     47 using base::TimeDelta;
     48 using base::TimeTicks;
     49 
     50 namespace {
     51 
     52 // From MSDN, FILETIME "Contains a 64-bit value representing the number of
     53 // 100-nanosecond intervals since January 1, 1601 (UTC)."
     54 int64 FileTimeToMicroseconds(const FILETIME& ft) {
     55   // Need to bit_cast to fix alignment, then divide by 10 to convert
     56   // 100-nanoseconds to milliseconds. This only works on little-endian
     57   // machines.
     58   return bit_cast<int64, FILETIME>(ft) / 10;
     59 }
     60 
     61 void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
     62   DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
     63       "representable in FILETIME";
     64 
     65   // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
     66   // handle alignment problems. This only works on little-endian machines.
     67   *ft = bit_cast<FILETIME, int64>(us * 10);
     68 }
     69 
     70 int64 CurrentWallclockMicroseconds() {
     71   FILETIME ft;
     72   ::GetSystemTimeAsFileTime(&ft);
     73   return FileTimeToMicroseconds(ft);
     74 }
     75 
     76 // Time between resampling the un-granular clock for this API.  60 seconds.
     77 const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
     78 
     79 int64 initial_time = 0;
     80 TimeTicks initial_ticks;
     81 
     82 void InitializeClock() {
     83   initial_ticks = TimeTicks::Now();
     84   initial_time = CurrentWallclockMicroseconds();
     85 }
     86 
     87 // The two values that ActivateHighResolutionTimer uses to set the systemwide
     88 // timer interrupt frequency on Windows. It controls how precise timers are
     89 // but also has a big impact on battery life.
     90 const int kMinTimerIntervalHighResMs = 1;
     91 const int kMinTimerIntervalLowResMs = 4;
     92 // Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active.
     93 bool g_high_res_timer_enabled = false;
     94 // How many times the high resolution timer has been called.
     95 uint32_t g_high_res_timer_count = 0;
     96 // The lock to control access to the above two variables.
     97 base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
     98     LAZY_INSTANCE_INITIALIZER;
     99 
    100 }  // namespace
    101 
    102 // Time -----------------------------------------------------------------------
    103 
    104 // The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
    105 // 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
    106 // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
    107 // 1700, 1800, and 1900.
    108 // static
    109 const int64 Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
    110 
    111 // static
    112 Time Time::Now() {
    113   if (initial_time == 0)
    114     InitializeClock();
    115 
    116   // We implement time using the high-resolution timers so that we can get
    117   // timeouts which are smaller than 10-15ms.  If we just used
    118   // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
    119   //
    120   // To make this work, we initialize the clock (initial_time) and the
    121   // counter (initial_ctr).  To compute the initial time, we can check
    122   // the number of ticks that have elapsed, and compute the delta.
    123   //
    124   // To avoid any drift, we periodically resync the counters to the system
    125   // clock.
    126   while (true) {
    127     TimeTicks ticks = TimeTicks::Now();
    128 
    129     // Calculate the time elapsed since we started our timer
    130     TimeDelta elapsed = ticks - initial_ticks;
    131 
    132     // Check if enough time has elapsed that we need to resync the clock.
    133     if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
    134       InitializeClock();
    135       continue;
    136     }
    137 
    138     return Time(elapsed + Time(initial_time));
    139   }
    140 }
    141 
    142 // static
    143 Time Time::NowFromSystemTime() {
    144   // Force resync.
    145   InitializeClock();
    146   return Time(initial_time);
    147 }
    148 
    149 // static
    150 Time Time::FromFileTime(FILETIME ft) {
    151   if (bit_cast<int64, FILETIME>(ft) == 0)
    152     return Time();
    153   if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
    154       ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
    155     return Max();
    156   return Time(FileTimeToMicroseconds(ft));
    157 }
    158 
    159 FILETIME Time::ToFileTime() const {
    160   if (is_null())
    161     return bit_cast<FILETIME, int64>(0);
    162   if (is_max()) {
    163     FILETIME result;
    164     result.dwHighDateTime = std::numeric_limits<DWORD>::max();
    165     result.dwLowDateTime = std::numeric_limits<DWORD>::max();
    166     return result;
    167   }
    168   FILETIME utc_ft;
    169   MicrosecondsToFileTime(us_, &utc_ft);
    170   return utc_ft;
    171 }
    172 
    173 // static
    174 void Time::EnableHighResolutionTimer(bool enable) {
    175   base::AutoLock lock(g_high_res_lock.Get());
    176   if (g_high_res_timer_enabled == enable)
    177     return;
    178   g_high_res_timer_enabled = enable;
    179   if (!g_high_res_timer_count)
    180     return;
    181   // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true)
    182   // was called which called timeBeginPeriod with g_high_res_timer_enabled
    183   // with a value which is the opposite of |enable|. With that information we
    184   // call timeEndPeriod with the same value used in timeBeginPeriod and
    185   // therefore undo the period effect.
    186   if (enable) {
    187     timeEndPeriod(kMinTimerIntervalLowResMs);
    188     timeBeginPeriod(kMinTimerIntervalHighResMs);
    189   } else {
    190     timeEndPeriod(kMinTimerIntervalHighResMs);
    191     timeBeginPeriod(kMinTimerIntervalLowResMs);
    192   }
    193 }
    194 
    195 // static
    196 bool Time::ActivateHighResolutionTimer(bool activating) {
    197   // We only do work on the transition from zero to one or one to zero so we
    198   // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
    199   // called.
    200   const uint32_t max = std::numeric_limits<uint32_t>::max();
    201 
    202   base::AutoLock lock(g_high_res_lock.Get());
    203   UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
    204                                          : kMinTimerIntervalLowResMs;
    205   if (activating) {
    206     DCHECK(g_high_res_timer_count != max);
    207     ++g_high_res_timer_count;
    208     if (g_high_res_timer_count == 1)
    209       timeBeginPeriod(period);
    210   } else {
    211     DCHECK(g_high_res_timer_count != 0);
    212     --g_high_res_timer_count;
    213     if (g_high_res_timer_count == 0)
    214       timeEndPeriod(period);
    215   }
    216   return (period == kMinTimerIntervalHighResMs);
    217 }
    218 
    219 // static
    220 bool Time::IsHighResolutionTimerInUse() {
    221   base::AutoLock lock(g_high_res_lock.Get());
    222   return g_high_res_timer_enabled && g_high_res_timer_count > 0;
    223 }
    224 
    225 // static
    226 Time Time::FromExploded(bool is_local, const Exploded& exploded) {
    227   // Create the system struct representing our exploded time. It will either be
    228   // in local time or UTC.
    229   SYSTEMTIME st;
    230   st.wYear = exploded.year;
    231   st.wMonth = exploded.month;
    232   st.wDayOfWeek = exploded.day_of_week;
    233   st.wDay = exploded.day_of_month;
    234   st.wHour = exploded.hour;
    235   st.wMinute = exploded.minute;
    236   st.wSecond = exploded.second;
    237   st.wMilliseconds = exploded.millisecond;
    238 
    239   FILETIME ft;
    240   bool success = true;
    241   // Ensure that it's in UTC.
    242   if (is_local) {
    243     SYSTEMTIME utc_st;
    244     success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) &&
    245               SystemTimeToFileTime(&utc_st, &ft);
    246   } else {
    247     success = !!SystemTimeToFileTime(&st, &ft);
    248   }
    249 
    250   if (!success) {
    251     NOTREACHED() << "Unable to convert time";
    252     return Time(0);
    253   }
    254   return Time(FileTimeToMicroseconds(ft));
    255 }
    256 
    257 void Time::Explode(bool is_local, Exploded* exploded) const {
    258   if (us_ < 0LL) {
    259     // We are not able to convert it to FILETIME.
    260     ZeroMemory(exploded, sizeof(*exploded));
    261     return;
    262   }
    263 
    264   // FILETIME in UTC.
    265   FILETIME utc_ft;
    266   MicrosecondsToFileTime(us_, &utc_ft);
    267 
    268   // FILETIME in local time if necessary.
    269   bool success = true;
    270   // FILETIME in SYSTEMTIME (exploded).
    271   SYSTEMTIME st = {0};
    272   if (is_local) {
    273     SYSTEMTIME utc_st;
    274     // We don't use FileTimeToLocalFileTime here, since it uses the current
    275     // settings for the time zone and daylight saving time. Therefore, if it is
    276     // daylight saving time, it will take daylight saving time into account,
    277     // even if the time you are converting is in standard time.
    278     success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
    279               SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st);
    280   } else {
    281     success = !!FileTimeToSystemTime(&utc_ft, &st);
    282   }
    283 
    284   if (!success) {
    285     NOTREACHED() << "Unable to convert time, don't know why";
    286     ZeroMemory(exploded, sizeof(*exploded));
    287     return;
    288   }
    289 
    290   exploded->year = st.wYear;
    291   exploded->month = st.wMonth;
    292   exploded->day_of_week = st.wDayOfWeek;
    293   exploded->day_of_month = st.wDay;
    294   exploded->hour = st.wHour;
    295   exploded->minute = st.wMinute;
    296   exploded->second = st.wSecond;
    297   exploded->millisecond = st.wMilliseconds;
    298 }
    299 
    300 // TimeTicks ------------------------------------------------------------------
    301 namespace {
    302 
    303 // We define a wrapper to adapt between the __stdcall and __cdecl call of the
    304 // mock function, and to avoid a static constructor.  Assigning an import to a
    305 // function pointer directly would require setup code to fetch from the IAT.
    306 DWORD timeGetTimeWrapper() {
    307   return timeGetTime();
    308 }
    309 
    310 DWORD (*tick_function)(void) = &timeGetTimeWrapper;
    311 
    312 // Accumulation of time lost due to rollover (in milliseconds).
    313 int64 rollover_ms = 0;
    314 
    315 // The last timeGetTime value we saw, to detect rollover.
    316 DWORD last_seen_now = 0;
    317 
    318 // Lock protecting rollover_ms and last_seen_now.
    319 // Note: this is a global object, and we usually avoid these. However, the time
    320 // code is low-level, and we don't want to use Singletons here (it would be too
    321 // easy to use a Singleton without even knowing it, and that may lead to many
    322 // gotchas). Its impact on startup time should be negligible due to low-level
    323 // nature of time code.
    324 base::Lock rollover_lock;
    325 
    326 // We use timeGetTime() to implement TimeTicks::Now().  This can be problematic
    327 // because it returns the number of milliseconds since Windows has started,
    328 // which will roll over the 32-bit value every ~49 days.  We try to track
    329 // rollover ourselves, which works if TimeTicks::Now() is called at least every
    330 // 49 days.
    331 TimeDelta RolloverProtectedNow() {
    332   base::AutoLock locked(rollover_lock);
    333   // We should hold the lock while calling tick_function to make sure that
    334   // we keep last_seen_now stay correctly in sync.
    335   DWORD now = tick_function();
    336   if (now < last_seen_now)
    337     rollover_ms += 0x100000000I64;  // ~49.7 days.
    338   last_seen_now = now;
    339   return TimeDelta::FromMilliseconds(now + rollover_ms);
    340 }
    341 
    342 bool IsBuggyAthlon(const base::CPU& cpu) {
    343   // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
    344   // unreliable.  Fallback to low-res clock.
    345   return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
    346 }
    347 
    348 // Overview of time counters:
    349 // (1) CPU cycle counter. (Retrieved via RDTSC)
    350 // The CPU counter provides the highest resolution time stamp and is the least
    351 // expensive to retrieve. However, the CPU counter is unreliable and should not
    352 // be used in production. Its biggest issue is that it is per processor and it
    353 // is not synchronized between processors. Also, on some computers, the counters
    354 // will change frequency due to thermal and power changes, and stop in some
    355 // states.
    356 //
    357 // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
    358 // resolution (100 nanoseconds) time stamp but is comparatively more expensive
    359 // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
    360 // (with some help from ACPI).
    361 // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
    362 // in the worst case, it gets the counter from the rollover interrupt on the
    363 // programmable interrupt timer. In best cases, the HAL may conclude that the
    364 // RDTSC counter runs at a constant frequency, then it uses that instead. On
    365 // multiprocessor machines, it will try to verify the values returned from
    366 // RDTSC on each processor are consistent with each other, and apply a handful
    367 // of workarounds for known buggy hardware. In other words, QPC is supposed to
    368 // give consistent result on a multiprocessor computer, but it is unreliable in
    369 // reality due to bugs in BIOS or HAL on some, especially old computers.
    370 // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
    371 // it should be used with caution.
    372 //
    373 // (3) System time. The system time provides a low-resolution (typically 10ms
    374 // to 55 milliseconds) time stamp but is comparatively less expensive to
    375 // retrieve and more reliable.
    376 class HighResNowSingleton {
    377  public:
    378   HighResNowSingleton()
    379       : ticks_per_second_(0),
    380         skew_(0) {
    381 
    382     base::CPU cpu;
    383     if (IsBuggyAthlon(cpu))
    384       return;
    385 
    386     // Synchronize the QPC clock with GetSystemTimeAsFileTime.
    387     LARGE_INTEGER ticks_per_sec = {0};
    388     if (!QueryPerformanceFrequency(&ticks_per_sec))
    389       return; // QPC is not available.
    390     ticks_per_second_ = ticks_per_sec.QuadPart;
    391 
    392     skew_ = UnreliableNow() - ReliableNow();
    393   }
    394 
    395   bool IsUsingHighResClock() {
    396     return ticks_per_second_ != 0;
    397   }
    398 
    399   TimeDelta Now() {
    400     if (IsUsingHighResClock())
    401       return TimeDelta::FromMicroseconds(UnreliableNow());
    402 
    403     // Just fallback to the slower clock.
    404     return RolloverProtectedNow();
    405   }
    406 
    407   int64 GetQPCDriftMicroseconds() {
    408     if (!IsUsingHighResClock())
    409       return 0;
    410     return abs((UnreliableNow() - ReliableNow()) - skew_);
    411   }
    412 
    413   int64 QPCValueToMicroseconds(LONGLONG qpc_value) {
    414     if (!ticks_per_second_)
    415       return 0;
    416     // If the QPC Value is below the overflow threshold, we proceed with
    417     // simple multiply and divide.
    418     if (qpc_value < Time::kQPCOverflowThreshold)
    419       return qpc_value * Time::kMicrosecondsPerSecond / ticks_per_second_;
    420     // Otherwise, calculate microseconds in a round about manner to avoid
    421     // overflow and precision issues.
    422     int64 whole_seconds = qpc_value / ticks_per_second_;
    423     int64 leftover_ticks = qpc_value - (whole_seconds * ticks_per_second_);
    424     int64 microseconds = (whole_seconds * Time::kMicrosecondsPerSecond) +
    425                          ((leftover_ticks * Time::kMicrosecondsPerSecond) /
    426                           ticks_per_second_);
    427     return microseconds;
    428   }
    429 
    430  private:
    431   // Get the number of microseconds since boot in an unreliable fashion.
    432   int64 UnreliableNow() {
    433     LARGE_INTEGER now;
    434     QueryPerformanceCounter(&now);
    435     return QPCValueToMicroseconds(now.QuadPart);
    436   }
    437 
    438   // Get the number of microseconds since boot in a reliable fashion.
    439   int64 ReliableNow() {
    440     return RolloverProtectedNow().InMicroseconds();
    441   }
    442 
    443   int64 ticks_per_second_;  // 0 indicates QPF failed and we're broken.
    444   int64 skew_;  // Skew between lo-res and hi-res clocks (for debugging).
    445 };
    446 
    447 static base::LazyInstance<HighResNowSingleton>::Leaky
    448     leaky_high_res_now_singleton = LAZY_INSTANCE_INITIALIZER;
    449 
    450 HighResNowSingleton* GetHighResNowSingleton() {
    451   return leaky_high_res_now_singleton.Pointer();
    452 }
    453 
    454 TimeDelta HighResNowWrapper() {
    455   return GetHighResNowSingleton()->Now();
    456 }
    457 
    458 typedef TimeDelta (*NowFunction)(void);
    459 
    460 bool CPUReliablySupportsHighResTime() {
    461   base::CPU cpu;
    462   if (!cpu.has_non_stop_time_stamp_counter() ||
    463       !GetHighResNowSingleton()->IsUsingHighResClock())
    464     return false;
    465 
    466   if (IsBuggyAthlon(cpu))
    467     return false;
    468 
    469   return true;
    470 }
    471 
    472 TimeDelta InitialNowFunction();
    473 
    474 volatile NowFunction now_function = InitialNowFunction;
    475 
    476 TimeDelta InitialNowFunction() {
    477   if (!CPUReliablySupportsHighResTime()) {
    478     InterlockedExchangePointer(
    479         reinterpret_cast<void* volatile*>(&now_function),
    480         &RolloverProtectedNow);
    481     return RolloverProtectedNow();
    482   }
    483   InterlockedExchangePointer(
    484         reinterpret_cast<void* volatile*>(&now_function),
    485         &HighResNowWrapper);
    486   return HighResNowWrapper();
    487 }
    488 
    489 }  // namespace
    490 
    491 // static
    492 TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
    493     TickFunctionType ticker) {
    494   base::AutoLock locked(rollover_lock);
    495   TickFunctionType old = tick_function;
    496   tick_function = ticker;
    497   rollover_ms = 0;
    498   last_seen_now = 0;
    499   return old;
    500 }
    501 
    502 // static
    503 TimeTicks TimeTicks::Now() {
    504   return TimeTicks() + now_function();
    505 }
    506 
    507 // static
    508 TimeTicks TimeTicks::HighResNow() {
    509   return TimeTicks() + HighResNowWrapper();
    510 }
    511 
    512 // static
    513 bool TimeTicks::IsHighResNowFastAndReliable() {
    514   return CPUReliablySupportsHighResTime();
    515 }
    516 
    517 // static
    518 TimeTicks TimeTicks::ThreadNow() {
    519   NOTREACHED();
    520   return TimeTicks();
    521 }
    522 
    523 // static
    524 TimeTicks TimeTicks::NowFromSystemTraceTime() {
    525   return HighResNow();
    526 }
    527 
    528 // static
    529 int64 TimeTicks::GetQPCDriftMicroseconds() {
    530   return GetHighResNowSingleton()->GetQPCDriftMicroseconds();
    531 }
    532 
    533 // static
    534 TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
    535   return TimeTicks(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
    536 }
    537 
    538 // static
    539 bool TimeTicks::IsHighResClockWorking() {
    540   return GetHighResNowSingleton()->IsUsingHighResClock();
    541 }
    542 
    543 TimeTicks TimeTicks::UnprotectedNow() {
    544   if (now_function == HighResNowWrapper) {
    545     return Now();
    546   } else {
    547     return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime());
    548   }
    549 }
    550 
    551 // TimeDelta ------------------------------------------------------------------
    552 
    553 // static
    554 TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
    555   return TimeDelta(GetHighResNowSingleton()->QPCValueToMicroseconds(qpc_value));
    556 }
    557