Bug 784859 - Part 4: Use the native GetTickCount64 function where available; r=bbondy
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 08 Sep 2012 14:12:34 -0400
changeset 104651 64ea34bc583e
parent 104650 9b7184f6e154
child 104652 9544f94ccdb8
push id23436
push userryanvm@gmail.com
push date2012-09-09 01:10 +0000
treeherdermozilla-central@f31d1aa89848 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbondy
bugs784859
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 784859 - Part 4: Use the native GetTickCount64 function where available; r=bbondy
xpcom/ds/TimeStamp_windows.cpp
--- a/xpcom/ds/TimeStamp_windows.cpp
+++ b/xpcom/ds/TimeStamp_windows.cpp
@@ -178,17 +178,17 @@ CRITICAL_SECTION sTimeStampLock;
 // Globals heavily chaning at runtime, protected with sTimeStampLock mutex
 // ----------------------------------------------------------------------------
 
 // The calibrated difference between QPC and GTC.
 //
 // Kept in [mt]
 static LONGLONG sSkew = 0;
 
-// Keeps the last result we have returned from TickCount64 (bellow).  Protects
+// Keeps the last result we have returned from sGetTickCount64 (bellow).  Protects
 // from roll over and going backward.
 //
 // Kept in [ms]
 static ULONGLONG sLastGTCResult = 0;
 
 // Holder of the last result of our main hi-res function.  Protects from going
 // backward.
 //
@@ -210,16 +210,18 @@ static bool sForceRecalibrate = false;
 
 
 namespace mozilla {
 
 
 static ULONGLONG
 CalibratedPerformanceCounter();
 
+typedef ULONGLONG (WINAPI* GetTickCount64_t)();
+static GetTickCount64_t sGetTickCount64 = nullptr;
 
 static inline ULONGLONG
 InterlockedRead64(volatile ULONGLONG* destination)
 {
 #ifdef _WIN64
   // Aligned 64-bit reads on x86-64 are atomic
   return *destination;
 #else
@@ -407,18 +409,18 @@ InitResolution()
 
   sResolutionSigDigs = sigDigs;
 }
 
 // Function protecting GetTickCount result from rolling over, result is in [ms]
 // @param gtc
 // Result of GetTickCount().  Passing it as an arg lets us call it out
 // of the common mutex.
-static inline ULONGLONG
-TickCount64()
+static ULONGLONG WINAPI
+GetTickCount64Fallback()
 {
   DWORD now = GetTickCount();
   ULONGLONG lastResultHiPart = sLastGTCResult & (~0ULL << 32);
   ULONGLONG result = lastResultHiPart | ULONGLONG(now);
 
   // It may happen that when accessing GTC on multiple threads the results
   // may differ (GTC value may be lower due to running before the others
   // right around the overflow moment).  That falsely shifts the high part.
@@ -455,17 +457,17 @@ RecordFlaw()
 #if 0
   // This code has been disabled, because we:
   // 0. InitResolution must not be called under the lock (would reenter) while
   //    we shouldn't release it here just to allow it
   // 1. may return back to using QPC after system wake up
   // 2. InitResolution for GTC will probably return 0 anyway (increments
   //    only every 15 or 16 ms.)
   //
-  // There is no need to drop sFrequencyPerSec to 1, result of TickCount64
+  // There is no need to drop sFrequencyPerSec to 1, result of sGetTickCount64
   // is multiplied and later divided with sFrequencyPerSec.  Changing it
   // here may introduce sync problems.  Syncing access to sFrequencyPerSec
   // is overkill.  Drawback is we loose some bits from the upper bound of
   // the 64 bits timer value, usualy up to 7, it means the app cannot run
   // more then some 4'000'000 years :)
   InitResolution();
 #endif
 }
@@ -567,17 +569,17 @@ CalibratedPerformanceCounter()
 
   ULONGLONG qpc = PerformanceCounter();
 
   ULONGLONG result;
   {
   AutoCriticalSection lock(&sTimeStampLock);
 
   // Rollover protection
-  ULONGLONG gtc = TickCount64();
+  ULONGLONG gtc = sGetTickCount64();
 
   LONGLONG diff = qpc - ms2mt(gtc) - sSkew;
   LONGLONG overflow = 0;
 
   if (diff < sUnderrunThreshold) {
     overflow = sUnderrunThreshold - diff;
   }
   else if (diff > sOverrunThreshold) {
@@ -650,16 +652,25 @@ struct TimeStampInitialization
 
 static TimeStampInitialization initOnce;
 
 nsresult
 TimeStamp::Startup()
 {
   // Decide which implementation to use for the high-performance timer.
 
+  HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll");
+  sGetTickCount64 = reinterpret_cast<GetTickCount64_t>
+    (GetProcAddress(kernelDLL, "GetTickCount64"));
+  if (!sGetTickCount64) {
+    // If the platform does not support the GetTickCount64 (Windows XP doesn't),
+    // then use our fallback implementation based on GetTickCount.
+    sGetTickCount64 = GetTickCount64Fallback;
+  }
+
   InitializeCriticalSectionAndSpinCount(&sTimeStampLock, kLockSpinCount);
 
   LARGE_INTEGER freq;
   BOOL QPCAvailable = ::QueryPerformanceFrequency(&freq);
   if (!QPCAvailable) {
     // No Performance Counter.  Fall back to use GetTickCount.
     sFrequencyPerSec = 1;
     sFallBackToGTC = true;
@@ -667,17 +678,17 @@ TimeStamp::Startup()
 
     LOG(("TimeStamp: using GetTickCount"));
     return NS_OK;
   }
 
   sFrequencyPerSec = freq.QuadPart;
 
   ULONGLONG qpc = PerformanceCounter();
-  sLastCalibrated = TickCount64();
+  sLastCalibrated = sGetTickCount64();
   sSkew = qpc - ms2mt(sLastCalibrated);
 
   InitThresholds();
   InitResolution();
 
   sHasStableTSC = HasStableTSC();
 
   LOG(("TimeStamp: initial skew is %1.2fms", mt2ms_d(sSkew)));