112

What is the difference between std::system_clock and std::steady_clock? (An example case that illustrate different results/behaviours would be great).

If my goal is to precisely measure execution time of functions (like a benchmark), what would be the best choice between std::system_clock, std::steady_clock and std::high_resolution_clock?

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
Vincent
  • 57,703
  • 61
  • 205
  • 388
  • 11
    To start with, the system_clock may not be steady. – James McNellis Nov 07 '12 at 04:52
  • @James McNellis, that's true, but in practice the `system_clock` will only be non-steady on fantasy computers that the C++ standard tries to accommodate. The thing is, `system_clock` maps to `std::time_t` values (C-style time), and I know of no platform (no non-exotic or ancient platform at least) where the C `std::time()` function is *not* the same as POSIX time. And POSIX time is, by definition, "steady". – Charles Salvia Sep 09 '15 at 18:25
  • 12
    @CharlesSalvia I can't speak for other platforms, but the `system_clock` is not steady on Windows. On Windows, the system time may be altered to any arbitrary value by any sufficiently privileged user. Additionally, the time synchronziation service may adjust the system time backwards if required. I expect most other platforms have similar features that permit adjustment of the system time. – James McNellis Sep 09 '15 at 18:41
  • 3
    @Charles: Most POSIX boxes I know of are similarly affected and will have their time change if the user changes the time. – Billy ONeal Sep 09 '15 at 20:54
  • 6
    Video answer to this question: http://www.youtube.com/watch?v=P32hvk8b13M&t=48m44s – Howard Hinnant Dec 17 '16 at 22:40
  • 1
    @CharlesSalvia. Per my own experience analyzing timing output from dozens of PC data acquisition systems, time from a computer is not steady. Linux, Windows, and the specific system calls used are unknown, but the commonality is frequent negative time differences between subsequent time values. Straight-line time is not the norm. – Tyson Hilmer Dec 08 '17 at 08:45

5 Answers5

80

From N3376:

20.11.7.1 [time.clock.system]/1:

Objects of class system_clock represent wall clock time from the system-wide realtime clock.

20.11.7.2 [time.clock.steady]/1:

Objects of class steady_clock represent clocks for which values of time_point never decrease as physical time advances and for which values of time_point advance at a steady rate relative to real time. That is, the clock may not be adjusted.

20.11.7.3 [time.clock.hires]/1:

Objects of class high_resolution_clock represent clocks with the shortest tick period. high_resolution_clock may be a synonym for system_clock or steady_clock.

For instance, the system wide clock might be affected by something like daylight savings time, at which point the actual time listed at some point in the future can actually be a time in the past. (E.g. in the US, in the fall time moves back one hour, so the same hour is experienced "twice") However, steady_clock is not allowed to be affected by such things.

Another way of thinking about "steady" in this case is in the requirements defined in the table of 20.11.3 [time.clock.req]/2:

In Table 59 C1 and C2 denote clock types. t1 and t2 are values returned by C1::now() where the call returning t1 happens before the call returning t2 and both of these calls occur before C1::time_point::max(). [ Note: this means C1 did not wrap around between t1 and t2. —end note ]

Expression: C1::is_steady
Returns: const bool
Operational Semantics: true if t1 <= t2 is always true and the time between clock ticks is constant, otherwise false.

That's all the standard has on their differences.

