Bug 784859 - Part 5: Change the implementation of GetTickCount64Fallback so that it never locks; r=bbondy
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 06 Sep 2012 11:01:06 -0400
changeset 104650 9544f94ccdb8
parent 104649 64ea34bc583e
child 104651 d4a8c7efef04
push id14615
push usereakhgari@mozilla.com
push date2012-09-08 18:13 +0000
treeherdermozilla-inbound@d4a8c7efef04 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbondy
bugs784859
milestone18.0a1
Bug 784859 - Part 5: Change the implementation of GetTickCount64Fallback so that it never locks; r=bbondy
xpcom/ds/TimeStamp_windows.cpp
--- a/xpcom/ds/TimeStamp_windows.cpp
+++ b/xpcom/ds/TimeStamp_windows.cpp
@@ -412,34 +412,32 @@ InitResolution()
 
 // 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 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.
-  // Easiest solution is to check for a significant difference.
+  ULONGLONG old, newValue;
+  do {
+    old = InterlockedRead64(&sLastGTCResult);
+    ULONGLONG oldTop = old & 0xffffffff00000000;
+    ULONG oldBottom = old & 0xffffffff;
+    ULONG newBottom = GetTickCount();
+    if (newBottom < oldBottom) {
+        // handle overflow
+        newValue = (oldTop + (1ULL<<32)) | newBottom;
+    } else {
+        newValue = oldTop | newBottom;
+    }
+  } while (old != _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*> (&sLastGTCResult),
+                                                newValue, old));
 
-  if (sLastGTCResult > result) {
-    if ((sLastGTCResult - result) > (1ULL << 31))
-      result += 1ULL << 32;
-    else
-      result = sLastGTCResult;
-  }
-
-  sLastGTCResult = result;
-  return result;
+  return newValue;
 }
 
 // Result is in [mt]
 static inline ULONGLONG
 PerformanceCounter()
 {
   LARGE_INTEGER pc;
   ::QueryPerformanceCounter(&pc);
@@ -564,23 +562,23 @@ CalibratedPerformanceCounter()
   StandbyObserver::Ensure();
 
   // Don't hold the lock over call to QueryPerformanceCounter, since it is
   // the largest bottleneck, let threads read the value concurently to have
   // possibly a better performance.
 
   ULONGLONG qpc = PerformanceCounter();
 
+  // Rollover protection
+  ULONGLONG gtc = sGetTickCount64();
+
   ULONGLONG result;
   {
   AutoCriticalSection lock(&sTimeStampLock);
 
-  // Rollover protection
-  ULONGLONG gtc = sGetTickCount64();
-
   LONGLONG diff = qpc - ms2mt(gtc) - sSkew;
   LONGLONG overflow = 0;
 
   if (diff < sUnderrunThreshold) {
     overflow = sUnderrunThreshold - diff;
   }
   else if (diff > sOverrunThreshold) {
     overflow = diff - sOverrunThreshold;