From 76685eee9db738af32c7e6b3c32c476552cc7dd6 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Tue, 20 Oct 2026 13:26:27 +0200 Subject: [PATCH] fix(criterion): avoid duplicate setup in simulation iter_batched Use the input already prepared outside measurement instead of calling setup again for the measured iteration. This prevents an unused input from remaining alive during the routine. Add regression coverage for setup counts and input lifetime. --- crates/criterion_compat/src/compat/bencher.rs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/criterion_compat/src/compat/bencher.rs b/crates/criterion_compat/src/compat/bencher.rs index 5e6295c6..d4b68e12 100644 --- a/crates/criterion_compat/src/compat/bencher.rs +++ b/crates/criterion_compat/src/compat/bencher.rs @@ -85,7 +85,6 @@ impl<'a> Bencher<'a> { let output = if i < codspeed::codspeed::WARMUP_RUNS { routine(input) } else { - let input = black_box(setup()); self.codspeed.start_benchmark(self.uri.as_str()); let output = routine(input); self.codspeed.end_benchmark(); @@ -305,6 +304,34 @@ impl<'a, 'b, A: AsyncExecutor> AsyncBencher<'a, 'b, A> { #[cfg(test)] mod tests { use super::*; + use std::cell::Cell; + use std::rc::Rc; + + #[test] + fn iter_batched_consumes_each_setup_input() { + let mut codspeed = CodSpeed::new(); + let mut bencher = Bencher::new(&mut codspeed, "iter_batched_setup".to_owned()); + let setups = Cell::new(0); + let routines = Cell::new(0); + let live_inputs = Rc::new(()); + + bencher.iter_batched( + || { + setups.set(setups.get() + 1); + Rc::clone(&live_inputs) + }, + |input| { + routines.set(routines.get() + 1); + assert_eq!(setups.get(), routines.get()); + assert_eq!(Rc::strong_count(&input), 2); + input + }, + BatchSize::PerIteration, + ); + + assert_eq!(setups.get(), routines.get()); + assert_eq!(Rc::strong_count(&live_inputs), 1); + } fn assert_send() {} fn assert_sync() {}