If you want to do benchmarking, your best bet is probably going to be std::high_resolution_clock, because it is likely that your platform uses a high resolution timer (e.g. QueryPerformanceCounter on Windows) for this clock. However, if you're benchmarking, you should really consider using platform specific timers for your benchmark, because different platforms handle this differently. For instance, some platforms might give you some means of determining the actual number of clock ticks the program required (independent of other processes running on the same CPU). Better yet, get your hands on a real profiler and use that.

Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • This is correct, of course - but `system_clock` is the only clock that maps to C time (i.e. to `std::time_t` values), and the C `time()` function is almost always the same as POSIX time (I know of no platform where it's not) - and POSIX time is, by definition, "steady" - it's not affected by daylight savings or anything like that. So the result is that in practice, `system_clock` *always* meets the requirements of `steady_clock`, except on exotic platforms that don't use POSIX time for C style time. – Charles Salvia Sep 09 '15 at 18:19
  • 1
    @Charles: Care to point out in the standard where that is the case? It seems to clearly indicate the opposite. – Billy ONeal Sep 09 '15 at 18:56
  • 10
    @Charles: Also, POSIX time is not "steady" -- if the user changes the time setting on their computer POSIX time will change. If you are cooking an egg, and need a timer that lasts 4 minutes, then you need it to last 4 minutes even if the current time is changed. If you've got a timer set for a meeting on the 5th at 3, then you absolutely need that timer to change if the local time changes. Hence the difference between `steady_clock` and `system_clock` here. – Billy ONeal Sep 09 '15 at 20:54
  • @BillyONeal I think that the remarks in your last comment are correct but daylight saving time is still not among the reasons `std::chrono::system_cklock` may change as you still have to convert its result to local time using the corresponding C function. So changes to time as caused by an NTP daemon or the user manually adjusting the clock would be a better example, IMHO. I do realize that there are bizarre systems that think in local time and for those, your example would apply. – 5gon12eder Dec 17 '15 at 02:00
  • 2
    @5gon: Nothing requires that `system_clock` be UTC. – Billy ONeal Dec 17 '15 at 03:33
  • 1
    @CharlesSalvia Please also note that since POSIX time is tied to UTC, and UTC has leap seconds (cf. https://en.wikipedia.org/wiki/Unix_time#Leap_seconds). That means that even if the time on a machine is never adjusted, C/POSIX time may be non-monotonic. – Michael Schlottke-Lakemper Jan 11 '16 at 13:19
  • `std::system_clock` is not affected by daylight savings. `std::system_clock` is the number of periods (seconds, milliseconds, etc...) passed from the *epoch*, and that number of periods is not adjusted by daylight savings. It's a **calendar time** which is affected by daylight savings, so the different values of `std::system_clock::now` may be mapped to the same calendar time, but even in this case `tm_isdst` flag will be different. (see `system_clock::to_time_t` and `std::localtime`) – anton_rh May 25 '16 at 01:51
  • 1
    @anton_rh: There is no such requirement that the number of periods is not adjusted for DST. – Billy ONeal May 25 '16 at 02:17
  • 3
    UPDATE (Visual Studio 2015) The implementation of steady_clock has changed [.....] steady_clock is now based on QueryPerformanceCounter() and high_resolution_clock is now a typedef for steady_clock. Quoted from https://msdn.microsoft.com/en-us/library/hh874757.aspx – felix-b Jan 14 '18 at 10:29
  • Just checked - mingw32's version of high_resolution_clock is less precise than steady_clock. Doesn't sense sub-millisecond time intervals. – ogurets Jun 28 '18 at 15:18
  • You are incorrect about the daylight saving time. DST do not affect unix time, They only affect how unix times are converted to human readable times. The system clock might be adjusted by the user, or by the system (if you have a process adjusting your system clock) – Arnaud Dec 20 '18 at 11:28
50

Billy provided a great answer based on the ISO C++ standard that I fully agree with. However there is another side of the story - real life. It seems that right now there is really no difference between those clocks in implementation of popular compilers:

gcc 4.8:

#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
   ...
#else
  typedef system_clock steady_clock;
#endif
  typedef system_clock high_resolution_clock;

Visual Studio 2012:

class steady_clock : public system_clock
{   // wraps monotonic clock
public:
  static const bool is_monotonic = true;    // retained
  static const bool is_steady = true;
};

typedef system_clock high_resolution_clock;

In case of gcc you can check if you deal with steady clock simply by checking is_steady and behave accordingly. However VS2012 seems to cheat a bit here :-)

If you need high precision clock I recommend for now writing your own clock that conforms to C++11 official clock interface and wait for implementations to catch up. It will be much better approach than using OS specific API directly in your code. For Windows you can do it like that:

// Self-made Windows QueryPerformanceCounter based C++11 API compatible clock
struct qpc_clock {
  typedef std::chrono::nanoseconds                       duration;      // nanoseconds resolution
  typedef duration::rep                                  rep;
  typedef duration::period                               period;
  typedef std::chrono::time_point<qpc_clock, duration>   time_point;
  static bool is_steady;                                                // = true
  static time_point now()
  {
    if(!is_inited) {
      init();
      is_inited = true;
    }
    LARGE_INTEGER counter;
    QueryPerformanceCounter(&counter);
    return time_point(duration(static_cast<rep>((double)counter.QuadPart / frequency.QuadPart *
                                                period::den / period::num)));
  }

private:
  static bool is_inited;                                                // = false
  static LARGE_INTEGER frequency;
  static void init()
  {
    if(QueryPerformanceFrequency(&frequency) == 0)
      throw std::logic_error("QueryPerformanceCounter not supported: " + std::to_string(GetLastError()));
  }
};

For Linux it is even easier. Just read the man page of clock_gettime and modify the code above.

Mateusz Pusz
  • 1,363
  • 1
  • 9
  • 16
  • 20
    The VC++ 2012 implementation has been acknowledged as a bug by MS's standard library maintainer. – ildjarn Nov 07 '12 at 19:16
  • 5
    For those interested, [this is a link to that bug](https://connect.microsoft.com/VisualStudio/feedback/details/719443) – Ben Voigt Jul 15 '13 at 13:55
  • 1
    Boost uses QueryPerformanceCounter, so using boost::chrono is a good workaround this bug till Visual Studio 14 is released – Mohamed El-Nakeep Jun 19 '14 at 11:56
  • And here are the POSIX calls those forward to on GCC 5.3.0: http://stackoverflow.com/a/36700301/895245 – Ciro Santilli OurBigBook.com Apr 23 '16 at 14:19
  • 1
    Latest MS STL std::system_clock wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime and std::steady_clock/std::high_resolution_clock wraps QueryPerformanceCounter https://github.com/microsoft/STL/blob/2f03bdf361f7f153b4216c60a0d9491c0be13a73/stl/inc/__msvc_chrono.hpp#L638-L697 – KindDragon Sep 26 '22 at 21:09
24

GCC 5.3.0 implementation

C++ stdlib is inside GCC source:

  • high_resolution_clock is an alias for system_clock
  • system_clock forwards to the first of the following that is available:
    • clock_gettime(CLOCK_REALTIME, ...)
    • gettimeofday
    • time
  • steady_clock forwards to the first of the following that is available:
    • clock_gettime(CLOCK_MONOTONIC, ...)
    • system_clock

Then CLOCK_REALTIME vs CLOCK_MONOTONIC is explained at: Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
  • cf.> MSVC: `high_resolution_clock` is an alias for `steady_clock` in std::chrono, and `steady_clock` uses QueryPerformanceCounter and QueryPerformanceFrequency. (Visual Studio 2015 and (maybe) beyond) – starriet Oct 08 '22 at 02:05
7

Relevant talk about chrono by Howard Hinnant, author of chrono:

don't use high_resolution_clock, as it's an alias for one of these:

  • system_clock: it's like a regular clock, use it for time/date related stuff
  • steady_clock: it's like a stopwatch, use it for timing things.
Adrià Arrufat
  • 413
  • 6
  • 6
6

Maybe, the most significant difference is the fact that the starting point of std::chrono:system_clock is the 1.1.1970, so-called UNIX-epoch. On the other side, for std::chrono::steady_clock typically the boot time of your PC and it's most suitable for measuring intervals.

Silviu
  • 103
  • 1
  • 7