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
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)));