Search code examples
rustbenchmarkingrust-cargorust-criterion

Adding async functions in `criterion_group!()` macro


In Criterion's documentation, there is plenty of information on how to benchmark asynchronous functions, but I'm having difficulty figuring out how to run an async function that exists outside of the function I'm attempting to benchmark. The basic idea is this:

pub async fn benchmark_inputs(c: &mut Criterion) {
    // function that gathers inputs is async
    // it also would be redundant to retrieve this info in the benchmark `.iter()` every time.
    // the below code does not work with either block_on() or .await
    let inputs = block_on(get_inputs());


    c.bench_function("benchmark_inputs_that_match", |b| {
        b.iter(|| {
            func_to_benchmark(inputs) // this function is _not_ async
        })
    });
}

The code above has no warnings or errors in the Rust analyzer, but when you try to add this to the criterion_group, you get a warning:

criterion_group!(
    benches,
    benchmark_inputs,
);
criterion_main!(benches);

This does not work, as there is an unused implementer of futures::Future that must be used futures do nothing unless you .await or poll them warning.

Ignoring the warning and running cargo bench will technically work, but there is no timing information or HTML reports generated as usual, so it is useless.

Has anyone else come across this issue?


Solution

  • With a nudge from Chayim, I found a way to make this work (although it's not my favorite to have mut variables):

    I created a mutable inputs variable, then created a tokio runtime to retrieve the inputs in:

    pub async fn benchmark_inputs(c: &mut Criterion) {
        // function that gathers inputs is async
        // it also would be redundant to retrieve this info in the benchmark `.iter()` every time.
        // the below code does not work with either block_on() or .await
        let mut inputs = Vec::new()
    
        let runtime = tokio::runtime::Builder::new_current_thread()
            .build()
            .unwrap();
    
        runtime.block_on(async {
            inputs = get_inputs().await;
        });
    
    
        c.bench_function("benchmark_inputs_that_match", |b| {
            b.iter(|| {
                func_to_benchmark(inputs) // this function is _not_ async
            })
        });
    }