24.9 Benchmarking

Performance is crucial in systems programming. Rust offers multiple ways to measure runtime efficiency:

  • Nightly-only Benchmark Harness: A built-in harness requiring the nightly compiler.
  • criterion and divan Crates: Third-party benchmarking libraries with statistical analysis and stable Rust support.

Below are concise examples for each method.

24.9.1 The Built-in Benchmark Harness (Nightly Only)

If you use nightly Rust, you can use the language's built-in benchmarking support. For example:

#![feature(test)]

extern crate test;

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[test]
    fn it_works() {
        assert_eq!(add_two(2), 4);
    }

    #[bench]
    fn bench_add_two(b: &mut Bencher) {
        b.iter(|| add_two(2));
    }
}
  1. Add #![feature(test)] at the top (an unstable feature).
  2. Import the test crate.
  3. Mark benchmark functions with #[bench], taking a &mut Bencher parameter.
  4. Use b.iter(...) to specify the code to measure.

To run tests and benchmarks:

cargo test
cargo bench

Note: Compiler optimizations might remove what it sees as “unused” code. To prevent this, consider using test::black_box(...) around critical operations.

24.9.2 criterion

Criterion is a popular benchmarking crate for stable Rust. It provides advanced features, such as statistical measurements and detailed reports.

Quickstart

  1. Add criterion to dev-dependencies in Cargo.toml:

    [dev-dependencies]
    criterion = { version = "0.5", features = ["html_reports"] }
    
    [[bench]]
    name = "my_benchmark"
    harness = false
    
  2. Create benches/my_benchmark.rs:

    use std::hint::black_box;
    use criterion::{criterion_group, criterion_main, Criterion};
    
    fn fibonacci(n: u64) -> u64 {
        match n {
            0 => 1,
            1 => 1,
            n => fibonacci(n - 1) + fibonacci(n - 2),
        }
    }
    
    fn criterion_benchmark(c: &mut Criterion) {
        c.bench_function("fib 20", |b| {
            b.iter(|| fibonacci(black_box(20)))
        });
    }
    
    criterion_group!(benches, criterion_benchmark);
    criterion_main!(benches);
  3. Run:

    cargo bench
    

Criterion generates a report (often in target/criterion/report/index.html) that includes detailed results and plots.

24.9.3 divan

Divan is a newer benchmarking crate (currently around version 0.1.17) requiring Rust 1.80.0 or later.

Getting Started

  1. In Cargo.toml:

    [dev-dependencies]
    divan = "0.1.17"
    
    [[bench]]
    name = "example"
    harness = false
    
  2. Create benches/example.rs:

    fn main() {
        // Execute registered benchmarks.
        divan::main();
    }
    
    // Register the `fibonacci` function and benchmark it with multiple arguments.
    #[divan::bench(args = [1, 2, 4, 8, 16, 32])]
    fn fibonacci(n: u64) -> u64 {
        if n <= 1 {
            1
        } else {
            fibonacci(n - 2) + fibonacci(n - 1)
        }
    }
  3. Run:

    cargo bench
    

Divan outputs benchmark results on the command line; consult the Divan documentation for more features.