std::chrono::high_resolution_clock based frame timer

885 views Asked by At

I have been using the following clock definition for a frame timer for years now:

    using frame_clock = std::conditional_t<
        std::chrono::high_resolution_clock::is_steady,
        std::chrono::high_resolution_clock,
        std::chrono::steady_clock>;

In other words, I want a clock that is defined using the highest possible resolution, but it must increment monotonically. Note that MSVC currently uses the following alias to define std::chrono::high_resolution_clock:

    using high_resolution_clock = steady_clock;

Therefore, on MSVC, the alias I have defined will just use std::chrono::steady_clock. This is not necessarily true for libstdc++ and libc++, hence the use of the alias.

Recently, I stumbled across a footnote here: https://en.cppreference.com/w/cpp/chrono/high_resolution_clock

Notice that cppreference explicitly discourages the use of std::chrono::high_resolution_clock. Their rationale was that the clock varies by implementation... but isn't this true for std::chrono::steady_clock and std::chrono::system_clock as well? For instance, I was unable to find anything that guaranteed that the clock periods between clocks must be in certain units. In fact, I understand that is by design.

My question is, after having used std::chrono::high_resolution_clock for so many years (for frame timers and benchmarks), should I be more concerned than I am? Even here on this site, I see many recommendations to use std::chrono::high_resolution_clock, despite what this footnote says. Any kind of further insight on this disparity, or examples of where this could cause problems would be much appreciated.

3

There are 3 answers

8
SergeyA On BEST ANSWER

For practical purposes, you only have 3 choices:

  • For taking real time, your only choice is std::system_clock (if you want to stay inside C++, OS levels routines do exist)
  • For measuring intervals, if you want to stay within C++, you have to use std::steady_clock. There is no implementation out there which would have a steady clock with resolution higher than you get with std::steady_clock
  • Viable alternative to above if you are eager to sacrifice C++ conformance is using TSC counters directly. This is highest possible resolution one can ever see and is also the fastest to use. The downside is that if you want to measure units of time rather than cycles, you'd have to convert cycles to seconds using CPU cycle rate.
10
Howard Hinnant On

What you've read is essentially the advice I have been giving for the past handful of years.

It isn't that high_resolution_clock is dangerous. It is just that it is rather useless. This is because it is always aliased to either system_clock or steady_clock. And so you might as well choose system_clock or steady_clock so that you know which one you're getting.

steady_clock always has is_steady == true. That's a requirement. Additionally system_clock never has is_steady == true. It isn't actually a requirement, but unless your computer has a clock that keeps perfect time, it will need adjusting occasionally to set it to the correct time. And a clock that can be adjusted must have is_steady == false.

Your frame_clock alias is just a fancy way of saying:

using frame_clock = std::chrono::steady_clock;
0
Casey On

Yes, you should be concerned. high_resolution_clock is implementation defined. Don't let the implementaiton pick, just use steady_clock directly.

Howard Hinnant wrote a great comparison between steady and system clocks and wishes he had never added high_resolution_clock in the first place.

As before, stick to using std::chrono::steady_clock directly instead of letting the implementation pick.