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 thebenchmarks
argument, 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| EXPRESSION
or the shorter
|IDENTIFIER| EXPRESSION
where
IDENTIFIER
is the identifier of your choice for theBinaryBenchmarkGroup
(we usegroup
throughout our examples) andEXPRESSION
is the code where you make use of theBinaryBenchmarkGroup
to 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::BinaryBenchmarkGroup
crate::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_benchmark
crate::BenchmarkId
: The benchmark id is for example used incrate::BinaryBenchmark::new
andcrate::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::Command
s 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)
);