Skip to content

<chrono>: std::chrono::steady_clock::now() overflow #971

@slay-er

Description

@slay-er

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!high priorityImportant!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions