-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Describe the bug
I encountered an overflow issue with std::chrono::steady_clock::now() after ~923 seconds (~15 minutes).
Just copied some source from the original implementation to demonstrate the issue.
Test sample
#include <cassert>
#include <chrono>
_NODISCARD static long long _Scale_large_counter(const long long _Ctr, const long long _Freq) noexcept {
const long long _Whole = (_Ctr / _Freq) * std::nano::den;
const long long _Part = (_Ctr % _Freq) * std::nano::den / _Freq;
return _Whole + _Part;
}
int main(int argc, char* argv[])
{
static volatile long long _Cached_freq = LLONG_MAX;
static volatile long long _Cached_ctr_base = LLONG_MAX;
static volatile long long _Cached_result_base = LLONG_MAX;
{
const long long _Freq = _Query_perf_frequency();
const long long _Ctr = _Query_perf_counter();
const long long _Result = _Scale_large_counter(_Ctr, _Freq);
_Cached_freq = _Freq;
_Cached_ctr_base = _Ctr;
_Cached_result_base = _Result;
}
const long long _Freq_from_cache = _Cached_freq;
const long long _Ctr_base = _Cached_ctr_base;
const long long _Result_base = _Cached_result_base;
for (long long i = 1; i > 0; i += 1) {
const long long _Ctr = _Ctr_base + i * 10000000;
const long long now = _Result_base + (_Ctr - _Ctr_base) * std::nano::den / _Freq_from_cache;
assert(now > _Result_base);
}
return 0;
}
Expected behavior
The overflow should happen at the earliest after 100 years as described on MSDN.
https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
How often does QPC roll over?
Not less than 100 years from the most recent system boot, and potentially longer based on the underlying hardware timer used. For most applications, rollover isn't a concern.
STL version
- Option 1: Visual Studio version
Microsoft Visual Studio Enterprise 2019 Preview Version 16.7.0 Preview 3.0
Additional context
I think the formula to compute now is wrong:
_Result_base + (_Ctr - _Ctr_base) * std::nano::den / _Freq_from_cache
The multiplication by std::nano::den results in a negative value which then is divided.
The formula should be:
_Result_base + (_Ctr - _Ctr_base) * (std::nano::den / _Freq_from_cache)
Also tracked by DevCom-1105325 and Microsoft-internal VSO-1153359 / AB#1153359.