nsresult TimeStamp::Startup() { // Decide which implementation to use for the high-performance timer. InitializeCriticalSectionAndSpinCount(&sTimeStampLock, kLockSpinCount); LARGE_INTEGER freq; BOOL QPCAvailable = ::QueryPerformanceFrequency(&freq); if (!QPCAvailable) { // No Performance Counter. Fall back to use GetTickCount. sFrequencyPerSec = 1; sFallBackToGTC = true; InitResolution(); LOG(("TimeStamp: using GetTickCount")); return NS_OK; } sFrequencyPerSec = freq.QuadPart; ULONGLONG qpc = PerformanceCounter(); sLastCalibrated = TickCount64(::GetTickCount()); sSkew = qpc - ms2mt(sLastCalibrated); InitThresholds(); InitResolution(); LOG(("TimeStamp: initial skew is %1.2fms", mt2ms_d(sSkew))); return NS_OK; }
TimeStamp TimeStamp::Now(bool aHighResolution) { // sUseQPC is volatile bool useQPC = (aHighResolution && sUseQPC); // Both values are in [mt] units. ULONGLONG QPC = useQPC ? PerformanceCounter() : uint64_t(0); ULONGLONG GTC = ms2mt(sGetTickCount64()); return TimeStamp(TimeStampValue(GTC, QPC, useQPC)); }
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; }
// The main function. Result is in [mt] ensuring to not go back and be mostly // reliable with highest possible resolution. static ULONGLONG CalibratedPerformanceCounter() { // XXX This is using ObserverService, cannot instantiate in the static // startup, really needs a better initation code here. 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(); DWORD gtcw = GetTickCount(); AutoCriticalSection lock(&sTimeStampLock); // Rollover protection ULONGLONG gtc = TickCount64(gtcw); LONGLONG diff = qpc - ms2mt(gtc) - sSkew; LONGLONG overflow = 0; if (diff < sUnderrunThreshold) { overflow = sUnderrunThreshold - diff; } else if (diff > sOverrunThreshold) { overflow = diff - sOverrunThreshold; } ULONGLONG result = qpc; if (!CheckCalibration(overflow, qpc, gtc)) { // We are back on GTC, QPC has been observed unreliable result = ms2mt(gtc) + sSkew; } #if 0 LOG(("TimeStamp: result = %1.2fms, diff = %1.4fms", mt2ms_d(result), mt2ms_d(diff))); #endif if (result > sLastResult) sLastResult = result; return sLastResult; }
void CPerformanceStats::AddSample(const std::string &strStatName, double dTime) { AddSample(strStatName, PerformanceCounter(dTime)); }