xpcom/ds/TimeStamp_windows.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial