criterion.rs
criterion.rs copied to clipboard
AsyncBencher::iter_batched and iter_batched_ref should allow for async setup
Right now, the setup closures return a synchronous value, not a future, disallowing setup from being async.
Additionally, iter_batched
wraps the call to setup
in a block_on
call:
https://github.com/bheisler/criterion.rs/blob/b913e232edd98780961ecfbae836ec77ede49259/src/bencher.rs#L622-L631
This means that you can't use block_on
in the closure yourself as that would create a nested runtime:
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use tokio::runtime::Builder;
pub fn criterion_benchmark(c: &mut Criterion) {
let rt = Builder::new_multi_thread().enable_all().build().unwrap();
c.bench_function("demo", |b| {
b.to_async(&rt).iter_batched(
|| rt.block_on(async {}),
|_| async {},
BatchSize::SmallInput,
);
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
thread 'main' panicked at ~/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.35.1/src/runtime/scheduler/multi_thread/mod.rs:86:9:
Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
Our current workaround is to use iter_custom
instead.
Indeed, I have faced a similar and more extended version of this problem.
I came up with the following workaround for my particular case:
fn setup(rt: &runtime::Runtime) -> u64 {
rt.block_on(async {
// do async stuff
tokio::time::sleep(Duration::from_millis(100)).await;
1
})
}
async fn test() -> u64 {
1
}
pub fn criterion_benchmark(c: &mut Criterion) {
let rt = runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let setup = setup(&rt);
c.bench_function("demo", |b| {
b.to_async(&rt)
.iter_batched(|| setup.clone(), |_| async {}, BatchSize::SmallInput);
});
}