Quickstart

Suppose the crate's binary is called my-foo and this binary takes a file path as positional argument. This first example shows the basic usage of the high-level api with the #[binary_benchmark] attribute:

extern crate iai_callgrind;
macro_rules! env { ($m:tt) => {{ "/some/path" }} }
use iai_callgrind::{binary_benchmark, binary_benchmark_group, main};

#[binary_benchmark]
#[bench::some_id("foo.txt")]
fn bench_binary(path: &str) -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
        .arg(path)
        .build()
}

binary_benchmark_group!(
    name = my_group;
    benchmarks = bench_binary
);

fn main() {
main!(binary_benchmark_groups = my_group);
}

If you want to try out this example with your crate's binary, put the above code into a file in $WORKSPACE_ROOT/benches/binary_benchmark.rs. Next, replace my-foo in env!("CARGO_BIN_EXE_my-foo") with the name of a binary of your crate.

Note the env! macro is a rust builtin macro and CARGO_BIN_EXE_<name> is documented here.

You should always use env!("CARGO_BIN_EXE_<name>") to determine the path to the binary of your crate. Do not use relative paths like target/release/my-foo since this might break your benchmarks in many ways. The environment variable does exactly the right thing and the usage is short and simple.

Lastly, adjust the argument of the Command and add the following to your Cargo.toml:

[[bench]]
name = "binary_benchmark"
harness = false

Running

cargo bench

presents you with something like the following:

binary_benchmark::my_group::bench_binary some_id:("foo.txt") -> target/release/my-foo foo.txt
  Instructions:              342129|N/A             (*********)
  L1 Hits:                   457370|N/A             (*********)
  L2 Hits:                      734|N/A             (*********)
  RAM Hits:                    4096|N/A             (*********)
  Total read+write:          462200|N/A             (*********)
  Estimated Cycles:          604400|N/A             (*********)

As opposed to library benchmarks, binary benchmarks have access to a low-level api. Here, pretty much the same as the above high-level usage but written in the low-level api:

extern crate iai_callgrind;
macro_rules! env { ($m:tt) => {{ "/some/path" }} }
use iai_callgrind::{BinaryBenchmark, Bench, binary_benchmark_group, main};

binary_benchmark_group!(
    name = my_group;
    benchmarks = |group: &mut BinaryBenchmarkGroup| {
        group.binary_benchmark(BinaryBenchmark::new("bench_binary")
            .bench(Bench::new("some_id")
                .command(iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-foo"))
                    .arg("foo.txt")
                    .build()
                )
            )
        )
    }
);

fn main() {
main!(binary_benchmark_groups = my_group);
}

If in doubt, use the high-level api. You can still migrate to the low-level api very easily if you really need to. The other way around is more involved.