Skip to content

Commit 112112d

Browse files
authored
Yield instead of sleep in component-async-tests (#12567)
* Yield instead of sleep in component-async-tests Use cooperative yields instead of sleeps to make tests more deterministic and also avoid them unnecessarily taking up test parallelism by sleeping. Yielding should have the same effect in terms of testing by exercising behavior returning `Pending` in futures, so there's no expected loss in test coverage here. * Yield fewer times
1 parent c12e169 commit 112112d

22 files changed

Lines changed: 221 additions & 366 deletions

crates/misc/component-async-tests/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ pub mod resource_stream;
99
pub mod round_trip;
1010
pub mod round_trip_direct;
1111
pub mod round_trip_many;
12-
pub mod sleep;
1312
pub mod transmit;
1413
pub mod util;
15-
pub mod yield_host;
14+
pub mod yield_;
15+
pub mod yield_runner;
1616

1717
/// Host implementation, usable primarily by tests
1818
pub struct Ctx {

crates/misc/component-async-tests/src/round_trip.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::Ctx;
2-
use std::time::Duration;
2+
use crate::util::yield_times;
33
use wasmtime::component::Accessor;
44

55
pub mod bindings {
@@ -20,7 +20,7 @@ pub mod non_concurrent_export_bindings {
2020

2121
impl bindings::local::local::baz::HostWithStore for Ctx {
2222
async fn foo<T>(_: &Accessor<T, Self>, s: String) -> wasmtime::Result<String> {
23-
crate::util::sleep(Duration::from_millis(10)).await;
23+
yield_times(10).await;
2424
Ok(format!("{s} - entered host - exited host"))
2525
}
2626
}

crates/misc/component-async-tests/src/round_trip_direct.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::Ctx;
2-
use std::time::Duration;
2+
use crate::util::yield_times;
33
use wasmtime::component::Accessor;
44

55
pub mod bindings {
@@ -11,7 +11,7 @@ pub mod bindings {
1111

1212
impl bindings::RoundTripDirectImportsWithStore for Ctx {
1313
async fn foo<T>(_: &Accessor<T, Self>, s: String) -> String {
14-
crate::util::sleep(Duration::from_millis(10)).await;
14+
yield_times(5).await;
1515
format!("{s} - entered host - exited host")
1616
}
1717
}

crates/misc/component-async-tests/src/round_trip_many.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::Ctx;
2-
use std::time::Duration;
2+
use crate::util::yield_times;
33
use wasmtime::Result;
44
use wasmtime::component::Accessor;
55

@@ -41,7 +41,7 @@ impl bindings::local::local::many::HostWithStore for Ctx {
4141
Option<Stuff>,
4242
Result<Stuff, ()>,
4343
) {
44-
crate::util::sleep(Duration::from_millis(10)).await;
44+
yield_times(5).await;
4545
(
4646
format!("{a} - entered host - exited host"),
4747
b,

crates/misc/component-async-tests/src/sleep.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

crates/misc/component-async-tests/src/util.rs

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::{
33
marker::PhantomData,
44
pin::Pin,
55
task::{Context, Poll},
6-
thread,
76
};
87
use wasmtime::Result;
98
use wasmtime::{
@@ -14,24 +13,9 @@ use wasmtime::{
1413
},
1514
};
1615

17-
pub async fn sleep(duration: std::time::Duration) {
18-
if cfg!(miri) {
19-
// TODO: We should be able to use `tokio::time::sleep` here, but as of
20-
// this writing the miri-compatible version of `wasmtime-fiber` uses
21-
// threads behind the scenes, which means thread-local storage is not
22-
// preserved when we switch fibers, and that confuses Tokio. If we ever
23-
// fix that we can stop using our own, special version of `sleep` and
24-
// switch back to the Tokio version.
25-
26-
let (tx, rx) = oneshot::channel();
27-
let handle = thread::spawn(move || {
28-
thread::sleep(duration);
29-
_ = tx.send(());
30-
});
31-
_ = rx.await;
32-
_ = handle.join();
33-
} else {
34-
tokio::time::sleep(duration).await;
16+
pub async fn yield_times(n: usize) {
17+
for _ in 0..n {
18+
tokio::task::yield_now().await;
3519
}
3620
}
3721

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use super::Ctx;
2+
use wasmtime::component::Accessor;
3+
4+
wasmtime::component::bindgen!({
5+
path: "wit",
6+
world: "yield-host",
7+
});
8+
9+
impl local::local::yield_::HostWithStore for Ctx {
10+
async fn yield_times<T>(_: &Accessor<T, Self>, times: u64) {
11+
crate::util::yield_times(times.try_into().unwrap()).await;
12+
}
13+
}
14+
15+
impl local::local::yield_::Host for Ctx {}

crates/misc/component-async-tests/src/yield_host.rs renamed to crates/misc/component-async-tests/src/yield_runner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use wasmtime::component::{Accessor, Resource};
88
pub mod bindings {
99
wasmtime::component::bindgen!({
1010
path: "wit",
11-
world: "yield-host",
11+
world: "yield-runner",
1212
imports: { default: trappable },
1313
with: {
1414
"local:local/ready.thing": super::Thing,

crates/misc/component-async-tests/tests/scenario/common.rs

Lines changed: 0 additions & 113 deletions
This file was deleted.

crates/misc/component-async-tests/tests/scenario/post_return.rs

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
use super::util::test_run;
22
use crate::scenario::util::{config, make_component};
33
use component_async_tests::util;
4-
use component_async_tests::{Ctx, sleep};
4+
use component_async_tests::{Ctx, yield_};
55
use std::future;
66
use std::pin::pin;
77
use std::task::Poll;
8-
use std::time::Duration;
98
use wasmtime::Result;
109
use wasmtime::component::{Accessor, Linker, ResourceTable};
1110
use wasmtime::{AsContextMut, Engine, Store, StoreContextMut};
1211
use wasmtime_wasi::WasiCtxBuilder;
1312

14-
mod sleep_post_return {
13+
mod yield_post_return {
1514
wasmtime::component::bindgen!({
1615
path: "wit",
17-
world: "sleep-post-return-callee",
16+
world: "yield-post-return-callee",
1817
exports: { default: task_exit },
1918
});
2019
}
@@ -36,29 +35,29 @@ pub async fn async_post_return_caller() -> Result<()> {
3635
}
3736

3837
#[tokio::test]
39-
pub async fn async_sleep_post_return_caller() -> Result<()> {
40-
test_sleep_post_return(&[
41-
test_programs_artifacts::ASYNC_SLEEP_POST_RETURN_CALLER_COMPONENT,
42-
test_programs_artifacts::ASYNC_SLEEP_POST_RETURN_CALLEE_COMPONENT,
38+
pub async fn async_yield_post_return_caller() -> Result<()> {
39+
test_yield_post_return(&[
40+
test_programs_artifacts::ASYNC_YIELD_POST_RETURN_CALLER_COMPONENT,
41+
test_programs_artifacts::ASYNC_YIELD_POST_RETURN_CALLEE_COMPONENT,
4342
])
4443
.await
4544
}
4645

4746
#[tokio::test]
48-
pub async fn async_sleep_post_return_callee() -> Result<()> {
49-
test_sleep_post_return(&[test_programs_artifacts::ASYNC_SLEEP_POST_RETURN_CALLEE_COMPONENT])
47+
pub async fn async_yield_post_return_callee() -> Result<()> {
48+
test_yield_post_return(&[test_programs_artifacts::ASYNC_YIELD_POST_RETURN_CALLEE_COMPONENT])
5049
.await
5150
}
5251

53-
async fn test_sleep_post_return(components: &[&str]) -> Result<()> {
52+
async fn test_yield_post_return(components: &[&str]) -> Result<()> {
5453
let engine = Engine::new(&config())?;
5554

5655
let component = make_component(&engine, components).await?;
5756

5857
let mut linker = Linker::new(&engine);
5958

6059
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
61-
sleep::local::local::sleep::add_to_linker::<_, Ctx>(&mut linker, |ctx| ctx)?;
60+
yield_::local::local::yield_::add_to_linker::<_, Ctx>(&mut linker, |ctx| ctx)?;
6261

6362
let mut store = Store::new(
6463
&engine,
@@ -69,19 +68,19 @@ async fn test_sleep_post_return(components: &[&str]) -> Result<()> {
6968
},
7069
);
7170

72-
let guest = sleep_post_return::SleepPostReturnCallee::instantiate_async(
71+
let guest = yield_post_return::YieldPostReturnCallee::instantiate_async(
7372
&mut store, &component, &linker,
7473
)
7574
.await?;
7675

7776
async fn run_with(
7877
accessor: &Accessor<Ctx>,
79-
guest: &sleep_post_return::SleepPostReturnCallee,
78+
guest: &yield_post_return::YieldPostReturnCallee,
8079
) -> Result<()> {
81-
// This function should return immediately, then sleep the specified
82-
// number of milliseconds after returning, and then finally exit.
80+
// This function should return immediately, then yield the specified
81+
// number of times after returning, and then finally exit.
8382
let exit = guest
84-
.local_local_sleep_post_return()
83+
.local_local_yield_post_return()
8584
.call_run(accessor, 100)
8685
.await?
8786
.1;
@@ -93,7 +92,7 @@ async fn test_sleep_post_return(components: &[&str]) -> Result<()> {
9392

9493
async fn run(
9594
store: StoreContextMut<'_, Ctx>,
96-
guest: &sleep_post_return::SleepPostReturnCallee,
95+
guest: &yield_post_return::YieldPostReturnCallee,
9796
) -> Result<()> {
9897
store
9998
.run_concurrent(async |accessor| {
@@ -104,7 +103,7 @@ async fn test_sleep_post_return(components: &[&str]) -> Result<()> {
104103
// outstanding guest or host tasks to poll for a while, trusting
105104
// that we'll resolve the future independently, with or without
106105
// giving it more work to do.
107-
util::sleep(Duration::from_millis(100)).await;
106+
util::yield_times(10).await;
108107

109108
run_with(accessor, guest).await?;
110109

0 commit comments

Comments
 (0)