// If the duration is less then one second, perform check of QPC stability // by comparing both 'epoch' and 'now' skew (=GTC - QPC) values. bool TimeStampValue::CheckQPC(int64_t aDuration, const TimeStampValue &aOther) const { if (!mHasQPC || !aOther.mHasQPC) // Not both holding QPC return false; if (sHasStableTSC) // For stable TSC there is no need to check return true; if (!sUseQPC) // QPC globally disabled return false; // Treat absolutely for calibration purposes aDuration = Abs(aDuration); // Check QPC is sane before using it. LONGLONG skew1 = mGTC - mQPC; LONGLONG skew2 = aOther.mGTC - aOther.mQPC; LONGLONG diff = skew1 - skew2; LONGLONG overflow; if (diff < sUnderrunThreshold) overflow = sUnderrunThreshold - diff; else if (diff > sOverrunThreshold) overflow = diff - sOverrunThreshold; else return true; ULONGLONG trend; if (aDuration) trend = LONGLONG(overflow * (double(sQPCHardFailureDetectionInterval) / aDuration)); else trend = overflow; LOG(("TimeStamp: QPC check after %llums with overflow %1.4fms" ", adjusted trend per interval is %1.4fms", mt2ms(aDuration), mt2ms_f(overflow), mt2ms_f(trend))); if (trend <= ms2mt(kOverflowLimit)) { // We are in the limit, let go. return true; } // QPC deviates, don't use it. LOG(("TimeStamp: QPC found highly jittering")); if (aDuration < sQPCHardFailureDetectionInterval) { // Interval between the two time stamps is very short, consider // QPC as unstable and disable it completely. sUseQPC = false; LOG(("TimeStamp: QPC disabled")); } return false; }
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(); ULONGLONG candidate = (end - start); if (candidate < minres) minres = candidate; } while (--loops && minres); if (0 == minres) { minres = 1; } // Converting minres that is in [mt] to nanosecods, multiplicating // the argument to preserve resolution. ULONGLONG result = mt2ms(minres * kNsPerMillisec); if (0 == result) { result = 1; } sResolution = result; // find the number of significant digits in mResolution, for the // sake of ToSecondsSigDigits() ULONGLONG sigDigs; for (sigDigs = 1; !(sigDigs == result || 10*sigDigs > result); sigDigs *= 10); sResolutionSigDigs = sigDigs; }
// If the duration is less then two seconds, perform check of QPC stability // by comparing both GTC and QPC calculated durations of this and aOther. MFBT_API uint64_t TimeStampValue::CheckQPC(const TimeStampValue& aOther) const { uint64_t deltaGTC = mGTC - aOther.mGTC; if (!mHasQPC || !aOther.mHasQPC) { // Both not holding QPC return deltaGTC; } uint64_t deltaQPC = mQPC - aOther.mQPC; if (sHasStableTSC) { // For stable TSC there is no need to check return deltaQPC; } // Check QPC is sane before using it. int64_t diff = DeprecatedAbs(int64_t(deltaQPC) - int64_t(deltaGTC)); if (diff <= sGTCResolutionThreshold) { return deltaQPC; } // Treat absolutely for calibration purposes int64_t duration = DeprecatedAbs(int64_t(deltaGTC)); int64_t overflow = diff - sGTCResolutionThreshold; LOG(("TimeStamp: QPC check after %llums with overflow %1.4fms", mt2ms(duration), mt2ms_f(overflow))); if (overflow <= sFailureThreshold) { // We are in the limit, let go. return deltaQPC; } // QPC deviates, don't use it, since now this method may only return deltaGTC. if (!sUseQPC) { // QPC already disabled, no need to run the fault tolerance algorithm. return deltaGTC; } LOG(("TimeStamp: QPC jittered over failure threshold")); if (duration < sHardFailureLimit) { // Interval between the two time stamps is very short, consider // QPC as unstable and record a failure. uint64_t now = ms2mt(sGetTickCount64()); AutoCriticalSection lock(&sTimeStampLock); if (sFaultIntoleranceCheckpoint && sFaultIntoleranceCheckpoint > now) { // There's already been an error in the last fault intollerant interval. // Time since now to the checkpoint actually holds information on how many // failures there were in the failure free interval we have defined. uint64_t failureCount = (sFaultIntoleranceCheckpoint - now + sFailureFreeInterval - 1) / sFailureFreeInterval; if (failureCount > kMaxFailuresPerInterval) { sUseQPC = false; LOG(("TimeStamp: QPC disabled")); } else { // Move the fault intolerance checkpoint more to the future, prolong it // to reflect the number of detected failures. ++failureCount; sFaultIntoleranceCheckpoint = now + failureCount * sFailureFreeInterval; LOG(("TimeStamp: recording %dth QPC failure", failureCount)); } } else { // Setup fault intolerance checkpoint in the future for first detected error. sFaultIntoleranceCheckpoint = now + sFailureFreeInterval; LOG(("TimeStamp: recording 1st QPC failure")); } } return deltaGTC; }