Skip to main content

BenchGroup

Struct BenchGroup 

Source
pub struct BenchGroup { /* private fields */ }
Expand description

A group of benchmarks to compare via interleaved execution.

Implementations§

Source§

impl BenchGroup

Source

pub fn new_public(name: impl Into<String>) -> Self

Create a new group (public, for criterion_compat).

Source

pub fn bench<F>(&mut self, name: impl Into<String>, f: F)
where F: FnMut(&mut Bencher) + Send + 'static,

Add a benchmark to this comparison group.

Source

pub fn bench_tagged<F>( &mut self, name: impl Into<String>, tags: &[(&str, &str)], f: F, )
where F: FnMut(&mut Bencher) + Send + 'static,

Add a benchmark with key-value tags for multi-dimensional reporting.

Tags enable grouping and pivoting in reports. Common tags: ("library", "zenflate"), ("level", "L6"), ("data", "mixed").

Source

pub fn bench_contended<S, Setup, Work>( &mut self, name: impl Into<String>, threads: usize, setup: Setup, work: Work, )
where S: Send + Sync + 'static, Setup: Fn() -> S + Send + 'static, Work: Fn(&mut Bencher, &S, usize) + Send + Sync + Clone + 'static,

Add a multithreaded contention benchmark.

Spawns threads threads that all start simultaneously (barrier-synchronized) and run the benchmark closure in parallel. Measures wall-clock time from barrier release to all threads completing — this is the throughput under contention that your users experience.

The setup closure runs once to create shared state (typically an Arc). The work closure runs on each thread with a reference to the shared state and the thread index (0..threads).

group.bench_contended("mutex_map", 8,
    || Arc::new(Mutex::new(HashMap::new())),
    |b, shared, thread_id| {
        b.iter(|| { shared.lock().unwrap().insert(thread_id, 42); })
    },
);
Source

pub fn bench_parallel<F>( &mut self, name: impl Into<String>, threads: usize, work: F, )
where F: Fn(&mut Bencher, usize) + Send + Sync + Clone + 'static,

Add a parallel throughput benchmark (no shared state).

Spawns threads threads that each run the same work independently. Measures total wall-clock time. Use this to find scaling limits — if 4 threads aren’t 4x faster, you’re hitting cache/memory bandwidth or SMT contention.

Each thread gets its own thread index (0..threads) but no shared state. For shared-state contention testing, use BenchGroup::bench_contended instead.

// Compare 1, 2, 4 threads doing independent work
for threads in [1, 2, 4] {
    group.bench_parallel(format!("{threads}t"), threads, |b, _tid| {
        b.iter(|| std::hint::black_box(42u64.wrapping_mul(7)))
    });
}

Rayon / existing thread pools: Don’t use this for code that manages its own threads (rayon, tokio, etc.). Just use regular bench() — wall-clock timing already captures all threads’ work. bench_parallel spawns its own threads, which would compete with rayon’s pool.

Source

pub fn bench_scaling<F>(&mut self, name: impl Into<String>, work: F)
where F: Fn(&mut Bencher, usize) + Send + Sync + Clone + 'static,

Automatic thread scaling analysis.

Probes thread counts from 1 up to the system’s logical core count (powers of 2 plus the physical core count). Each thread count becomes a separate benchmark in the group, interleaved and compared.

Use with Throughput::Elements(N) to see scaling and efficiency:

group.throughput(Throughput::Elements(10_000));
group.bench_scaling("sqrt_work", |b, _tid| {
    b.iter(|| std::hint::black_box(42u64.wrapping_mul(7)))
});

The 1-thread benchmark is the baseline. The report shows how throughput scales (or doesn’t) with more threads.

Source

pub fn throughput(&mut self, throughput: Throughput) -> &mut Self

Declare the throughput for this group.

All benchmarks in the group process the same amount of data, so throughput is set at the group level.

Source

pub fn subgroup(&mut self, label: impl Into<String>) -> &mut Self

Set a visual subgroup label for subsequent benchmarks.

Subgroups are display-only — benchmarks are still interleaved and compared across subgroups within the same comparison group. The label appears as a section header in the table and bar chart.

group.subgroup("Ok path");
group.bench("no_error", |b| b.iter(|| std::hint::black_box(1)));
group.subgroup("Error path");
group.bench("with_backtrace", |b| b.iter(|| std::hint::black_box(2)));
Source

pub fn throughput_unit(&mut self, unit: impl Into<String>) -> &mut Self

Set a custom unit name for Throughput::Elements.

When set, reports show e.g. “5.0 Gchecks/s” instead of “5.0 Gops/s”.

Source

pub fn baseline(&mut self, name: impl Into<String>) -> &mut Self

Set which benchmark is the baseline for comparisons.

By default, the first benchmark added is the baseline. Use this to compare against a different benchmark by name.

Source

pub fn config(&mut self) -> &mut GroupConfig

Configure this group’s execution parameters.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.