Skip to content
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

use CLOCK_BOOTTIME in Instant::now #88714

Closed
wants to merge 2 commits into from

Conversation

hellow554
Copy link
Contributor

@hellow554 hellow554 commented Sep 7, 2021

There was a discussion on #87907 that all platforms expect
linux advance its monotonic timer if the system goes into a sleep state
(e.g. suspend or hibernate).
It was decided that CLOCK_BOOTTIME should be used on inux targets, but
because that constant would break older systems (e.g. linux kernels
<2.6.39) there should be a fallback to CLOCK_MONOTONIC.

Related to #87907
Closes #87906

cc @joshtriplett @cuviper

@rust-highfive
Copy link
Collaborator

r? @Mark-Simulacrum

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 7, 2021
Comment on lines 297 to 308
let t = match now(libc::CLOCK_BOOTTIME) {
Err(e) if e.kind() == io::ErrorKind::InvalidInput => now(libc::CLOCK_MONOTONIC),
v => v,
}
.unwrap();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO this match is easier to read than a or_else, but I'm not sure if that's faster/better/stronger.

Here's a godbolt link, maybe someone can decide what to use: https://rust.godbolt.org/z/6Eoxc7PEz

Copy link
Member

@workingjubilee workingjubilee Sep 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a glance, there is not what I would consider a significant enough difference in the assembly to merit one approach over another, which is as it should be for such similar expressions. One may be better contextually if carefully benchmarked.

let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
t
cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).map(|_| t)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I write:

cvt(...)?;
t

instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please.

@CryZe
Copy link
Contributor

CryZe commented Sep 7, 2021

Alright, so the situation is the following:

  • All the resources I found seem to very roughly indicate that except for Linux CLOCK_MONOTONIC does actually include suspend on basically all / most of (?) the operating systems.
  • I have tried to verify this since then, but had a lot of trouble setting up FreeBSD for example (it refused to ever wake up again after suspending)
  • Therefore I am not super confident that the claim is actually true.
  • However if anything macOS would also need to switch over to CLOCK_MONOTONIC as it currently uses it's own implementation in std. This function that is called is: not recommended by the documentation, has a lower limit (u32 + u32 as opposed to u64 + u32) and doesn't include suspends.

So yeah, that's why I didn't open this PR yet.

@hellow554
Copy link
Contributor Author

hellow554 commented Sep 7, 2021

macos currently uses mach_absolute_time (here) which states:

[...] this clock does not increment while the system is asleep.

and

Prefer to use the equivalent clock_gettime_nsec_np(CLOCK_UPTIME_RAW) in nanoseconds.

Following that: http://manpagez.com/man/3/clock_gettime_nsec_np/

CLOCK_MONOTONIC
clock that increments monotonically, tracking the time since an arbitrary point, and will continue to increment while the system is asleep.

CLOCK_MONOTONIC_RAW
clock that increments monotonically, tracking the time since an arbitrary point like CLOCK_MONOTONIC. However, this clock is unaffected by frequency or time adjustments. It should not be compared to other system time sources.

I'm more than willing to also add a change for that. Only problem I don't have a mac to test that.

@thomcc
Copy link
Member

thomcc commented Sep 7, 2021

Essentially all the clock APIs on Darwin other than mach_absolute_time were added in Darwin 16 (macOS 10.12, iOS 10.0, ...). This includes clock_gettime, clock_gettime_nsec_np, mach_continuous_time, CLOCK_UPTIME_RAW and all the other CLOCK_* constants...

We support back to macOS 10.6 or 10.7, which is considerably older. Darwin 16 is only about 4 or 5 years old, and I think it would be a problem for libstd to require this.

@workingjubilee
Copy link
Member

workingjubilee commented Sep 7, 2021

It would be a good idea if further metadiscussion took place in the original issue, since it seems to be that the discussion is ongoing. Discussion immediately relevant to this PR's code, of course, can continue here.

@joshtriplett
Copy link
Member

@thomcc I think it's reasonable to handle macOS in a separate PR. And as with this PR, it'd be acceptable if the primary approach required new macOS and the fallback didn't account for suspend time.

