Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // Implement TimeStamp::Now() with QueryPerformanceCounter() controlled with
8 // values of GetTickCount().
10 #include "mozilla/MathAlgorithms.h"
11 #include "mozilla/Mutex.h"
12 #include "mozilla/TimeStamp.h"
13 #include "nsWindowsHelpers.h"
14 #include <windows.h>
16 #include "nsCRT.h"
17 #include "prlog.h"
18 #include "prprf.h"
19 #include <stdio.h>
21 #include <intrin.h>
23 #if defined(PR_LOGGING)
24 // Log module for mozilla::TimeStamp for Windows logging...
25 //
26 // To enable logging (see prlog.h for full details):
27 //
28 // set NSPR_LOG_MODULES=TimeStampWindows:5
29 // set NSPR_LOG_FILE=nspr.log
30 //
31 // this enables PR_LOG_DEBUG level information and places all output in
32 // the file nspr.log
33 static PRLogModuleInfo*
34 GetTimeStampLog()
35 {
36 static PRLogModuleInfo *sLog;
37 if (!sLog)
38 sLog = PR_NewLogModule("TimeStampWindows");
39 return sLog;
40 }
41 #define LOG(x) PR_LOG(GetTimeStampLog(), PR_LOG_DEBUG, x)
42 #else
43 #define LOG(x)
44 #endif /* PR_LOGGING */
46 // Estimate of the smallest duration of time we can measure.
47 static volatile ULONGLONG sResolution;
48 static volatile ULONGLONG sResolutionSigDigs;
49 static const double kNsPerSecd = 1000000000.0;
50 static const LONGLONG kNsPerSec = 1000000000;
51 static const LONGLONG kNsPerMillisec = 1000000;
53 // ----------------------------------------------------------------------------
54 // Global constants
55 // ----------------------------------------------------------------------------
57 // Tolerance to failures settings.
58 //
59 // What is the interval we want to have failure free.
60 // in [ms]
61 static const uint32_t kFailureFreeInterval = 5000;
62 // How many failures we are willing to tolerate in the interval.
63 static const uint32_t kMaxFailuresPerInterval = 4;
64 // What is the threshold to treat fluctuations as actual failures.
65 // in [ms]
66 static const uint32_t kFailureThreshold = 50;
68 // If we are not able to get the value of GTC time increment, use this value
69 // which is the most usual increment.
70 static const DWORD kDefaultTimeIncrement = 156001;
72 // ----------------------------------------------------------------------------
73 // Global variables, not changing at runtime
74 // ----------------------------------------------------------------------------
76 /**
77 * The [mt] unit:
78 *
79 * Many values are kept in ticks of the Performance Coutner x 1000,
80 * further just referred as [mt], meaning milli-ticks.
81 *
82 * This is needed to preserve maximum precision of the performance frequency
83 * representation. GetTickCount values in milliseconds are multiplied with
84 * frequency per second. Therefor we need to multiply QPC value by 1000 to
85 * have the same units to allow simple arithmentic with both QPC and GTC.
86 */
88 #define ms2mt(x) ((x) * sFrequencyPerSec)
89 #define mt2ms(x) ((x) / sFrequencyPerSec)
90 #define mt2ms_f(x) (double(x) / sFrequencyPerSec)
92 // Result of QueryPerformanceFrequency
93 static LONGLONG sFrequencyPerSec = 0;
95 // How much we are tolerant to GTC occasional loose of resoltion.
96 // This number says how many multiples of the minimal GTC resolution
97 // detected on the system are acceptable. This number is empirical.
98 static const LONGLONG kGTCTickLeapTolerance = 4;
100 // Base tolerance (more: "inability of detection" range) threshold is calculated
101 // dynamically, and kept in sGTCResulutionThreshold.
102 //
103 // Schematically, QPC worked "100%" correctly if ((GTC_now - GTC_epoch) -
104 // (QPC_now - QPC_epoch)) was in [-sGTCResulutionThreshold, sGTCResulutionThreshold]
105 // interval every time we'd compared two time stamps.
106 // If not, then we check the overflow behind this basic threshold
107 // is in kFailureThreshold. If not, we condider it as a QPC failure. If too many
108 // failures in short time are detected, QPC is considered faulty and disabled.
109 //
110 // Kept in [mt]
111 static LONGLONG sGTCResulutionThreshold;
113 // If QPC is found faulty for two stamps in this interval, we engage
114 // the fault detection algorithm. For duration larger then this limit
115 // we bypass using durations calculated from QPC when jitter is detected,
116 // but don't touch the sUseQPC flag.
117 //
118 // Value is in [ms].
119 static const uint32_t kHardFailureLimit = 2000;
120 // Conversion to [mt]
121 static LONGLONG sHardFailureLimit;
123 // Conversion of kFailureFreeInterval and kFailureThreshold to [mt]
124 static LONGLONG sFailureFreeInterval;
125 static LONGLONG sFailureThreshold;
127 // ----------------------------------------------------------------------------
128 // Systemm status flags
129 // ----------------------------------------------------------------------------
131 // Flag for stable TSC that indicates platform where QPC is stable.
132 static bool sHasStableTSC = false;
134 // ----------------------------------------------------------------------------
135 // Global state variables, changing at runtime
136 // ----------------------------------------------------------------------------
138 // Initially true, set to false when QPC is found unstable and never
139 // returns back to true since that time.
140 static bool volatile sUseQPC = true;
142 // ----------------------------------------------------------------------------
143 // Global lock
144 // ----------------------------------------------------------------------------
146 // Thread spin count before entering the full wait state for sTimeStampLock.
147 // Inspired by Rob Arnold's work on PRMJ_Now().
148 static const DWORD kLockSpinCount = 4096;
150 // Common mutex (thanks the relative complexity of the logic, this is better
151 // then using CMPXCHG8B.)
152 // It is protecting the globals bellow.
153 static CRITICAL_SECTION sTimeStampLock;
155 // ----------------------------------------------------------------------------
156 // Global lock protected variables
157 // ----------------------------------------------------------------------------
159 // Timestamp in future until QPC must behave correctly.
160 // Set to now + kFailureFreeInterval on first QPC failure detection.
161 // Set to now + E * kFailureFreeInterval on following errors,
162 // where E is number of errors detected during last kFailureFreeInterval
163 // milliseconds, calculated simply as:
164 // E = (sFaultIntoleranceCheckpoint - now) / kFailureFreeInterval + 1.
165 // When E > kMaxFailuresPerInterval -> disable QPC.
166 //
167 // Kept in [mt]
168 static ULONGLONG sFaultIntoleranceCheckpoint = 0;
170 // Used only when GetTickCount64 is not available on the platform.
171 // Last result of GetTickCount call.
172 //
173 // Kept in [ms]
174 static DWORD sLastGTCResult = 0;
176 // Higher part of the 64-bit value of MozGetTickCount64,
177 // incremented atomically.
178 static DWORD sLastGTCRollover = 0;
180 namespace mozilla {
182 typedef ULONGLONG (WINAPI* GetTickCount64_t)();
183 static GetTickCount64_t sGetTickCount64 = nullptr;
185 // Function protecting GetTickCount result from rolling over,
186 // result is in [ms]
187 static ULONGLONG WINAPI
188 MozGetTickCount64()
189 {
190 DWORD GTC = ::GetTickCount();
192 // Cheaper then CMPXCHG8B
193 AutoCriticalSection lock(&sTimeStampLock);
195 // Pull the rollover counter forward only if new value of GTC goes way
196 // down under the last saved result
197 if ((sLastGTCResult > GTC) && ((sLastGTCResult - GTC) > (1UL << 30)))
198 ++sLastGTCRollover;
200 sLastGTCResult = GTC;
201 return ULONGLONG(sLastGTCRollover) << 32 | sLastGTCResult;
202 }
204 // Result is in [mt]
205 static inline ULONGLONG
206 PerformanceCounter()
207 {
208 LARGE_INTEGER pc;
209 ::QueryPerformanceCounter(&pc);
210 return pc.QuadPart * 1000ULL;
211 }
213 static void
214 InitThresholds()
215 {
216 DWORD timeAdjustment = 0, timeIncrement = 0;
217 BOOL timeAdjustmentDisabled;
218 GetSystemTimeAdjustment(&timeAdjustment,
219 &timeIncrement,
220 &timeAdjustmentDisabled);
222 LOG(("TimeStamp: timeIncrement=%d [100ns]", timeIncrement));
224 if (!timeIncrement)
225 timeIncrement = kDefaultTimeIncrement;
227 // Ceiling to a millisecond
228 // Example values: 156001, 210000
229 DWORD timeIncrementCeil = timeIncrement;
230 // Don't want to round up if already rounded, values will be: 156000, 209999
231 timeIncrementCeil -= 1;
232 // Convert to ms, values will be: 15, 20
233 timeIncrementCeil /= 10000;
234 // Round up, values will be: 16, 21
235 timeIncrementCeil += 1;
236 // Convert back to 100ns, values will be: 160000, 210000
237 timeIncrementCeil *= 10000;
239 // How many milli-ticks has the interval rounded up
240 LONGLONG ticksPerGetTickCountResolutionCeiling =
241 (int64_t(timeIncrementCeil) * sFrequencyPerSec) / 10000LL;
243 // GTC may jump by 32 (2*16) ms in two steps, therefor use the ceiling value.
244 sGTCResulutionThreshold =
245 LONGLONG(kGTCTickLeapTolerance * ticksPerGetTickCountResolutionCeiling);
247 sHardFailureLimit = ms2mt(kHardFailureLimit);
248 sFailureFreeInterval = ms2mt(kFailureFreeInterval);
249 sFailureThreshold = ms2mt(kFailureThreshold);
250 }
252 static void
253 InitResolution()
254 {
255 // 10 total trials is arbitrary: what we're trying to avoid by
256 // looping is getting unlucky and being interrupted by a context
257 // switch or signal, or being bitten by paging/cache effects
259 ULONGLONG minres = ~0ULL;
260 int loops = 10;
261 do {
262 ULONGLONG start = PerformanceCounter();
263 ULONGLONG end = PerformanceCounter();
265 ULONGLONG candidate = (end - start);
266 if (candidate < minres)
267 minres = candidate;
268 } while (--loops && minres);
270 if (0 == minres) {
271 minres = 1;
272 }
274 // Converting minres that is in [mt] to nanosecods, multiplicating
275 // the argument to preserve resolution.
276 ULONGLONG result = mt2ms(minres * kNsPerMillisec);
277 if (0 == result) {
278 result = 1;
279 }
281 sResolution = result;
283 // find the number of significant digits in mResolution, for the
284 // sake of ToSecondsSigDigits()
285 ULONGLONG sigDigs;
286 for (sigDigs = 1;
287 !(sigDigs == result
288 || 10*sigDigs > result);
289 sigDigs *= 10);
291 sResolutionSigDigs = sigDigs;
292 }
294 // ----------------------------------------------------------------------------
295 // TimeStampValue implementation
296 // ----------------------------------------------------------------------------
298 TimeStampValue::TimeStampValue(ULONGLONG aGTC, ULONGLONG aQPC, bool aHasQPC)
299 : mGTC(aGTC)
300 , mQPC(aQPC)
301 , mHasQPC(aHasQPC)
302 , mIsNull(false)
303 {
304 }
306 TimeStampValue&
307 TimeStampValue::operator+=(const int64_t aOther)
308 {
309 mGTC += aOther;
310 mQPC += aOther;
311 return *this;
312 }
314 TimeStampValue&
315 TimeStampValue::operator-=(const int64_t aOther)
316 {
317 mGTC -= aOther;
318 mQPC -= aOther;
319 return *this;
320 }
322 // If the duration is less then two seconds, perform check of QPC stability
323 // by comparing both GTC and QPC calculated durations of this and aOther.
324 uint64_t
325 TimeStampValue::CheckQPC(const TimeStampValue &aOther) const
326 {
327 uint64_t deltaGTC = mGTC - aOther.mGTC;
329 if (!mHasQPC || !aOther.mHasQPC) // Both not holding QPC
330 return deltaGTC;
332 uint64_t deltaQPC = mQPC - aOther.mQPC;
334 if (sHasStableTSC) // For stable TSC there is no need to check
335 return deltaQPC;
337 if (!sUseQPC) // QPC globally disabled
338 return deltaGTC;
340 // Check QPC is sane before using it.
341 int64_t diff = DeprecatedAbs(int64_t(deltaQPC) - int64_t(deltaGTC));
342 if (diff <= sGTCResulutionThreshold)
343 return deltaQPC;
345 // Treat absolutely for calibration purposes
346 int64_t duration = DeprecatedAbs(int64_t(deltaGTC));
347 int64_t overflow = diff - sGTCResulutionThreshold;
349 LOG(("TimeStamp: QPC check after %llums with overflow %1.4fms",
350 mt2ms(duration), mt2ms_f(overflow)));
352 if (overflow <= sFailureThreshold) // We are in the limit, let go.
353 return deltaQPC; // XXX Should we return GTC here?
355 // QPC deviates, don't use it, since now this method may only return deltaGTC.
356 LOG(("TimeStamp: QPC jittered over failure threshold"));
358 if (duration < sHardFailureLimit) {
359 // Interval between the two time stamps is very short, consider
360 // QPC as unstable and record a failure.
361 uint64_t now = ms2mt(sGetTickCount64());
363 AutoCriticalSection lock(&sTimeStampLock);
365 if (sFaultIntoleranceCheckpoint && sFaultIntoleranceCheckpoint > now) {
366 // There's already been an error in the last fault intollerant interval.
367 // Time since now to the checkpoint actually holds information on how many
368 // failures there were in the failure free interval we have defined.
369 uint64_t failureCount = (sFaultIntoleranceCheckpoint - now + sFailureFreeInterval - 1) /
370 sFailureFreeInterval;
371 if (failureCount > kMaxFailuresPerInterval) {
372 sUseQPC = false;
373 LOG(("TimeStamp: QPC disabled"));
374 }
375 else {
376 // Move the fault intolerance checkpoint more to the future, prolong it
377 // to reflect the number of detected failures.
378 ++failureCount;
379 sFaultIntoleranceCheckpoint = now + failureCount * sFailureFreeInterval;
380 LOG(("TimeStamp: recording %dth QPC failure", failureCount));
381 }
382 }
383 else {
384 // Setup fault intolerance checkpoint in the future for first detected error.
385 sFaultIntoleranceCheckpoint = now + sFailureFreeInterval;
386 LOG(("TimeStamp: recording 1st QPC failure"));
387 }
388 }
390 return deltaGTC;
391 }
393 uint64_t
394 TimeStampValue::operator-(const TimeStampValue &aOther) const
395 {
396 if (mIsNull && aOther.mIsNull)
397 return uint64_t(0);
399 return CheckQPC(aOther);
400 }
402 // ----------------------------------------------------------------------------
403 // TimeDuration and TimeStamp implementation
404 // ----------------------------------------------------------------------------
406 double
407 TimeDuration::ToSeconds() const
408 {
409 // Converting before arithmetic avoids blocked store forward
410 return double(mValue) / (double(sFrequencyPerSec) * 1000.0);
411 }
413 double
414 TimeDuration::ToSecondsSigDigits() const
415 {
416 // don't report a value < mResolution ...
417 LONGLONG resolution = sResolution;
418 LONGLONG resolutionSigDigs = sResolutionSigDigs;
419 LONGLONG valueSigDigs = resolution * (mValue / resolution);
420 // and chop off insignificant digits
421 valueSigDigs = resolutionSigDigs * (valueSigDigs / resolutionSigDigs);
422 return double(valueSigDigs) / kNsPerSecd;
423 }
425 TimeDuration
426 TimeDuration::FromMilliseconds(double aMilliseconds)
427 {
428 return TimeDuration::FromTicks(int64_t(ms2mt(aMilliseconds)));
429 }
431 TimeDuration
432 TimeDuration::Resolution()
433 {
434 return TimeDuration::FromTicks(int64_t(sResolution));
435 }
437 static bool
438 HasStableTSC()
439 {
440 union {
441 int regs[4];
442 struct {
443 int nIds;
444 char cpuString[12];
445 };
446 } cpuInfo;
448 __cpuid(cpuInfo.regs, 0);
449 // Only allow Intel CPUs for now
450 // The order of the registers is reg[1], reg[3], reg[2]. We just adjust the
451 // string so that we can compare in one go.
452 if (_strnicmp(cpuInfo.cpuString, "GenuntelineI", sizeof(cpuInfo.cpuString)))
453 return false;
455 int regs[4];
457 // detect if the Advanced Power Management feature is supported
458 __cpuid(regs, 0x80000000);
459 if (regs[0] < 0x80000007)
460 return false;
462 __cpuid(regs, 0x80000007);
463 // if bit 8 is set than TSC will run at a constant rate
464 // in all ACPI P-state, C-states and T-states
465 return regs[3] & (1 << 8);
466 }
468 nsresult
469 TimeStamp::Startup()
470 {
471 // Decide which implementation to use for the high-performance timer.
473 HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll");
474 sGetTickCount64 = reinterpret_cast<GetTickCount64_t>
475 (GetProcAddress(kernelDLL, "GetTickCount64"));
476 if (!sGetTickCount64) {
477 // If the platform does not support the GetTickCount64 (Windows XP doesn't),
478 // then use our fallback implementation based on GetTickCount.
479 sGetTickCount64 = MozGetTickCount64;
480 }
482 InitializeCriticalSectionAndSpinCount(&sTimeStampLock, kLockSpinCount);
484 sHasStableTSC = HasStableTSC();
485 LOG(("TimeStamp: HasStableTSC=%d", sHasStableTSC));
487 LARGE_INTEGER freq;
488 sUseQPC = ::QueryPerformanceFrequency(&freq);
489 if (!sUseQPC) {
490 // No Performance Counter. Fall back to use GetTickCount.
491 InitResolution();
493 LOG(("TimeStamp: using GetTickCount"));
494 return NS_OK;
495 }
497 sFrequencyPerSec = freq.QuadPart;
498 LOG(("TimeStamp: QPC frequency=%llu", sFrequencyPerSec));
500 InitThresholds();
501 InitResolution();
503 return NS_OK;
504 }
506 void
507 TimeStamp::Shutdown()
508 {
509 DeleteCriticalSection(&sTimeStampLock);
510 }
512 TimeStamp
513 TimeStamp::Now(bool aHighResolution)
514 {
515 // sUseQPC is volatile
516 bool useQPC = (aHighResolution && sUseQPC);
518 // Both values are in [mt] units.
519 ULONGLONG QPC = useQPC ? PerformanceCounter() : uint64_t(0);
520 ULONGLONG GTC = ms2mt(sGetTickCount64());
521 return TimeStamp(TimeStampValue(GTC, QPC, useQPC));
522 }
524 // Computes and returns the process uptime in microseconds.
525 // Returns 0 if an error was encountered.
527 uint64_t
528 TimeStamp::ComputeProcessUptime()
529 {
530 SYSTEMTIME nowSys;
531 GetSystemTime(&nowSys);
533 FILETIME now;
534 bool success = SystemTimeToFileTime(&nowSys, &now);
536 if (!success)
537 return 0;
539 FILETIME start, foo, bar, baz;
540 success = GetProcessTimes(GetCurrentProcess(), &start, &foo, &bar, &baz);
542 if (!success)
543 return 0;
545 ULARGE_INTEGER startUsec = {
546 start.dwLowDateTime,
547 start.dwHighDateTime
548 };
549 ULARGE_INTEGER nowUsec = {
550 now.dwLowDateTime,
551 now.dwHighDateTime
552 };
554 return (nowUsec.QuadPart - startUsec.QuadPart) / 10ULL;
555 }
557 } // namespace mozilla