iai_callgrind

Macro binary_benchmark_group

source
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
    ) => { ... };
}
Available on crate feature 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 the main! macro

  • config (optional): A crate::BinaryBenchmarkConfig

  • compare_by_id (optional): The default is false. If true, all commands from the functions specified in the benchmarks 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 the BinaryBenchmarkGroup (we use group throughout our examples) and EXPRESSION is the code where you make use of the BinaryBenchmarkGroup 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:

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)
);