@the8472 the8472 added T-libs Relevant to the library team, which will review and decide on the PR/issue. A-time Area: Time labels Sep 8, 2021
@jonhoo
Copy link
Contributor

jonhoo commented Sep 23, 2021

Should this also be tagged with relnotes?

@joshtriplett
Copy link
Member

This needs an update to make the use of CLOCK_BOOTTIME conditional (only on Linux), and to make the fallback conditional (only on x86, x86_64, powerpc, powerpc64, and s390x).

This also needs an update (as noticed by the author) to use ? in error handling.

@joshtriplett joshtriplett added relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 4, 2021
@JohnCSimon
Copy link
Member

Ping from triage:
@hellow554 Can you please post your status on this PR?

@hellow554
Copy link
Contributor Author

I'm sorry for the late response. Got many things to do.

I reworked the error handling in the now function and the fallback to CLOCK_MONOTIC is now only done on said architectures.

Linux is only used if I see it correctly because of the #[cfg] on the mod inner block, am I right?

@joshtriplett
Copy link
Member

The mod inner here applies to anything that isn't macos or ios: #[cfg(not(any(target_os = "macos", target_os = "ios")))].

You need to add a cfg limiting the use of CLOCK_BOOTTIME to Linux only.

@hellow554
Copy link
Contributor Author

ALright, I wrapped it into if cfg! :)

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 25, 2022
@maurer
Copy link
Contributor

maurer commented Sep 8, 2022

Please add "android" to the list of CFG'd OSes for using CLOCK_BOOTTIME - we currently carry a patch to std in Android to use this clock for Instant.

I'm not on the libs team, but I see no reason we'd need a fallback path now that #95026 is merged - we no longer support any of the Linux systems where CLOCK_BOOTTIME does not exist.

@cuviper
Copy link
Member

cuviper commented Sep 9, 2022

We don't need a fallback anymore -- we just need to decide if we want to change this after all.

@faern
Copy link
Contributor

faern commented Nov 11, 2022

Can we please make this happen now? My impression is that we had agreed on switching to CLOCK_BOOTTIME, we just needed to fix the compatibility issues. And those are long gone now.

@bors
Copy link
Contributor

bors commented Nov 19, 2022

