Migrate existing benchmarks

Keep familiar Criterion calls for exploration; use native groups for confirmation.

Choose whether you need familiar Criterion calls for exploratory reporting or registered native Suite groups for interleaving and confirmation. The current compatibility layer executes measurements immediately and sequentially; it does not supply the fixed-process evidence needed for baseline promotion.

Keep Criterion-style calls

Enable compatibility on the Git dependency used by these guides:

[dev-dependencies]
zenbench = { git = "https://github.com/imazen/zenbench", branch = "main", features = ["criterion-compat"] }

Keep Criterion itself while comparing separate targets. In a zenbench target, replace imports with:

use zenbench::criterion_compat::*;
use zenbench::{criterion_group, criterion_main};

Common calls include benchmark_group, bench_function, bench_with_input, BenchmarkId, Throughput, iter, iter_batched and iter_batched_ref, plus sample size, measurement-time and warmup configuration. Inspect the current compatibility source for the subset you use rather than assuming every Criterion API is covered.

Immediate bench_function and bench_with_input closures may borrow local data. Batched setup closures still need 'static; captured setup state can require move and owned/cloned values. Timing boundaries and configuration semantics may also differ. Run correctness checks and inspect your migrated report.

cargo bench --bench my_criterion_bench
cargo bench --bench my_zenbench_bench -- --format=html

The names are example targets you define separately with harness = false. Compatibility timing is exploratory even when its report contains a narrow interval. It cannot accept a Confirm candidate or promote a baseline.

Move comparisons into native groups

For interleaving and the current confirmation protocol, register the arms in Suite::group and use zenbench::main!:

use zenbench::prelude::*;

fn benches(suite: &mut Suite) {
    suite.group("sum", |g| {
        g.bench("iterator", |b| {
            b.iter(|| std::hint::black_box(0..1000u64).sum::<u64>())
        });
        g.bench("loop", |b| {
            b.iter(|| {
                let mut total = 0;
                for value in std::hint::black_box(0..1000u64) {
                    total += value;
                }
                total
            })
        });
    });
}

zenbench::main!(benches);

This is a registration example, not a measured speed claim. Confirm equal outputs and use representative inputs before timing. Native g.bench closures are stored for later interleaved execution and need owned 'static captures when state is captured. Replace bench_function with bench and wrap registration in suite.group(...); no finish() call is needed.

Follow the first benchmark guide to inspect and run it, then confirm a frozen candidate.

Update CLI scripts by task

The preferred command groups are guide, cpu-info, exec, pair, nice, self-compare, data, fleet and jobs. Previous flat command names remain accepted. Typical replacements:

Older spellingPreferred spelling
zenbench read FILEzenbench data read FILE
zenbench compare BEFORE AFTERzenbench data compare BEFORE AFTER
zenbench snapshot FILE --output CSVzenbench data snapshot FILE --output CSV
zenbench baseline listzenbench data baseline list
zenbench fleet-run BUNDLE ...zenbench fleet run BUNDLE ...
zenbench run NAME ...zenbench jobs run NAME ...

Both --name=value and --name value work for benchmark options. Preserve recorded mode/plan identity within an experiment. Read the complete migration contract for aliases, decision exits and API compatibility.

Found an error or it needs a clarification? Open an issue on GitHub.
Substantiated corrections will be incorporated with attribution.