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

time: implicit 1ms delay in sleep_until #6866

Open
SmnTin opened this issue Sep 24, 2024 · 3 comments
Open

time: implicit 1ms delay in sleep_until #6866

SmnTin opened this issue Sep 24, 2024 · 3 comments
Labels
A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-time Module: tokio/time

Comments

@SmnTin
Copy link

SmnTin commented Sep 24, 2024

Version
I tested it with 1.35, 1.36, 1.37, and 1.38.

Platform
Ubuntu 20.04.6 LTS, Linux 5.4.0, x86_64.

Description

It seems that Tokio adds an implicit delay of 1ms to any sleeping operation, even if the time is paused:

use tokio::time::{Instant, Duration};

#[tokio::main(flavor = "current_thread")]
async fn main() {
    tokio::time::pause();
    
    let now = Instant::now();
    tokio::time::sleep_until(now).await;
    dbg!(Instant::now() - now); // 1 ms
    
    let next_at = now + Duration::from_secs(1);
    tokio::time::sleep_until(next_at).await;
    dbg!(Instant::now() - next_at); // 1 ms
}

This behavior is unexpected, to say the least.

Link to the playground

Related to #6390.

@SmnTin SmnTin added A-tokio Area: The main tokio crate C-bug Category: This is a bug. labels Sep 24, 2024
@Darksonn Darksonn added the M-time Module: tokio/time label Sep 24, 2024
@Darksonn
Copy link
Contributor

Tokio's timer is only precise up to 1ms. Any durations less than that are rounded up to the next millisecond.

@SmnTin
Copy link
Author

SmnTin commented Sep 25, 2024

@Darksonn In other words, the duration should be a multiple of 1 ms. Otherwise, it is rounded up. For example, 17ns should be rounded to 1ms, but 0ms should be rounded to 0ms, not 1ms. Moreover, in the second case, 1s is already a multiple of 1ms, yet the time advances for an extra ms. Note that the time is paused, so there shouldn't be any issues with imprecise sleeping.

@Darksonn
Copy link
Contributor

Ah I see where the confusion comes from. The problem is the amount of time it takes from the start of the test until the call to time::pause(). Compare with this version that has no time pass before the test is paused:

use tokio::time::{Instant, Duration};

#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
    let now = Instant::now();
    tokio::time::sleep_until(now).await;
    dbg!(Instant::now() - now); // 0 ns
    
    let next_at = now + Duration::from_secs(1);
    tokio::time::sleep_until(next_at).await;
    dbg!(Instant::now() - next_at); // 0 ns
}

It's not durations that are rounded up to the next millisecond. Rather, the deadline of the sleep is rounded up to the next millisecond "tick" since the runtime started. If some time has already passed since the start of the test, then even a sleep of duration zero is rounded up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-bug Category: This is a bug. M-time Module: tokio/time
Projects
None yet
Development

No branches or pull requests

2 participants