TimeStamp_windows.cpp (4558B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 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/. */ 6 7 #include "mozilla/DynamicallyLinkedFunctionPtr.h" 8 #include "mozilla/TimeStamp.h" 9 #include <intrin.h> 10 #include <windows.h> 11 12 // Historical note: We used to sample both QueryPerformanceCounter (QPC) and 13 // GetTickCount (GTC) timestamps in the past, as very early implementations of 14 // QPC were buggy. We had heuristics to determine if QPC is unreliable and 15 // would have switched to GTC in case, which could cause unexpected time 16 // travels between QPC and GPC values when that occured. 17 // 18 // Since Windows 8 together with the then modern CPUs, QPC became both reliable 19 // and almost as fast as GTC timestamps and provides a much higher resolution. 20 // QPC in general exists long enough even on older systems than Windows 8, such 21 // that we can just always rely on it, as we do in rust. 22 23 // ---------------------------------------------------------------------------- 24 // Global variables, not changing at runtime 25 // ---------------------------------------------------------------------------- 26 27 // Result of QueryPerformanceFrequency, set only once on startup. 28 static double sTicksPerSecd; 29 static double sTicksPerMsd; 30 31 // ---------------------------------------------------------------------------- 32 // Useful constants 33 // ---------------------------------------------------------------------------- 34 35 static constexpr double kMsPerSecd = 1000.0; 36 37 namespace mozilla { 38 39 // Result is in ticks. 40 static inline ULONGLONG PerformanceCounter() { 41 LARGE_INTEGER pc; 42 MOZ_ALWAYS_TRUE(::QueryPerformanceCounter(&pc)); 43 return pc.QuadPart; 44 } 45 46 static void InitConstants() { 47 // Query the frequency from QPC and rely on it for all values. 48 // Note: The resolution used to be sampled based on a loop of QPC calls. 49 // While it is true that on most systems we cannot expect to subsequently 50 // sample QPC values as fast as the QPC frequency, we still will get that 51 // as resolution of the sampled values, that is we have 1 tick resolution. 52 LARGE_INTEGER freq; 53 bool hasQPC = ::QueryPerformanceFrequency(&freq); 54 MOZ_RELEASE_ASSERT(hasQPC); 55 sTicksPerSecd = double(freq.QuadPart); 56 sTicksPerMsd = sTicksPerSecd / kMsPerSecd; 57 } 58 59 // ---------------------------------------------------------------------------- 60 // TimeDuration and TimeStamp implementation 61 // ---------------------------------------------------------------------------- 62 63 MFBT_API double BaseTimeDurationPlatformUtils::ToSeconds(int64_t aTicks) { 64 return double(aTicks) / sTicksPerSecd; 65 } 66 67 MFBT_API int64_t 68 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(double aMilliseconds) { 69 double result = sTicksPerMsd * aMilliseconds; 70 // NOTE: this MUST be a >= test, because int64_t(double(INT64_MAX)) 71 // overflows and gives INT64_MIN. 72 if (result >= double(INT64_MAX)) { 73 return INT64_MAX; 74 } 75 if (result <= double(INT64_MIN)) { 76 return INT64_MIN; 77 } 78 79 return (int64_t)result; 80 } 81 82 // Note that we init early enough during startup such that we are supposed to 83 // not yet have started other threads which could try to use us. 84 static bool gInitialized = false; 85 86 MFBT_API void TimeStamp::Startup() { 87 if (gInitialized) { 88 return; 89 } 90 InitConstants(); 91 gInitialized = true; 92 } 93 94 MFBT_API void TimeStamp::Shutdown() {} 95 96 MFBT_API TimeStamp TimeStamp::Now(bool aHighResolution) { 97 MOZ_ASSERT(gInitialized); 98 return TimeStamp((TimeStampValue)PerformanceCounter()); 99 } 100 101 // Computes and returns the process uptime in microseconds. 102 // Returns 0 if an error was encountered. 103 104 MFBT_API uint64_t TimeStamp::ComputeProcessUptime() { 105 FILETIME start, foo, bar, baz; 106 bool success = GetProcessTimes(GetCurrentProcess(), &start, &foo, &bar, &baz); 107 if (!success) { 108 return 0; 109 } 110 111 static const StaticDynamicallyLinkedFunctionPtr<void(WINAPI*)(LPFILETIME)> 112 pGetSystemTimePreciseAsFileTime(L"kernel32.dll", 113 "GetSystemTimePreciseAsFileTime"); 114 115 FILETIME now; 116 if (pGetSystemTimePreciseAsFileTime) { 117 pGetSystemTimePreciseAsFileTime(&now); 118 } else { 119 GetSystemTimeAsFileTime(&now); 120 } 121 122 ULARGE_INTEGER startUsec = {{start.dwLowDateTime, start.dwHighDateTime}}; 123 ULARGE_INTEGER nowUsec = {{now.dwLowDateTime, now.dwHighDateTime}}; 124 125 return (nowUsec.QuadPart - startUsec.QuadPart) / 10ULL; 126 } 127 128 } // namespace mozilla