diff --git a/crates/bencher_compat/src/compat.rs b/crates/bencher_compat/src/compat.rs index c0d221a7..9cbd8aa6 100644 --- a/crates/bencher_compat/src/compat.rs +++ b/crates/bencher_compat/src/compat.rs @@ -1,4 +1,4 @@ -use codspeed::codspeed::{black_box, CodSpeed}; +use codspeed::codspeed::{black_box, CodSpeed, WARMUP_RUNS}; pub struct Bencher { pub bytes: u64, @@ -24,6 +24,9 @@ impl Bencher { F: FnMut() -> T, { let uri = self.current_uri.as_str(); + for _ in 0..WARMUP_RUNS { + black_box(inner()); + } self.codspeed.start_benchmark(uri); black_box(inner()); self.codspeed.end_benchmark(); diff --git a/crates/codspeed/src/codspeed.rs b/crates/codspeed/src/codspeed.rs index 65431134..78a9ac50 100644 --- a/crates/codspeed/src/codspeed.rs +++ b/crates/codspeed/src/codspeed.rs @@ -4,6 +4,8 @@ use colored::Colorize; use crate::measurement; +pub const WARMUP_RUNS: u32 = 5; + //TODO: use std::hint::black_box when it's stable pub fn black_box(dummy: T) -> T { unsafe { diff --git a/crates/criterion_compat/benches/criterion_integration/compare_functions.rs b/crates/criterion_compat/benches/criterion_integration/compare_functions.rs index 5c9bec4d..7a2563be 100644 --- a/crates/criterion_compat/benches/criterion_integration/compare_functions.rs +++ b/crates/criterion_compat/benches/criterion_integration/compare_functions.rs @@ -1,4 +1,4 @@ -use codspeed_criterion_compat::{criterion_group, BenchmarkId, Criterion}; +use codspeed_criterion_compat::{black_box, criterion_group, BenchmarkId, Criterion}; fn fibonacci_slow(n: u64) -> u64 { match n { @@ -27,14 +27,16 @@ fn fibonacci_fast(n: u64) -> u64 { fn compare_fibonaccis(c: &mut Criterion) { let mut group = c.benchmark_group("Fibonacci"); - group.bench_with_input("Recursive", &20, |b, i| b.iter(|| fibonacci_slow(*i))); + group.bench_with_input("Recursive", &20, |b, i| { + b.iter(|| fibonacci_slow(black_box(*i))) + }); group.bench_with_input("Iterative", &20, |b, i| b.iter(|| fibonacci_fast(*i))); } fn compare_fibonaccis_group(c: &mut Criterion) { let mut group = c.benchmark_group("Fibonacci3"); for i in 20..=21 { group.bench_with_input(BenchmarkId::new("Recursive", i), &i, |b, i| { - b.iter(|| fibonacci_slow(*i)) + b.iter(|| fibonacci_slow(black_box(*i))) }); group.bench_with_input(BenchmarkId::new("Iterative", i), &i, |b, i| { b.iter(|| fibonacci_fast(*i)) diff --git a/crates/criterion_compat/src/compat/bencher.rs b/crates/criterion_compat/src/compat/bencher.rs index 7fb75ea4..53568d94 100644 --- a/crates/criterion_compat/src/compat/bencher.rs +++ b/crates/criterion_compat/src/compat/bencher.rs @@ -25,9 +25,17 @@ impl Bencher { R: FnMut() -> O, { let mut codspeed = self.codspeed.borrow_mut(); - codspeed.start_benchmark(self.uri.as_str()); - black_box(routine()); - codspeed.end_benchmark(); + // NOTE: this structure hardens our benchmark against dead code elimination + // https://godbolt.org/z/KnYeKMd1o + for i in 0..codspeed::codspeed::WARMUP_RUNS + 1 { + if i < codspeed::codspeed::WARMUP_RUNS { + black_box(routine()); + } else { + codspeed.start_benchmark(self.uri.as_str()); + black_box(routine()); + codspeed.end_benchmark(); + } + } } #[inline(never)] @@ -49,12 +57,20 @@ impl Bencher { R: FnMut(I) -> O, { let mut codspeed = self.codspeed.borrow_mut(); - let input = black_box(setup()); - codspeed.start_benchmark(self.uri.as_str()); - let output = routine(input); - codspeed.end_benchmark(); - drop(black_box(output)); + for i in 0..codspeed::codspeed::WARMUP_RUNS + 1 { + let input = black_box(setup()); + let output = if i < codspeed::codspeed::WARMUP_RUNS { + black_box(routine(input)) + } else { + let input = black_box(setup()); + codspeed.start_benchmark(self.uri.as_str()); + let output = black_box(routine(input)); + codspeed.end_benchmark(); + output + }; + drop(black_box(output)); + } } pub fn iter_with_setup(&mut self, setup: S, routine: R) @@ -87,14 +103,20 @@ impl Bencher { R: FnMut(&mut I) -> O, { let mut codspeed = self.codspeed.borrow_mut(); - let mut input = black_box(setup()); - codspeed.start_benchmark(self.uri.as_str()); - let output = routine(&mut input); - codspeed.end_benchmark(); - - drop(black_box(output)); - drop(black_box(input)); + for i in 0..codspeed::codspeed::WARMUP_RUNS + 1 { + let mut input = black_box(setup()); + let output = if i < codspeed::codspeed::WARMUP_RUNS { + black_box(routine(&mut input)) + } else { + codspeed.start_benchmark(self.uri.as_str()); + let output = black_box(routine(&mut input)); + codspeed.end_benchmark(); + output + }; + drop(black_box(output)); + drop(black_box(input)); + } } #[cfg(feature = "async")] @@ -121,9 +143,15 @@ impl<'b, A: AsyncExecutor> AsyncBencher<'b, A> { let AsyncBencher { b, runner } = self; runner.block_on(async { let mut codspeed = b.codspeed.borrow_mut(); - codspeed.start_benchmark(b.uri.as_str()); - black_box(routine().await); - codspeed.end_benchmark(); + for i in 0..codspeed::codspeed::WARMUP_RUNS + 1 { + if i < codspeed::codspeed::WARMUP_RUNS { + black_box(routine().await); + } else { + codspeed.start_benchmark(b.uri.as_str()); + black_box(routine().await); + codspeed.end_benchmark(); + } + } }); } @@ -180,11 +208,19 @@ impl<'b, A: AsyncExecutor> AsyncBencher<'b, A> { let AsyncBencher { b, runner } = self; runner.block_on(async { let mut codspeed = b.codspeed.borrow_mut(); - let input = black_box(setup()); - codspeed.start_benchmark(b.uri.as_str()); - let output = routine(input).await; - codspeed.end_benchmark(); - drop(black_box(output)); + + for i in 0..codspeed::codspeed::WARMUP_RUNS + 1 { + let input = black_box(setup()); + let output = if i < codspeed::codspeed::WARMUP_RUNS { + black_box(routine(input).await) + } else { + codspeed.start_benchmark(b.uri.as_str()); + let output = black_box(routine(input).await); + codspeed.end_benchmark(); + output + }; + drop(black_box(output)); + } }) } @@ -203,14 +239,20 @@ impl<'b, A: AsyncExecutor> AsyncBencher<'b, A> { let AsyncBencher { b, runner } = self; runner.block_on(async { let mut codspeed = b.codspeed.borrow_mut(); - let mut input = black_box(setup()); - codspeed.start_benchmark(b.uri.as_str()); - let output = routine(&mut input).await; - codspeed.end_benchmark(); - - drop(black_box(output)); - drop(black_box(input)); + for i in 0..codspeed::codspeed::WARMUP_RUNS + 1 { + let mut input = black_box(setup()); + let output = if i < codspeed::codspeed::WARMUP_RUNS { + black_box(routine(&mut input).await) + } else { + codspeed.start_benchmark(b.uri.as_str()); + let output = black_box(routine(&mut input).await); + codspeed.end_benchmark(); + output + }; + drop(black_box(output)); + drop(black_box(input)); + } }); } }