☔ The latest upstream changes (presumably #104573) made this pull request unmergeable. Please resolve the merge conflicts.

@JohnCSimon
Copy link
Member

@hellow554 - PR has merge conflicts

FYI: when a PR is ready for review, send a message containing
@rustbot ready to switch to S-waiting-on-review so the PR is in the reviewer's backlog.

@mati865
Copy link
Contributor

mati865 commented Nov 27, 2022

We don't need a fallback anymore -- we just need to decide if we want to change this after all.

My impression is this PR is still waiting on the decision.

There was a discussion on rust-lang#87907 that all platforms expect
linux advance its monotonic timer if the system goes into a sleep state
(e.g. suspend or hibernate).
It was decided that CLOCK_BOOTTIME should be used on unix targets.
@rustbot
Copy link
Collaborator

rustbot commented Nov 29, 2022

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@hellow554
Copy link
Contributor Author

@rustbot ready

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 29, 2022
@rust-log-analyzer

This comment has been minimized.

@hellow554
Copy link
Contributor Author

That's an error I can't explain. Maybe somebody can?

-    Instant {
-        t: Timespec::now(if cfg!(target_os = "linux") {
-            libc::CLOCK_BOOTTIME
-        } else {
-            libc::CLOCK_MONOTONIC
-        }),
-    }
+    #[cfg(target_os = "macos")]
+    const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
+
+    #[cfg(target_os = "linux")]
+    const clock_id: libc::clockid_t = libc::CLOCK_BOOTTIME;
+
+    #[cfg(not(any(target_os = "macos", target_os = "linux")))]
+    const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
+
+    Instant { t: Timespec::now(clock_id) }

that's not a lot of changes and certainly no changes that should do have an impact. Maybe something else changed in the meantime?

@maniwani
Copy link
Contributor

It looks like Miri tests are failing when emulating x86_64-unknown-linux-gnu. I believe the error is that Miri doesn't recognize libc::CLOCK_BOOTTIME.

I think it needs to be added to the shims:
https://github.com/rust-lang/miri/blob/master/src/shims/time.rs

@rustbot
Copy link
Collaborator

rustbot commented Nov 30, 2022

The Miri subtree was changed

cc @rust-lang/miri

@RalfJung
Copy link
Member

RalfJung commented Nov 30, 2022

There was a discussion on #87907 that all platforms expect
linux advance its monotonic timer if the system goes into a sleep state
(e.g. suspend or hibernate).

This does not seem accurate. Since #103594, macOS on aarch64 uses CLOCK_UPTIME_RAW which does not increment when the system is asleep. On x86 it uses mach_absolute_time which, according to that manpage, also does not increment when the system is asleep.

@@ -45,6 +45,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
relative_clocks = vec![
this.eval_libc_i32("CLOCK_MONOTONIC")?,
this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?,
// This is the equivalent to `CLOCK_UPTIME_RAW` in the macos section
// We support it, because std relies on it
Copy link
Member

@RalfJung RalfJung Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is backwards -- BOOTTIME you say does increment when the machine is asleep, but CLOCK_UPTIME_RAW does not.

If anything, it seems like CLOCK_BOOTTIME on linux is like CLOCK_MONOTONIC on macOS, and CLOCK_MONOTONIC on linux is like CLOCK_UPTIME_RAW (and mach_absolute_time) on macos?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah judging from a quick search, looks like MONOTONIC on Linux does not increment when sleeping, but on macos it does. It also looks before this PR we are actually consistent (both Linux and macos use clocks that do not count when the system is asleep), and this PR makes us inconsistent by changing only Linux.

Or maybe I am looking at the wrong docs? This seems to look reasonably official though for macos.

#[cfg(not(target_os = "macos"))]

#[cfg(target_os = "linux")]
const clock_id: libc::clockid_t = libc::CLOCK_BOOTTIME;
Copy link
Member

@RalfJung RalfJung Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have documentation saying that Instant, when possible, will use a clock that keeps going when the system is asleep -- and list on which targets this is definitely the case?

Judging from this and this PR, that would be Windows and Linux. No idea about Android, the BSDs, iOS/watchOS, ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so it seems like after this PR it's pretty much "everything except macOS"?

Copy link
Contributor

@CryZe CryZe Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fuchsia is also problematic as they specifically defined their monotonic to behave like Linux's... but they didn't provide an alternative BOOTTIME one yet. Also the PR only checks for "linux" specifically and not Linux derivatives such as Android and l4re (not sure 100% on l4re, at least libc usually bundles it into the Linux-like #[cfg]s), which it probably should (just not emscripten as it errors out on BOOTTIME atm).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, doesn't look like this actually closes #87906 quite yet then.

Comment on lines +48 to +49
// This is the equivalent to `CLOCK_UPTIME_RAW` in the macos section
// We support it, because std relies on it
Copy link
Member

@RalfJung RalfJung Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This is the equivalent to `CLOCK_UPTIME_RAW` in the macos section
// We support it, because std relies on it
// Unlike `CLOCK_MONOTONIC` (which is weird on Linux in that it does not increment
// during system sleep), this *is* supposed to increment during system sleep...
// but that's not really something a program running inside Miri can tell, anyway.
// We support it because std relies on it.

@m-ou-se
Copy link
Member

m-ou-se commented Dec 14, 2022

This issue was discussed again in the libs meeting last week. There is currently no consensus for switching to CLOCK_BOOTTIME.

One of the points that was brought up is that many Linux APIs like futex(), futex_waitv(), and pthread_cond_t only support CLOCK_REALTIME and CLOCK_MONOTONIC. In general, it seems that CLOCK_MONOTONIC is the 'default' monotonic clock on Linux in many situations, unlike CLOCK_BOOTTIME. It seems best for std's Instant to just use whatever is the 'standard' monotonic clock on each platform.

What was also mentioned is that without providing additional guarantees that hold across all platforms, switching just one platform doesn't seem that useful; users still wouldn't be able to rely on the exact behaviour.

@hellow554
Copy link
Contributor Author

So I'm gonna close this.
Feel free to return to this PR whenever we decide elsewise, but for now, it's okay to allow this PR to rest :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-time Area: Time relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Instant::duration_since returns a shortened duration if a suspend occurred