Attribute Macro divan::bench_group
source · #[bench_group]
Expand description
Registers a benchmarking group.
Examples
This is used for setting options shared across
#[divan::bench]
functions in the same module:
#[divan::bench_group(
sample_count = 100,
sample_size = 500,
)]
mod math {
use divan::black_box;
#[divan::bench]
fn add() -> i32 {
black_box(1) + black_box(42)
}
#[divan::bench]
fn div() -> i32 {
black_box(1) / black_box(42)
}
}
fn main() {
// Run `math::add` and `math::div` benchmarks:
divan::main();
}
Benchmarking options set on parent groups cascade into child groups and their benchmarks:
#[divan::bench_group(
sample_count = 100,
sample_size = 500,
)]
mod parent {
#[divan::bench_group(sample_size = 1)]
mod child1 {
#[divan::bench]
fn bench() {
// Will be sampled 100 times with 1 iteration per sample.
}
}
#[divan::bench_group(sample_count = 42)]
mod child2 {
#[divan::bench]
fn bench() {
// Will be sampled 42 times with 500 iterations per sample.
}
}
mod child3 {
#[divan::bench(sample_count = 1)]
fn bench() {
// Will be sampled 1 time with 500 iterations per sample.
}
}
}
Applying this attribute multiple times to the same item will cause a compile error:
#[divan::bench_group]
#[divan::bench_group]
mod math {
// ...
}
Options
name
By default, the benchmark group uses the module’s name. It can be overridden
via the name
option:
#[divan::bench_group(name = "my_math")]
mod math {
#[divan::bench(name = "my_add")]
fn add() -> i32 {
// Will appear as "crate_name::my_math::my_add".
}
}
crate
The path to the specific divan
crate instance used by this macro’s
generated code can be specified via the crate
option. This is applicable
when using divan
via a macro from your own crate.
extern crate divan as sofa;
#[::sofa::bench_group(crate = ::sofa)]
mod math {
#[::sofa::bench(crate = ::sofa)]
fn add() -> i32 {
// ...
}
}
sample_count
The number of statistical sample recordings can be set to a predetermined
u32
value via the sample_count
option. This may be overridden at
runtime using either the DIVAN_SAMPLE_COUNT
environment variable or
--sample-count
CLI argument.
#[divan::bench_group(sample_count = 1000)]
mod math {
#[divan::bench]
fn add() -> i32 {
// ...
}
}
If the threads
option is enabled, sample count becomes a multiple of the
number of threads. This is because each thread operates over the same sample
size to ensure there are always N competing threads doing the same amount of
work.
sample_size
The number iterations within each statistical sample can be set to a
predetermined u32
value via the sample_size
option. This may be
overridden at runtime using either the DIVAN_SAMPLE_SIZE
environment
variable or --sample-size
CLI argument.
#[divan::bench_group(sample_size = 1000)]
mod math {
#[divan::bench]
fn add() -> i32 {
// ...
}
}
threads
See #[divan::bench(threads = ...)]
.
counters
The Counter
s of each iteration of benchmarked
functions in a group can be set via the counters
option. The following
example emits info for the number of bytes and number of ints processed when
benchmarking slice sorting:
use divan::{Bencher, counter::{BytesCount, ItemsCount}};
const INTS: &[i32] = &[
// ...
];
#[divan::bench_group(counters = [
BytesCount::of_slice(INTS),
ItemsCount::new(INTS.len()),
])]
mod sort {
use super::*;
#[divan::bench]
fn default(bencher: Bencher) {
bencher
.with_inputs(|| INTS.to_vec())
.bench_refs(|ints| ints.sort());
}
#[divan::bench]
fn unstable(bencher: Bencher) {
bencher
.with_inputs(|| INTS.to_vec())
.bench_refs(|ints| ints.sort_unstable());
}
}
For convenience, singular counter
allows a single
Counter
to be set. The following example emits
info for the number of bytes processed when benchmarking
char
-counting and
char
-collecting:
use divan::counter::BytesCount;
const STR: &str = "...";
#[divan::bench_group(counter = BytesCount::of_str(STR))]
mod chars {
use super::STR;
#[divan::bench]
fn count() -> usize {
divan::black_box(STR).chars().count()
}
#[divan::bench]
fn collect() -> String {
divan::black_box(STR).chars().collect()
}
}
See:
min_time
The minimum time spent benchmarking each function can be set to a
predetermined Duration
via the min_time
option. This may be
overridden at runtime using either the DIVAN_MIN_TIME
environment variable
or --min-time
CLI argument.
Unless skip_ext_time
is set, this includes time external to benchmarked
functions, such as time spent generating inputs and running Drop
.
use std::time::Duration;
#[divan::bench_group(min_time = Duration::from_secs(3))]
mod math {
#[divan::bench]
fn add() -> i32 {
// ...
}
}
For convenience, min_time
can also be set with seconds as u64
or
f64
. Invalid values will cause a panic at runtime.
#[divan::bench_group(min_time = 2)]
mod int_secs {
// ...
}
#[divan::bench_group(min_time = 1.5)]
mod float_secs {
// ...
}
max_time
The maximum time spent benchmarking each function can be set to a
predetermined Duration
via the max_time
option. This may be
overridden at runtime using either the DIVAN_MAX_TIME
environment variable
or --max-time
CLI argument.
Unless skip_ext_time
is set, this includes time external to benchmarked
functions, such as time spent generating inputs and running Drop
.
If min_time > max_time
, then max_time
has priority and min_time
will not be reached.
use std::time::Duration;
#[divan::bench_group(max_time = Duration::from_secs(5))]
mod math {
#[divan::bench]
fn add() -> i32 {
// ...
}
}
For convenience, like min_time
, max_time
can also be set with
seconds as u64
or f64
. Invalid values will cause a panic at runtime.
#[divan::bench_group(max_time = 8)]
mod int_secs {
// ...
}
#[divan::bench_group(max_time = 9.5)]
mod float_secs {
// ...
}
skip_ext_time
By default, min_time
and max_time
include time external to
benchmarked functions, such as time spent generating inputs and running
Drop
. Enabling the skip_ext_time
option will instead make those
options only consider time spent within benchmarked functions. This may be
overridden at runtime using either the DIVAN_SKIP_EXT_TIME
environment
variable or --skip-ext-time
CLI argument.
In the following example, max_time
only considers time spent running
measured_function
:
#[divan::bench_group(skip_ext_time)]
mod group {
#[divan::bench(max_time = 5)]
fn bench(bencher: divan::Bencher) {
bencher
.with_inputs(|| generate_input())
.bench_values(|input| measured_function(input));
}
}
This option can be set to an explicit bool
value to override parent
values:
#[divan::bench_group(skip_ext_time = false)]
mod group {
// ...
}
ignore
Like #[test]
and #[divan::bench]
, #[divan::bench_group]
functions can
use #[ignore]
:
#[divan::bench_group]
#[ignore]
mod math {
#[divan::bench]
fn todo() {
unimplemented!();
}
}
This option can also instead be set within the #[divan::bench_group]
attribute:
#[divan::bench_group(ignore)]
mod math {
#[divan::bench]
fn todo() {
unimplemented!();
}
}
Like skip_ext_time
, this option can be set to an explicit bool
value
to override parent values:
#[divan::bench_group(ignore = false)]
mod group {
// ...
}
This can be used to ignore benchmarks based on a runtime condition. The following example benchmark group will be ignored if an environment variable is not set to “true”:
#[divan::bench_group(
ignore = std::env::var("BENCH_EXPENSIVE").as_deref() != Ok("true")
)]
mod expensive_benches {
// ...
}