macro_rules! binary_benchmark_group {
(
name = $name:ident; $(;)*
$(before = $before:ident $(,bench = $bench_before:literal)? ; $(;)*)?
$(after = $after:ident $(,bench = $bench_after:literal)? ; $(;)*)?
$(setup = $setup:ident $(,bench = $bench_setup:literal)? ; $(;)*)?
$(teardown = $teardown:ident $(,bench = $bench_teardown:literal)? ; $(;)*)?
$( config = $config:expr ; $(;)* )?
benchmark = |$cmd:literal, $group:ident: &mut BinaryBenchmarkGroup| $body:expr
) => { ... };
(
name = $name:ident; $(;)*
$( before = $before:ident $(,bench = $bench_before:literal)? ; $(;)* )?
$( after = $after:ident $(,bench = $bench_after:literal)? ; $(;)* )?
$( setup = $setup:ident $(,bench = $bench_setup:literal)? ; $(;)* )?
$( teardown = $teardown:ident $(,bench = $bench_teardown:literal )? ; $(;)* )?
$( config = $config:expr ; $(;)* )?
benchmark = |$group:ident: &mut BinaryBenchmarkGroup| $body:expr
) => { ... };
(
$( config = $config:expr ; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = $( $function:ident ),+ $(,)*
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks =
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr ; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr ; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = $( $function:ident ),+ $(,)*
) => { ... };
(
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = |$group:ident: &mut BinaryBenchmarkGroup| $body:expr
) => { ... };
(
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = |$group:ident| $body:expr
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = |$group:ident|
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = |$group:ident: &mut BinaryBenchmarkGroup|
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = |$group:ident: &mut BinaryBenchmarkGroup| $body:expr
) => { ... };
(
name = $name:ident; $(;)*
$( config = $config:expr; $(;)* )?
$( compare_by_id = $compare:literal ; $(;)* )?
$( setup = $setup:expr; $(;)* )?
$( teardown = $teardown:expr; $(;)* )?
benchmarks = |$group:ident| $body:expr
) => { ... };
}default only.Expand description
Macro used to define a group of binary benchmarks
There are two apis to set up binary benchmarks. The recommended way is to use the
#[binary_benchmark] attribute.
But, if you find yourself in the situation that the attribute isn’t enough you can fall back to
the low level api or even intermix both
styles.
§The macro’s arguments in detail:
The following top-level arguments are accepted (in this order):
binary_benchmark_group!(
name = my_group;
config = BinaryBenchmarkConfig::default();
compare_by_id = false;
setup = run_setup();
teardown = run_teardown();
benchmarks = bench_binary
);-
name(mandatory): A unique name used to identify the group for themain!macro -
config(optional): Acrate::BinaryBenchmarkConfig -
compare_by_id(optional): The default is false. If true, all commands from the functions specified in thebenchmarksargument, are compared with each other as long as the ids (the part after the::in#[bench::id(...)]) match. -
setup(optional): A function which is executed before all benchmarks in this group -
teardown(optional): A function which is executed after all benchmarks in this group -
benchmarks(mandatory): A,-separated list of#[binary_benchmark]annotated function names you want to put into this group. Or, if you want to use the low level api|IDENTIFIER: &mut BinaryBenchmarkGroup| EXPRESSIONor the shorter
|IDENTIFIER| EXPRESSIONwhere
IDENTIFIERis the identifier of your choice for theBinaryBenchmarkGroup(we usegroupthroughout our examples) andEXPRESSIONis the code where you make use of theBinaryBenchmarkGroupto set up the binary benchmarks
§Using the high-level api with the #[binary benchmark] attribute
A small introductory example which demonstrates the basic setup (assuming a crate’s binary is
named my-foo):
use iai_callgrind::{binary_benchmark_group, BinaryBenchmarkGroup, binary_benchmark};
#[binary_benchmark]
#[bench::hello_world("hello world")]
#[bench::foo("foo")]
#[benches::multiple("bar", "baz")]
fn bench_binary(arg: &str) -> iai_callgrind::Command {
iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
.arg(arg)
.build()
}
binary_benchmark_group!(
name = my_group;
benchmarks = bench_binary
);
iai_callgrind::main!(binary_benchmark_groups = my_group);To be benchmarked a binary_benchmark_group has to be added to the main! macro by adding its
name to the binary_benchmark_groups argument of the main! macro. See there for further
details about the crate::main macro. See the documentation of crate::binary_benchmark
for more details about the attribute itself and the inner attributes #[bench] and
#[benches].
§The low-level api
Using the low-level api has advantages but when it comes to stability in terms of usability, the
low level api might be considered less stable. What does this mean? If we have to make changes
to the inner workings of iai-callgrind which not necessarily change the high-level api it is
more likely that the low-level api has to be adjusted. This implies you might have to adjust
your benchmarks more often with a version update of iai-callgrind. Hence, it is recommended to
use the high-level api as much as possible and only use the low-level api under special
circumstances. You can also intermix both styles!
The low-level api mirrors the high-level constructs as close as possible. The
crate::BinaryBenchmarkGroup is a special case, since we use the information from the
binary_benchmark_group! macro arguments (name,
config, …) to create the BinaryBenchmarkGroup and pass it to the benchmarks
argument.
That being said, here’s the basic usage:
use iai_callgrind::{binary_benchmark_group, BinaryBenchmark, Bench};
binary_benchmark_group!(
// All the other options from the `binary_benchmark_group` are used as usual
name = my_group;
// Note there's also the shorter form `benchmarks = |group|` but in the examples we want
// to be more explicit
benchmarks = |group: &mut BinaryBenchmarkGroup| {
// We have chosen `group` to be our identifier but it can be anything
group.binary_benchmark(
// This is the equivalent of the `#[binary_benchmark]` attribute. The `id`
// mirrors the function name of the `#[binary_benchmark]` annotated function.
BinaryBenchmark::new("some_id")
.bench(
// The equivalent of the `#[bench]` attribute.
Bench::new("my_bench_id")
.command(
// The `Command` stays the same
iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
.arg("foo").build()
)
)
)
}
);Depending on your IDE, it’s nicer to work with the code after the |group: &mut BinaryBenchmarkGroup| if it resides in a separate function rather than the macro itself as in
use iai_callgrind::{binary_benchmark_group, BinaryBenchmark, Bench, BinaryBenchmarkGroup};
fn setup_my_group(group: &mut BinaryBenchmarkGroup) {
// Enjoy all the features of your IDE ...
}
binary_benchmark_group!(
name = my_group;
benchmarks = |group: &mut BinaryBenchmarkGroup| setup_my_group(group)
);The list of all structs and macros used exclusively in the low-level api:
crate::BinaryBenchmarkGroupcrate::BinaryBenchmark: Mirrors the#[binary_benchmark]attributecrate::Bench: Mirrors the#[bench]attributecrate::binary_benchmark_attribute: Used to add a#[binary_benchmark]attributed function incrate::BinaryBenchmarkGroup::binary_benchmarkcrate::BenchmarkId: The benchmark id is for example used incrate::BinaryBenchmark::newandcrate::Bench::new
Note there’s no equivalent for the #[benches] attribute. The crate::Bench behaves exactly
as the #[benches] attribute if more than a single crate::Command is added.
§Intermixing both apis
For example, if you started with the #[binary_benchmark] attribute and noticed you are limited
by it to set up all the crate::Commands the way you want, you can intermix both styles:
use iai_callgrind::{
binary_benchmark, binary_benchmark_group, BinaryBenchmark, Bench, BinaryBenchmarkGroup,
binary_benchmark_attribute
};
#[binary_benchmark]
#[bench::foo("foo")]
#[benches::multiple("bar", "baz")]
fn bench_binary(arg: &str) -> iai_callgrind::Command {
iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
.arg(arg)
.build()
}
fn setup_my_group(group: &mut BinaryBenchmarkGroup) {
group
// Simply add what you already have with the `binary_benchmark_attribute!` macro.
// This macro returns a `BinaryBenchmark`, so you could even add more `Bench`es
// to it instead of creating a new one as we do below
.binary_benchmark(binary_benchmark_attribute!(bench_binary))
.binary_benchmark(
BinaryBenchmark::new("did_not_work_with_attribute")
.bench(Bench::new("low_level")
.command(
iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
.arg("foo")
.build()
)
)
);
}
binary_benchmark_group!(
name = my_group;
benchmarks = |group: &mut BinaryBenchmarkGroup| setup_my_group(group)
);