-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch Instant to use CLOCK_BOOTTIME #87907
Conversation
For Linux-like platforms, use CLOCK_BOOTTIME which continues ticking during suspend. Without this change, `Duration` between two `Instant`s can bear little relation to reality if a suspend took place in between. Fixes rust-lang#87906
r? @dtolnay (rust-highfive has picked a reviewer for you, use r? to override) |
I would find it really difficult to only have this behaviour on linux. What about windows? How does it currently do the time measurement? What about bsd, ios, redox, ... ? I think if we touch one thing, we should update every OS. |
BSD, iOS, redox, and OSX would all be updated by this change as well - perhaps my commit message could have been worded better, but they all use Windows has difficulties because
In an ideal world I agree, but I don't think that we want a lowest common denominator interface here. Just because Windows doesn't offer a high precision timer that ticks in suspend doesn't mean we shouldn't use it where supported. |
My previous post was based on what is evidently old information. According to Microsoft they are now handling any necessary adjustments for sleep in |
@@ -293,7 +293,7 @@ mod inner { | |||
|
|||
impl Instant { | |||
pub fn now() -> Instant { | |||
Instant { t: now(libc::CLOCK_MONOTONIC) } | |||
Instant { t: now(libc::CLOCK_BOOTTIME) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CLOCK_BOOTTIME
isn't supported on Linux <= 2.6.39, but Rust supports Linux >= 2.6.32. This should check if -EINVAL
is returned and fall back to CLOCK_MONOTONIC
if so.
osx has a separate implementation rust/library/std/src/sys/unix/time.rs Lines 149 to 155 in 362e0f5
|
This does not mean the code would remain correct. CLOCK_MONOTONIC is true on all these platforms because it is POSIX. This notably does not specify whether CLOCK_BOOTTIME is a sensical value on all Unix platforms. I expect this PR would cause other platforms to fail to build, like FreeBSD, which uses its own constants and not the "Linux-like" set in libc. As such, this PR must bifurcate the implementation of |
@workingjubilee That would have to be done to support Tier 1 targets too, since older versions of Linux supported by Rust don't support |
Sorry, missed that |
@workingjubilee |
On macOS 10.12 (iOS/tvOS 10, watchOS 3) We'd have to dynamically load it (via [1]: There's also (That said, I would not really tempt Apple about using an API they explicitly tell you not to in the docs...) |
Imo that calls into question the value of this change. If we can't promise this behavior then someone may start to rely on non-portable implementation details because it worked on their machine but not on old (but supported) or less common platforms. |
I feel that way too, and am fairly torn on it. But the original issue seems to imply people already rely on this, or at least failed to consider it. As a result, their their code is has some bugs in this case. ISTM like it already behaves non-portably, but just in a weaker sense — it works fine on machines that don't get put to sleep much/ever (many servers, some desktop machines, etc), but this assumption is "not portable" to systems that do, like consumer phones, laptops, etc. (Yes, I'm aware this is an abuse of terminology) As mentioned though, I'm torn on it, and could probably be convinced either way. |
I think we should just document |
I'd say it absolutely should be documented that it can't guarantee that across all the platforms, such that people don't rely on it. But I'd still like to see this PR be merged. There's very little reason not to fix the behavior where possible. This otherwise just causes unnecessary bugs for lots of people for no good reason. Let's say it this way: Yes, the documentation doesn't guarantee a lot about Instant other than that it's monotonic, but there's still an expectation of it being the de facto API to measure time. Therefore while yes, a monotonic implementation of Instant could just be an atomic integer that counts up by 1 on every call, or even always just return 0. That would absolutely be the fastest implementation and fits the docs, but that's just not a useful implementation. People want to use the type to measure time, so the best OS API that does that should be used, even if there's not a lot of specifics we can guarantee. |
Having a huge discontinuity over suspends isn't necessarily always the desirable behavior. If you're trying to do something like "update based on the amount of time that has passed", or "measure how long a computation took", you may want to skip suspended time. I personally would like more of an ability to use other clocks. But I don't think we should change the behavior of Perhaps we should have an |
This is problematic for Darwin, although I guess it could be used elsewhere. |
@thomcc Can you elaborate on why that would be problematic for Darwin? |
On darwin, the clock_gettime-alikes are only in Darwin 16 (macOS 10.12) and later. Before that you just have Also, the versions that use timespecs are disrecommended in favor of the |
We discussed this in today's @rust-lang/libs-api meeting. We decided that we don't want to make this change for multiple reasons:
Thus, we're going to close this issue. However, we'd be interested in seeing work that makes Instant consistent in the other direction: if it's possible to ignore suspended time on all versions of Windows, we'd love to see a patch that switches to doing that. (cc @Amanieu who had some ideas about that in the meeting) |
Part of my disagreement with this being useful is that this does not measure the amount of time passed (the system being suspended doesn't stop time), and doesn't measure how long a computation took (this clock keeps ticking even if your process gets SIGSTOP'd, or the kernel has other higher priority threads to evaluate). The only correct use I've seen for
If we choose to go the route of "provide other clocks as things other than As an aside, if we did go the |
On Wed, Aug 18, 2021 at 01:12:01PM -0700, Matthew Maurer wrote:
> Perhaps we should have an `InstantExt` on UNIX with a method that allows passing an arbitrary `libc::clockid_t` and/or `libc::timespec`. That would let people choose whatever clock they want to use.
If we choose to go the route of "provide other clocks as things other than `Instant"`, I don't think it should be through an OS-specific interface. I think it would make more sense to provide "A clock that ticks during suspend, and advances monotonically at a constant rate" "A clock which only runs while the machine is running" etc. as generic interfaces with OS-specific implementations when possible. the `InstantExt` route would require a user who wants a clock that ticks in suspend to write different code for Linux, Windows, and any UNIX-like that uses its own name for `CLOCK_BOOTTIME` in their application.
As an aside, if we did go the `InstantExt` route, I'd at least want the source clock included in the `Instant` to have dynamic checks to prevent accidental `.duration_since()` between different clocks.
I'm not even sure if InstantExt is the right interface for that; that
was just one possibility. Some of the clocks available don't actually
make sense as an Instant; for instance, some need the ability to access
the raw value to make sense of them (e.g. CLOCK_PROCESS_CPUTIME_ID), so
Instant as an opaque type doesn't work well there.
But I'm also not sure we can provide a sufficiently portable
implementation of "a clock that ticks during suspend", either.
|
Unless I've missed something, we can do that on Linux >= 2.6.39, OSX >= 10.12, and Windows (not sure of versions, I think the function we're using changes behavior if you go back far enough but I'm not certain), without much difficulty. That seems fairly portable... |
On Wed, Aug 18, 2021 at 01:35:30PM -0700, Matthew Maurer wrote:
> But I'm also not sure we can provide a sufficiently portable implementation of "a clock that ticks during suspend", either.
Unless I've missed something, we can do that on Linux > 2.6.39, OSX > 10.12, and Windows (not sure of versions, I think the function we're using changes behavior if you go back far enough but I'm not certain), without much difficulty. That seems fairly portable...
What about other UNIX systems?
What should this implementation do on older Linux, older macOS, or older
Windows, all of which we still officially support?
I think it'd be appropriate for such an implementation to start in the
crate ecosystem.
|
@maurer: I am not aware of the best solution here, unfortunately. I am aware of what is POSIX and can smell a Linux-only extension at a thousand paces, and I believe that smaller platforms should be treated with appropriate respect, or at least, should successfully compile, so the introduction of Linux-only code that did not apply and would not compile, in a way that the full CI run would reject, was apparent to me in a way I could not help but note.
"fairly" is not "is", unfortunately. |
Support for multiple clocks should be implemented using a generic Perhaps this is a good starting point for a third party crate which provides support for multiple clocks with different properties. |
Actually I looked into it and it's only possible with some undocumented NT interfaces which aren't even stable across Windows versions. So that's probably right out. |
I've looked deeper into this and... this seems to literally be a Linux specific bug. On all other OSs Pretty sure none of these points apply anymore:
It's portable via the fallback.
The fallback ensures it works on all kernels.
It's consistent then, atm it isn't.
Exactly, the inconsistency is worse, which is the status quo, so this making it more consistent is the better behavior. |
Thank you, CryZe, for doing the work there to verify the appropriate setting is indeed I would like to note that on OpenBSD, however, the absolute value is still considered "meaningless" in a formal sense, promising only monotonic increase. It only "accidentally" aligns with a correct, monotonically increasing clock since boot time. So like Linux, they also introduced But I think this only reinforces the point, however, that becoming consistent with "wall time" is most intuitive for the default Instant type, given that people keep "accidentally" selecting it. I believe it is also consistent with the goal of |
If changing the Linux behavior in this regard would indeed result in consistency across all targets, then I think it'd be a reasonable change. (I'd love to have the Linux behavior on all platforms, either by default or via some other call, but it sounds like that's much harder.) However, I don't think we should implement caching behavior; that would optimize for the performance of repeated calls on ancient Linux at the expense of a slight hit on non-ancient Linux. I'd suggest, instead, that we do one of two things:
|
@CryZe If you're interested in submitting a pull request implementing this, with an explanation in the code and commit message based on your research into the behavior of various operating systems, I'd be happy to review it. |
I do, but only because our internal RHEL builders run on a kernel from the previous major release, so my RHEL 7 builds are running on RHEL 6's 2.6.32. So it's not something I need for customers, but it's important for me nonetheless. I know it's a pain though, and I'm willing to shoulder the burden of writing/maintaining compatibility code in such cases. Just please notify me (as you did here) when there's something that needs such help. |
@cuviper Alright. In that case, I think we should just always fallback on EINVAL. |
2.6.39 would also unlock |
@the8472 Based on further discussions with @cuviper, it sounds like upgrading the baseline version of the Linux kernel would require additional work and coordination. I'm hoping that may be possible at some point, but let's not block this proposed change on that, since it'd just take adding an unconditional fallback on |
@rustbot claim |
Wait a second, this isn't the issue, this is the PR... let's try that again there. @rustbot release |
For Linux-like platforms, use CLOCK_BOOTTIME which continues ticking
during suspend. Without this change,
Duration
between twoInstant
scan bear little relation to reality if a suspend took place in between.
Fixes #87906