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

AsyncBencher::iter_batched and iter_batched_ref should allow for async setup #751

Open
shepmaster opened this issue Jan 11, 2024 · 1 comment

Comments

@shepmaster
Copy link

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:

criterion.rs/src/bencher.rs

Lines 622 to 631 in b913e23

runner.block_on(async {
b.iterated = true;
let batch_size = size.iters_per_batch(b.iters);
assert!(batch_size != 0, "Batch size must not be zero.");
let time_start = Instant::now();
b.value = b.measurement.zero();
if batch_size == 1 {
for _ in 0..b.iters {
let input = black_box(setup());

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.

@vnermolaev
Copy link

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);
    });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants