Bug 1406386 - Control how TimeStamp works on Windows via and envvar. r=froydnj
authorHonza Bambas <honzab.moz@firemni.cz>
Fri, 06 Oct 2017 09:16:00 -0400
changeset 427927 8912a9d63a5c7f9b75c5740ff8be7835cba07747
parent 427926 784028f4bb880410c96ad88ba9a4fd4d54d66921
child 427928 0e548491460993bb141a68c596c186ef80dc0e68
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersfroydnj
bugs1406386
milestone58.0a1
Bug 1406386 - Control how TimeStamp works on Windows via and envvar. r=froydnj
mozglue/misc/TimeStamp_windows.cpp
--- a/mozglue/misc/TimeStamp_windows.cpp
+++ b/mozglue/misc/TimeStamp_windows.cpp
@@ -6,16 +6,17 @@
 
 // Implement TimeStamp::Now() with QueryPerformanceCounter() controlled with
 // values of GetTickCount64().
 
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/TimeStamp.h"
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <intrin.h>
 #include <windows.h>
 
 // To enable logging define to your favorite logging API
 #define LOG(x)
 
 class AutoCriticalSection
 {
@@ -74,17 +75,19 @@ static const DWORD kDefaultTimeIncrement
  * have the same units to allow simple arithmentic with both QPC and GTC.
  */
 
 #define ms2mt(x) ((x) * sFrequencyPerSec)
 #define mt2ms(x) ((x) / sFrequencyPerSec)
 #define mt2ms_f(x) (double(x) / sFrequencyPerSec)
 
 // Result of QueryPerformanceFrequency
-static LONGLONG sFrequencyPerSec = 0;
+// We use default of 1 for the case we can't use QueryPerformanceCounter
+// to make mt/ms conversions work despite that.
+static LONGLONG sFrequencyPerSec = 1;
 
 // How much we are tolerant to GTC occasional loose of resoltion.
 // This number says how many multiples of the minimal GTC resolution
 // detected on the system are acceptable.  This number is empirical.
 static const LONGLONG kGTCTickLeapTolerance = 4;
 
 // Base tolerance (more: "inability of detection" range) threshold is calculated
 // dynamically, and kept in sGTCResolutionThreshold.
@@ -222,29 +225,34 @@ InitThresholds()
 static void
 InitResolution()
 {
   // 10 total trials is arbitrary: what we're trying to avoid by
   // looping is getting unlucky and being interrupted by a context
   // switch or signal, or being bitten by paging/cache effects
 
   ULONGLONG minres = ~0ULL;
-  int loops = 10;
-  do {
-    ULONGLONG start = PerformanceCounter();
-    ULONGLONG end = PerformanceCounter();
+  if (sUseQPC) {
+    int loops = 10;
+    do {
+      ULONGLONG start = PerformanceCounter();
+      ULONGLONG end = PerformanceCounter();
 
-    ULONGLONG candidate = (end - start);
-    if (candidate < minres) {
-      minres = candidate;
+      ULONGLONG candidate = (end - start);
+      if (candidate < minres) {
+        minres = candidate;
+      }
+    } while (--loops && minres);
+
+    if (0 == minres) {
+      minres = 1;
     }
-  } while (--loops && minres);
-
-  if (0 == minres) {
-    minres = 1;
+  } else {
+    // GetTickCount has only ~16ms known resolution
+    minres = ms2mt(16);
   }
 
   // Converting minres that is in [mt] to nanosecods, multiplicating
   // the argument to preserve resolution.
   ULONGLONG result = mt2ms(minres * kNsPerMillisec);
   if (0 == result) {
     result = 1;
   }
@@ -467,29 +475,41 @@ TimeStamp::Startup()
   }
 
   gInitialized = true;
 
   // Decide which implementation to use for the high-performance timer.
 
   InitializeCriticalSectionAndSpinCount(&sTimeStampLock, kLockSpinCount);
 
-  sHasStableTSC = HasStableTSC();
-  LOG(("TimeStamp: HasStableTSC=%d", sHasStableTSC));
+  bool forceGTC = false;
+  bool forceQPC = false;
+
+  char* modevar = getenv("MOZ_TIMESTAMP_MODE");
+  if (modevar) {
+    if (!strcmp(modevar, "QPC")) {
+      forceQPC = true;
+    } else if (!strcmp(modevar, "GTC")) {
+      forceGTC = true;
+    }
+  }
 
   LARGE_INTEGER freq;
-  sUseQPC = ::QueryPerformanceFrequency(&freq);
+  sUseQPC = !forceGTC && ::QueryPerformanceFrequency(&freq);
   if (!sUseQPC) {
     // No Performance Counter.  Fall back to use GetTickCount64.
     InitResolution();
 
     LOG(("TimeStamp: using GetTickCount64"));
     return;
   }
 
+  sHasStableTSC = forceQPC || HasStableTSC();
+  LOG(("TimeStamp: HasStableTSC=%d", sHasStableTSC));
+
   sFrequencyPerSec = freq.QuadPart;
   LOG(("TimeStamp: QPC frequency=%llu", sFrequencyPerSec));
 
   InitThresholds();
   InitResolution();
 
   return;
 }