cargo bench
The cargo bench command compiles and executes performance benchmarks using the [profile.bench] build profile (which inherits opt-level = 3 optimizations from [profile.release]). Because the compiler's built-in #[bench] attribute (test::Bencher) requires an unstable nightly feature (#![feature(test)]), production Rust projects run stable statistical microbenchmarks under cargo bench using ecosystem harnesses like Criterion or Divan in benches/*.rs.
my_crate/
├── Cargo.toml (Declares `[[bench]] name = "..." harness = false`)
├── src/lib.rs (Library functions under benchmark)
└── benches/
└── sorting_bench.rs (Compiled with `[profile.bench]` opt-level = 3)
Preventing Dead-Code Elimination with std::hint::black_box
When benchmarking a pure function at opt-level = 3, LLVM's optimizer can see that the benchmark loop's return value is unused—or that its inputs are compile-time constants—and delete the entire computation at compile time, reporting an unrealistic 0 ns execution time!
Since Rust 1.66, the standard library provides std::hint::black_box on stable Rust. Wrapping inputs and outputs in black_box(...) forces the compiler to treat the value as opaquely read and written without constant-folding or dead-code elimination:
use std::hint::black_box;
use std::time::Instant;
pub fn fibonacci_iterative(n: u64) -> u64 {
let mut a = 0u64;
let mut b = 1u64;
for _ in 0..n {
let next = a.wrapping_add(b);
a = b;
b = next;
}
a
}
fn main() {
let iterations = 10_000u32;
let start = Instant::now();
for _ in 0..iterations {
// `black_box(30)` prevents LLVM from constant-folding `fibonacci_iterative(30)`
// and `black_box(result)` prevents LLVM from deleting the unused return value!
let input = black_box(30);
let result = fibonacci_iterative(input);
black_box(result);
}
let elapsed = start.elapsed();
println!(
"Ran {iterations} black_box iterations in {:?} (avg {:?}/iter)",
elapsed,
elapsed / iterations
);
}
Ran 10000 black_box iterations in 1.24ms (avg 124ns/iter)
Configuring Stable Benchmarks (criterion / divan) in Cargo.toml
To use a stable benchmarking framework with cargo bench, add the framework to [dev-dependencies] and set harness = false on the [[bench]] target so Cargo invokes the framework's statistical runner instead of libtest:
[dev-dependencies]
criterion = "0.5"
[[bench]]
name = "sorting_bench"
harness = false
| Benchmarking Approach | Works on Stable Rust? | Statistical Outlier & Regression Analysis? | Command |
|---|---|---|---|
#[bench] (extern crate test) |
No (Nightly #![feature(test)] only) |
Basic median ± deviation | cargo +nightly bench |
criterion (benches/*.rs) |
Yes | Full p-value regression tests, warmup, HTML violin plots | cargo bench |
divan (benches/*.rs) |
Yes | Fast attribute-based (#[divan::bench]), allocation counting |
cargo bench |
iai-callgrind |
Yes (Linux + Valgrind) | Deterministic CPU instruction & L1/L3 cache miss counts (zero noise in CI!) | cargo bench |