high_resolution_clock is apparently not guaranteed to advance while its thread is sleeping

1,360 views
Skip to first unread message

kyle.j...@gmail.com

unread,
Jul 7, 2016, 7:14:03 PM7/7/16
to ISO C++ Standard - Discussion
It seems reasonable to expect that `std::high_resolution_clock` would be a good tool to use with the timers provided by the standard library.

However, it's not clear from the standard that high_resolution_clock will be synchronized with any kind of "realtime" system clock, so the clock itself may stop updating when the thread it's in sleeps. This means that implementations may be allowed to provide `high_resolution_clock` without any guarantee that using `std::this_thread::sleep_until` with a `high_resolution_clock` timepoint will behave as expected: the thread could simply sleep forever.

This seems counterintuitive and dangerous, and also does not seem to be the intent of `high_resolution_clock`, especially given the suggestion that "`high_resolution_clock` may be a synonym for `system_clock` or `steady_clock`" in 20.13.7.3. (Note that both `system_clock` and `steady_clock` *are* guaranteed to be synchronized with a "realtime" system clock.) I suggest that this is a bug.

A more complete explanation of the issue can be found in this StackOverflow answer (which I wrote): http://stackoverflow.com/a/38253266/1858225

Howard Hinnant

unread,
Jul 7, 2016, 7:18:18 PM7/7/16
to std-dis...@isocpp.org
I would not be opposed to deprecating high_resolution_clock, with the intent to remove it after a suitable period of deprecation. The reality is that it is always a typedef to either steady_clock or system_clock, and the programmer is better off choosing one of those two and know what he’s getting, than choose high_resolution_clock and get some other clock by a roll of the dice.

I put it in C++11. My bad. I made a mistake.

Howard

signature.asc

Nicol Bolas

unread,
Jul 7, 2016, 7:53:25 PM7/7/16
to ISO C++ Standard - Discussion

