Open mahkoh opened 4 years ago
The behavior of CLOCK_MONOTONIC appears to vary between implementations:
[1] During the 4.17 development cycle CLOCK_MONOTONIC was changed to behave like CLOCK_BOOTTIME. But this broke userspace and was reverted. [2] https://lists.freebsd.org/pipermail/freebsd-hackers/2018-June/052899.html [3] https://github.com/openbsd/src/blob/e71a3804998757589450d9364e961ab21db849c9/sys/kern/kern_time.c#L121-L124 [4] http://www.manpagez.com/man/3/clock_gettime/
From the docs
An instant may jump forwards or experience time dilation (slow down or speed up), but it will never go backwards.
I think this leeway exists to allow whichever timer is the fastest to be used, not the most consistent or human-friendly one.
That comment is about NTP.
The documentation does not restrict itself to that. NTP is only one possible cause for clocks jumping, but not the only one. Users can manually adjust clocks too. Sleep is just another possible source. VM migrations are a thing too.
Please spare me this academic citing of the documentation. This issue is about a serious difference in behavior on different platforms. Your pedantic reading would make an implementation that has Instant::new return a constant value valid. This is neither what the authors of the API intended nor how downstream is using it.
The point is that Instant boils down to rdtsc on many systems (give or take some cleanups/backsliding protection). rdtsc quality has changed with cpu generations. E.g. in some models it did not tick when the cpu was in some sleep states (which would be similar to what you're experiencing) and this changed in other models (see the nonstop_tsc
cpu capability, among others).
Your pedantic reading would make an implementation that has Instant::new return a constant value valid.
Indeed. But implementations strive to do better than that on a best-effort basis. That doesn't mean they promise to do better than that. It definitely does not promise wall-time.
This is neither what the authors of the API intended
The intent of Instant is to have a low-overhead, fine-grained elapsed time measurement. Whether elapsed time includes sleeps or not isn't specified. Calling to the system clock that provides wall-time is high-overhead or low-granularity on some platforms.
This issue is about a serious difference in behavior on different platforms.
Well, at least the documentation could be improved.
Both CLOCK_MONOTONIC and CLOCK_BOOTTIME have the same associated costs on x86_64 linux. Therefore there is nothing inherent on x86_64 that makes one mode more expensive than the other one. Nobody was talking about wall-time.
CLOCK_BOOTTIME was introduced in kernel 2.6.39. Rust's minimum supported kernel version was recently bumped to 2.6.32. It might be possible to work around this by probing with different flags, but that would only provide this behavior on a best-effort basis and not guarantee it which means downstream should not be relying on it. And as you mention yourself there's no CLOCK_BOOTTIME for FreeBSD.
So the smallest common denominator is and remains that system suspend may or may not be accounted for.
I just ran into this on macOS, where the implementation is based on mach_absolute_time()
and (also) doesn't advance during sleep.
Is there any interest in updating the documentation to specifically mention that measured durations may or may not include time spent during system suspend/sleep? It's clearly a significant difference in behaviour amongst the supported platforms…
On linux, Instant uses clock_gettime with CLOCK_MONOTONIC which does not count time spent in a sleep state such as hiberation or standby.
On Windows, Instant uses QueryPerformanceCounter which does count time spent in a sleep state:
Neither behavior is currently documented.
Consider the following code (adapted from similar code in Tokio):
Behavior on Linux: Ticks during sleep are lost.
Behavior on Windows: Ticks during sleep occur in rapid succession after resume.