Cargo can build and execute Rust benchmark targets from the same package manifest that drives builds and tests. Running benchmarks before a performance-sensitive change or release gives the crate an optimized timing pass instead of relying on debug builds or ordinary unit tests.
Benchmark targets usually live under benches, and Cargo builds them with the bench profile. The built-in #[bench] attribute is nightly-only, so stable projects commonly use a custom harness or a benchmarking crate such as Criterion while keeping cargo bench as the entry command.
A small custom harness with harness = false can run on stable Rust without external dependencies. Existing projects that already have benchmark targets can skip the file setup and run cargo bench from the package root.
Related: How to run Rust tests with Cargo
Related: How to create a Rust project with Cargo
Steps to run Rust benchmarks with Cargo:
- Open the Rust package root that contains Cargo.toml.
Use cargo bench --manifest-path path/to/Cargo.toml when launching Cargo from another directory.
- Create the benchmark directory when the package does not already have one.
$ mkdir -p benches
- Add a benchmark target.
- benches/string_len.rs
use std::{hint::black_box, time::Instant}; fn main() { let input = "simplified-guide-benchmark"; let rounds = 1_000_000; let started = Instant::now(); let mut total = 0; for _ in 0..rounds { total += black_box(input).len(); } black_box(total); println!( "string_len: {rounds} iterations in {:?} (total={total})", started.elapsed() ); }
std::hint::black_box keeps the optimizer from removing the measured loop in the minimal benchmark.
- Register the benchmark as a custom harness in Cargo.toml.
- Cargo.toml
[[bench]] name = "string_len" harness = false
harness = false disables the default libtest benchmark harness, so the benchmark file provides its own main function.
- Build the benchmark target without executing it.
$ cargo bench --no-run --bench string_len Compiling demo-lib v0.1.0 (/home/dev/demo-lib) Finished `bench` profile [optimized] target(s) in 1.09s Executable benches/string_len.rs (target/release/deps/string_len-2ce2528f213845aa)Use --no-run when compile errors should be caught before collecting timing output.
- Run the selected benchmark target.
$ cargo bench --bench string_len Finished `bench` profile [optimized] target(s) in 0.01s Running benches/string_len.rs (target/release/deps/string_len-2ce2528f213845aa) string_len: 1000000 iterations in 581.792µs (total=26000000)A custom main function controls this output line. A Criterion benchmark or nightly #[bench] target reports in its own harness format.
- Run every benchmark target selected by the package manifest.
$ cargo bench Compiling demo-lib v0.1.0 (/home/dev/demo-lib) Finished `bench` profile [optimized] target(s) in 0.27s Running unittests src/lib.rs (target/release/deps/demo_lib-3c68178e29f1f907) running 1 test test tests::it_works ... ignored test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s Running benches/string_len.rs (target/release/deps/string_len-2ce2528f213845aa) string_len: 1000000 iterations in 398.625µs (total=26000000)Options before -- belong to Cargo. Arguments after -- are passed to the benchmark binary or harness.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.