I don't think that's the right answer. Neither steady_clock nor system_clock is expected to have any particular resolution, so there is no impetus on implementations to give it any particular resolution. By having a third type, one which users will expect to have the highest resolution available, implementations can be held accountable for having a crappy high_resolution_clock (see the frequent lambasting that Microsoft's version of HRC has gotten until VS2015).

The concept of a high-resolution clock is a good one. The issue here is that the question the OP wants answered is not a question that the current clock systems can answer. Namely whether or not a clock's advancement is tied to thread operation. Oh yes, `is_steady` being true implies this, but a clock may not be steady yet still have this property.

It seems to me that what is needed is a `async_advance` property which guarantees that the clock will record time if the thread is not active. And we should require that this property be true for HRC.

Anthony Williams

unread,
Jul 11, 2016, 4:45:52 AM7/11/16
to std-dis...@isocpp.org
On 08/07/16 00:53, Nicol Bolas wrote:
>
>
> On Thursday, July 7, 2016 at 7:18:18 PM UTC-4, Howard Hinnant wrote:
>
> On Jul 7, 2016, at 7:14 PM, kyle.j...@gmail.com <javascript:> wrote:
> >
> > It seems reasonable to expect that `std::high_resolution_clock`
> would be a good tool to use with the timers provided by the standard
> library.
> >
> > However, it's not clear from the standard that
> high_resolution_clock will be synchronized with any kind of
> "realtime" system clock, so the clock itself may stop updating when
> the thread it's in sleeps. This means that implementations may be
> allowed to provide `high_resolution_clock` without any guarantee
> that using `std::this_thread::sleep_until` with a
> `high_resolution_clock` timepoint will behave as expected: the
> thread could simply sleep forever.
> >
>
> I would not be opposed to deprecating high_resolution_clock, with
> the intent to remove it after a suitable period of deprecation. The
> reality is that it is always a typedef to either steady_clock or
> system_clock, and the programmer is better off choosing one of those
> two and know what he’s getting, than choose high_resolution_clock
> and get some other clock by a roll of the dice.
>
> I put it in C++11. My bad. I made a mistake.
>
>
> I don't think that's the right answer. Neither steady_clock nor
> system_clock is expected to have any particular resolution, so there is
> no impetus on implementations to give it any particular resolution. By
> having a third type, one which users /will/ expect to have the highest
> resolution available, implementations can be held accountable for having
> a crappy high_resolution_clock (see the frequent lambasting that
> Microsoft's version of HRC has gotten until VS2015).
>
> The concept of a high-resolution clock is a good one. The issue here is
> that the question the OP wants answered is not a question that the
> current clock systems /can/ answer. Namely whether or not a clock's
> advancement is tied to thread operation. Oh yes, `is_steady` being true
> implies this, but a clock may not be steady yet still have this property.
>
> It seems to me that what is needed is a `async_advance` property which
> guarantees that the clock will record time if the thread is not active.
> And we should require that this property be true for HRC.

Agreed. I wouldn't want to lose high_resolution_clock, but it probably
ought to be steady. I don't think "async_advance" would be sufficient.

It doesn't have to be the same as steady_clock though: steady_clock can
be a "cheap" clock with low resolution, while high_resolution_clock
requires more of the system, but provides higher resolution. Provided
the additional overhead of the high_resolution_clock is pretty constant
(so can be easily eliminated from timings), and less than the resolution
of the steady_clock then it can be an improvement when timing operations.

Of course, the precise details are all QoI.

Anthony
--
Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/
just::thread C++11 thread library http://www.stdthread.co.uk
Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

Nicol Bolas

unread,
Jul 11, 2016, 9:57:07 AM7/11/16
to ISO C++ Standard - Discussion

Why does it need to be "steady"?

What HRC needs to do is continuously advance. But the advancing may not be at an exact, constant rate, which is what "steady" requires. What HRC shouldn't do is suddenly change due to outside stuff.

The problem with `is_steady` is that it enforces a lot of stuff:

1: No sudden changes due to external factors.
2: Always advances.
3: Advances at a fixed rate, within its accuracy.

If I recall correctly, the old Win32 QueryPerformanceCounter had issues on some CPUs where the moment-to-moment frequency of its ticks would vary. Over time it would average out, but while it might have clock-tick precision, the frequency wasn't always correct. Would such a clock be considered "steady"? No, because it violates #3: it does not advance at a truly fixed rate.

Anthony Williams

unread,
Jul 11, 2016, 10:08:45 AM7/11/16
to std-dis...@isocpp.org
That depends on what you mean by "within its accuracy". There is no way
to specify the "accuracy" of a clock.

The standard says "the time between clock ticks is constant", which is a
very high bar: are there any clocks on Earth for which that is truly the
case?

If we're not going to meet that goal, then it's QoI.

If the jitter in the QPC frequency means your measurements are +/- 1
microsecond, report clock::period == 1 microsecond if it makes you feel
better. It's still better than you'll likely get from the other clocks
on the system.

Incidentally, I use GetTickCount64() as the basis of my steady_clock on
Windows. This typically has a +/- 15ms resolution, but may be as good as
1ms. If I report a period of 1ms, but the value only updates every 15ms,
is that good enough for your definition of steady?

Andrey Semashev

unread,
Jul 11, 2016, 10:54:05 AM7/11/16
to std-dis...@isocpp.org
On 07/11/16 17:08, Anthony Williams wrote:
> On 11/07/16 14:57, Nicol Bolas wrote:
>> On Monday, July 11, 2016 at 4:45:52 AM UTC-4, Anthony Williams wrote:
>> Agreed. I wouldn't want to lose high_resolution_clock, but it probably
>> ought to be steady. I don't think "async_advance" would be sufficient.
>>
>>
>> Why does it need to be "steady"?
>>
>> What HRC needs to do is continuously advance. But the advancing may not
>> be at an exact, constant rate, which is what "steady" requires. What HRC
>> shouldn't do is suddenly change due to outside stuff.
>>
>> The problem with `is_steady` is that it enforces a lot of stuff:
>>
>> 1: No sudden changes due to external factors.
>> 2: Always advances.
>> 3: Advances at a fixed rate, within its accuracy.
>>
>> If I recall correctly, the old Win32 QueryPerformanceCounter had issues
>> on some CPUs where the moment-to-moment frequency of its ticks would
>> vary. Over time it would average out, but while it might have clock-tick
>> precision, the frequency wasn't always correct. Would such a clock be
>> considered "steady"? No, because it violates #3: it does not advance at
>> a truly fixed rate.
>
> That depends on what you mean by "within its accuracy". There is no way
> to specify the "accuracy" of a clock.
>
> The standard says "the time between clock ticks is constant", which is a
> very high bar: are there any clocks on Earth for which that is truly the
> case?

I'd like to think the standard doesn't require the implementation to
contradict the laws of General Relativity - after all, time and space
depends on mass and speed of the system, which the standard does not
describe at all. :)

I think the assumption is that the implementation must have an internal
clock which represents the contiguous timeline from the perspective of
this system. That clock can be backed by the CPU clock or a separate
clock source - that is irrelevant, as long as the source is part of the
system. The clock source can be imperfect from the point of view of
another system, like a human observer, but for the purpose of the
implementation that error is non-existent.

is_steady should return true when the particular C++ clock advances
strictly at the same rate as that clock source (i.e. a steady clock
represents the described above timeline). Non-steady clocks may have
varying rate of advancement in comparison to the steady clock, for
example, in attempt to synchronize with an external clock
source/timeline, like an NTP server. For example, in a fast moving
system steady_clock would advance in the same rate from perspective of
this system and realtime_clock (assuming it represents time on Earth)
would advance at a faster rate (again, from perspective of this system).

In this view, a clock that stops running at a certain point (e.g. when
the machine goes to sleep) and starts running again at the same rate
(e.g. upon wakeup) can still be considered steady. If the time of
sleeping cannot be observed by the program then that time does not
exist, as far as the program is concerned. That, of course, may or may
not be a good thing, which depends on the intention of the programmer.
This is why synchronizing between multiple clocks can be useful, and is
one thing that the current standard is lacking.

In practice though, I think it is typical to assume that the steady
clock does not stop even if the machine goes to sleep, although some
time-related services can fail to function properly (like, a timeout for
a wait on a condition variable will not fire while the machine is
sleeping; but it will fire as soon as the machine wakes up). I guess
that property of the steady clock can be considered an implementation
detail, although it would be nice to have some certainty from the standard.

Patrice Roy

unread,
Jul 11, 2016, 9:41:56 PM7/11/16
to std-dis...@isocpp.org
From the standard's point of view, can we really ask more than the fact that two successive calls to now() on a steady clock return ti, tj such that ti <= tj (modulo overflow, maybe)? I'm not sure we can be more restrictive than this in practice, to be honest. Anything stricter might be in the nice-to-have category, but it's difficult to see (AFAIK) how the standard could impose it in any meaningful way. The latest version of the standard I have states «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». I fail to see how we realistically could impose something more strict, to be honest.



--

--- You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.

Nicol Bolas

unread,
Jul 11, 2016, 11:59:55 PM7/11/16
to ISO C++ Standard - Discussion
On Monday, July 11, 2016 at 9:41:56 PM UTC-4, Patrice Roy wrote:
From the standard's point of view, can we really ask more than the fact that two successive calls to now() on a steady clock return ti, tj such that ti <= tj (modulo overflow, maybe)? I'm not sure we can be more restrictive than this in practice, to be honest. Anything stricter might be in the nice-to-have category, but it's difficult to see (AFAIK) how the standard could impose it in any meaningful way. The latest version of the standard I have states «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». I fail to see how we realistically could impose something more strict, to be honest.

The goal isn't to make `is_steady` say more. The goal is to ensure that the HPC is useful in the domain for which people want to use it (ie: performance testing). That's very possible; simply require two things:

1: The HPC advances in one direction only (part of `is_steady`, but `is_steady` requires more than this).
2: The HPC time's will not be tied into the advancement of any CPU thread.

I don't see why these would be problematic to standardize.

Thiago Macieira

unread,
Jul 12, 2016, 1:42:21 AM7/12/16
to std-dis...@isocpp.org
On segunda-feira, 11 de julho de 2016 20:59:55 PDT Nicol Bolas wrote:
> The goal isn't to make `is_steady` say more. The goal is to ensure that the
> HPC is useful in the domain for which people want to use it (ie:
> performance testing). That's very possible; simply require two things:
>
> 1: The HPC advances in one direction only (part of `is_steady`, but
> `is_steady` requires more than this).
> 2: The HPC time's will not be tied into the advancement of any CPU thread.
>
> I don't see why these would be problematic to standardize.

So long as the HPC itself is optional, sure.

I could argue that this requirement is not implementable with Linux right now:
if you suspend the OS, the monotonic clock stops. When the computer resumes,
the monotonic clock may have advanced (say) 2 seconds, but the real time
advanced 2 hours.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Nicol Bolas

unread,
Jul 12, 2016, 5:28:04 PM7/12/16
to ISO C++ Standard - Discussion


On Tuesday, July 12, 2016 at 1:42:21 AM UTC-4, Thiago Macieira wrote:
On segunda-feira, 11 de julho de 2016 20:59:55 PDT Nicol Bolas wrote:
> The goal isn't to make `is_steady` say more. The goal is to ensure that the
> HPC is useful in the domain for which people want to use it (ie:
> performance testing). That's very possible; simply require two things:
>
> 1: The HPC advances in one direction only (part of `is_steady`, but
> `is_steady` requires more than this).
> 2: The HPC time's will not be tied into the advancement of any CPU thread.
>
> I don't see why these would be problematic to standardize.

So long as the HPC itself is optional, sure.

I could argue that this requirement is not implementable with Linux right now:
if you suspend the OS, the monotonic clock stops. When the computer resumes,
the monotonic clock may have advanced (say) 2 seconds, but the real time
advanced 2 hours.

OK, then consider the advancement not being tied to the application's update. It can be tied to the overall system updating.

Thiago Macieira

unread,
Jul 12, 2016, 7:28:23 PM7/12/16
to std-dis...@isocpp.org
Em terça-feira, 12 de julho de 2016, às 14:28:04 PDT, Nicol Bolas escreveu:
> > So long as the HPC itself is optional, sure.
> >
> > I could argue that this requirement is not implementable with Linux right
> > now:
> > if you suspend the OS, the monotonic clock stops. When the computer
> > resumes,
> > the monotonic clock may have advanced (say) 2 seconds, but the real time
> > advanced 2 hours.
>
> OK, then consider the advancement not being tied to the application's
> update. It can be tied to the overall system updating.

I would tie it to some observability. For example:

Thread A

read(pipe[0], &c, 1); // wait for thread B
auto afterA = std::whichever_clock::now();

Thread B:

do_some_work();
auto afterB = std::whichever_clock::now();
write(pipe[1], "", 1);

There's clearly a happens-before relationship between the call to now() in
Thread B and the call to now() in Thread A. So we must have:

afterA >= afterB

even if Thread A spent 2 hours sleeping on that read(2) call.

Similarly, I'd like to have both std::steady_clock and std::HPC mandate -- or
at least have a getter indicating -- the value it returns be comparable to the
value that the same implementation will return in other processes. Like

http://doc.qt.io/qt-5/qelapsedtimer.html#clockType
http://doc.qt.io/qt-5/qelapsedtimer.html#ClockType-enum

Nicol Bolas

unread,
Jul 13, 2016, 9:07:22 AM7/13/16
to ISO C++ Standard - Discussion

HPC should not have to be restricted in that way.

Thiago Macieira

unread,
Jul 13, 2016, 4:38:41 PM7/13/16
to std-dis...@isocpp.org
Em quarta-feira, 13 de julho de 2016, às 06:07:22 PDT, Nicol Bolas escreveu:
> > Similarly, I'd like to have both std::steady_clock and std::HPC mandate
> > --
> > or
> > at least have a getter indicating -- the value it returns be comparable
> > to
> > the
> > value that the same implementation will return in other processes. Like
>
> HPC should not have to be restricted in that way.

Fair enough.

But do you think the steady clock should guarantee the above behaviour?
Reply all
Reply to author
Forward
0 new messages