iai_callgrind

Struct Command

source
pub struct Command(/* private fields */);
Available on crate feature default only.
Expand description

Provide the Command to be benchmarked

Command is a builder for the binary which is going to be benchmarked providing fine-grained control over how the Command for the valgrind benchmark should be executed.

The default configuration is created with Command::new providing a path to an executable. Adding a crate’s binary is usually done with env!("CARGO_BIN_EXE_<name>") where <name> is the name of the binary. The builder methods allow the configuration to be changed prior to Command::build. The Command can be reused to build multiple processes.

§Examples

Suppose your crate’s binary is called my-echo:

use iai_callgrind::Command;
let command = Command::new(env!("CARGO_BIN_EXE_my-echo"));

However, an iai-callgrind benchmark is not limited to a crate’s binaries, it can be any executable in the $PATH, or an absolute path to a binary installed on your system. The following will create a Command for the system’s echo from the $PATH:

use iai_callgrind::Command;
let command = Command::new("echo");

Implementations§

source§

impl Command

source

pub fn new<T>(path: T) -> Self
where T: AsRef<OsStr>,

Create a new Command which is run under valgrind.

Use env!("CARGO_BIN_EXE_<name>) to provide the path to an executable of your project instead of target/release/<name>.

This Command is a builder for the binary which is going to be benchmarked but is not executed right away. We simply gather all the information to be finally able to execute the command under valgrind, later (after we collected all the commands in this benchmark file). As opposed to std::process::Command, the build is finalized with Command::build.

§Relative paths

Relative paths are interpreted relative to the current directory and if not running the benchmarks in a Sandbox, depends on where cargo bench sets the current directory. Usually, it’s best to use Path::canonicalize to resolve the relative path to a binary in your project’s directory. In case you’re running the benchmark in a Sandbox, the path is interpreted relative to the root directory of the Sandbox. Iai-Callgrind tries to resolve simple names like Command::new("echo") searching the $PATH. To disambiguate between simple names and relative paths, use ./. For example echo is searched in the $PATH and ./echo is interpreted relative.

§Examples

Assume the project’s binary or one of your project’s binaries name is my-echo:

use iai_callgrind::Command;

let command = Command::new(env!("CARGO_BIN_EXE_my-echo"));

or use your system’s echo from the $PATH with

use iai_callgrind::Command;

let command = Command::new("echo").arg("foo").build();
source

pub fn delay<T: Into<Delay>>(&mut self, delay: T) -> &mut Self

Delay the execution of the Command

This option allows to delay the Command execution till a certain event has happened. Supported events are:

  • Timer expired
  • File path exists
  • TCP/UDP connect succeeded

Delay can be used in combination with Command::setup_parallel to wait for an event that is triggered within the setup() function. E.g. the setup starts a server that is needed by the Command.

§Examples
use iai_callgrind::{binary_benchmark_group, binary_benchmark, main, Command, Delay, DelayKind};

fn start_server() {
    // action to start the server, creates pid file
    std::fs::File::create("/tmp/my-server.pid").unwrap();
}

#[binary_benchmark]
#[bench::server(setup = start_server)]
fn bench_binary() -> Command {
    Command::new(env!("CARGO_BIN_EXE_my-echo"))
        .setup_parallel(true)
        .delay(Delay::new(DelayKind::PathExists("/tmp/my-server.pid".into())))
        .build()
}

binary_benchmark_group!(name = my_group; benchmarks = bench_binary);
main!(binary_benchmark_groups = my_group);
source

pub fn setup_parallel(&mut self, setup_parallel: bool) -> &mut Self

Execute the setup() in parallel to the Command.

This option changes the execution flow in a way that the Command is executed parallel to the setup instead of waiting for the setup to complete.

This can be combined with the usage of Delay to further control the timing when the Command is executed.

§Examples
use std::time::Duration;
use std::net::{SocketAddr, TcpListener};
use std::thread;
use iai_callgrind::{binary_benchmark_group, binary_benchmark, main, Command, Delay, DelayKind};

fn setup_tcp_server() {
    thread::sleep(Duration::from_millis(300));
    let _listener = TcpListener::bind("127.0.0.1:31000".parse::<SocketAddr>().unwrap()).unwrap();
    thread::sleep(Duration::from_secs(1));
}

#[binary_benchmark]
#[bench::delay(setup = setup_tcp_server())]
fn bench_binary() -> iai_callgrind::Command {
    Command::new(env!("CARGO_BIN_EXE_my-echo"))
        .setup_parallel(true)
        .delay(
            Delay::new(
                DelayKind::TcpConnect("127.0.0.1:31000".parse::<SocketAddr>().unwrap()))
                .timeout(Duration::from_millis(500))
        ).build()
}

binary_benchmark_group!(name = delay; benchmarks = bench_binary);
main!(binary_benchmark_groups = delay);
source

pub fn arg<T>(&mut self, arg: T) -> &mut Self
where T: Into<OsString>,

Adds an argument to pass to the Command

This option works exactly the same way as std::process::Command::arg. To pass multiple arguments see Command::args.

§Examples
use iai_callgrind::{binary_benchmark_group, binary_benchmark};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-echo"))
        .arg("foo")
        .build()
}

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

pub fn args<I, T>(&mut self, args: T) -> &mut Self
where I: Into<OsString>, T: IntoIterator<Item = I>,

Adds multiple arguments to pass to the Command

This option works exactly the same way as std::process::Command::args.

§Examples

The following will execute my-echo foo.

use iai_callgrind::{binary_benchmark_group, binary_benchmark};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-echo"))
        .arg("foo")
        .build()
}

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

pub fn stdin<T>(&mut self, stdin: T) -> &mut Self
where T: Into<Stdin>,

Configuration for the process’s standard input (Stdin)

This method takes an Stdin, Stdio and everything that implements Into<Stdin>. The Stdin enum mirrors most of the possibilities of std::process::Stdio but also some additional possibilities most notably Stdin::Setup (see there for more details).

Per default, the stdin is not inherited from the parent and any attempt by the child process to read from the stdin stream will result in the stream immediately closing.

The options you might be interested in the most are Stdin::File, which mirrors the behaviour of std::process::Stdio if Stdio is a std::fs::File, and Stdin::Setup, which is special to iai-callgrind and lets you pipe the output of the setup function into the Stdin of this Command. If you need to delay the Command when using Stdin::Setup, you can do so with Command::delay.

§Implementation details

As the Command itself is not executed immediately, the std::process::Stdio is not created either. We only use the information from here to create the std::process::Stdio later after we collected all commands. Setting the Stdin to Inherit is discouraged and won’t have the effect you might expect, since the benchmark runner (the parent) uses the Stdin for its own purposes and closes it before this Command is executed.

§Examples

Pipe the content of a file (benches/fixture.txt) into the stdin of this Command:

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Stdio};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .stdin(Stdio::File("benches/fixture.txt".into()))
        .build()
}

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

Pipe the Stdout of setup into the Stdin of this Command:

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Stdin, Pipe};

fn setup_pipe() {
    // All output to Stdout of this function will be piped into the Stdin of `my-exe`
    println!("This string will be piped into the stdin of my-exe");
}

#[binary_benchmark(setup = setup_pipe())]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .stdin(Stdin::Setup(Pipe::Stdout))
        .build()
}

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

pub fn stdout<T>(&mut self, stdio: T) -> &mut Self
where T: Into<Stdio>,

Configuration for the Commands standard output (Stdout) handle.

The output of benchmark commands and functions are usually captured by the benchmark runner. This can be changed for example with the --nocapture option or here. Any option specified here takes precedence over the changes which --nocapture makes to the Stdout of the command.

§Examples

To see the output of this Command regardless of --nocapture in the benchmark output

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Stdio};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .stdout(Stdio::Inherit)
        .build()
}

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

To pipe the Stdout into a file /tmp/benchmark.output:

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Stdio};
use std::path::PathBuf;

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .stdout(Stdio::File("/tmp/benchmark.output".into()))
        // or
        .stdout(PathBuf::from("/tmp/benchmark.output"))
        .build()
}

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

pub fn stderr<T>(&mut self, stdio: T) -> &mut Self
where T: Into<Stdio>,

Configuration for the Commands standard error output (Stderr) handle.

This option is similar to Command::stdout but configures the Stderr. See there for more details.

§Examples

To see the error output of this Command regardless of --nocapture in the benchmark output

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Stdio};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .stderr(Stdio::Inherit)
        .build()
}

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

To pipe the Stderr into a file /tmp/benchmark.output:

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Stdio};
use std::path::PathBuf;

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .stderr(Stdio::File("/tmp/benchmark.output".into()))
        // or
        .stderr(PathBuf::from("/tmp/benchmark.output"))
        .build()
}

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

pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
where K: Into<OsString>, V: Into<OsString>,

Add an environment variable available for this Command

These environment variables are available independently of the setting of BinaryBenchmarkConfig::env_clear and additive to environment variables added with BinaryBenchmarkConfig::env.

§Examples

An example for a custom environment variable “FOO=BAR”:

use iai_callgrind::{binary_benchmark_group, binary_benchmark};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .env("FOO", "BAR")
        .build()
}

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

pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
where I: IntoIterator<Item = (K, V)>, K: Into<OsString>, V: Into<OsString>,

Add multiple environment variables available for this Command

See Command::env for more details.

§Examples

Add the custom environment variables “FOO=BAR” and BAR=BAZ:

use iai_callgrind::{binary_benchmark_group, binary_benchmark};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .envs([("FOO", "BAR"), ("BAR", "BAZ")])
        .build()
}

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

pub fn current_dir<T>(&mut self, value: T) -> &mut Self
where T: Into<PathBuf>,

Set the directory of the benchmarked binary (Default: Unchanged)

See also BinaryBenchmarkConfig::current_dir

§Examples

To set the working directory of your Command to /tmp:

use iai_callgrind::{binary_benchmark_group, binary_benchmark};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .current_dir("/tmp")
        .build()
}

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

and the following will change the current directory to fixtures located in the root of the BinaryBenchmarkConfig::sandbox

use iai_callgrind::{binary_benchmark_group, binary_benchmark, Sandbox, BinaryBenchmarkConfig};

fn setup_sandbox() {
    std::fs::create_dir("fixtures").unwrap();
}

#[binary_benchmark(
    setup = setup_sandbox(),
    config = BinaryBenchmarkConfig::default().sandbox(Sandbox::new(true))
)]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .current_dir("fixtures")
        .build()
}

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

pub fn exit_with(&mut self, exit_with: ExitWith) -> &mut Self

Set the expected exit status ExitWith of this Command

See also BinaryBenchmarkConfig::exit_with. This setting overwrites the setting of the BinaryBenchmarkConfig.

§Examples

If the command is expected to exit with a specific code, for example 100:

use iai_callgrind::{binary_benchmark_group, binary_benchmark, ExitWith};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .exit_with(ExitWith::Code(100))
        .build()
}

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

If a command is expected to fail, but the exit code doesn’t matter:

use iai_callgrind::{binary_benchmark_group, binary_benchmark, ExitWith};

#[binary_benchmark]
fn bench_binary() -> iai_callgrind::Command {
    iai_callgrind::Command::new(env!("CARGO_BIN_EXE_my-exe"))
        .exit_with(ExitWith::Failure)
        .build()
}

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

pub fn build(&mut self) -> Self

Finalize and build this Command

§Examples
use iai_callgrind::Command;

let command: Command = Command::new(env!("CARGO_BIN_EXE_my-exe"))
    .arg("foo")
    .build();

Trait Implementations§

source§

impl AsRef<Command> for Command

source§

fn as_ref(&self) -> &InternalCommand

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Clone for Command

source§

fn clone(&self) -> Command

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Command

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for Command

source§

fn default() -> Command

Returns the “default value” for a type. Read more
source§

impl From<&Command> for InternalCommand

source§

fn from(value: &Command) -> Self

Converts to this type from the input type.
source§

impl From<&Command> for Command

source§

fn from(value: &Command) -> Self

Converts to this type from the input type.
source§

impl From<&mut Command> for InternalCommand

source§

fn from(value: &mut Command) -> Self

Converts to this type from the input type.
source§

impl From<&mut Command> for Command

source§

fn from(value: &mut Command) -> Self

Converts to this type from the input type.
source§

impl From<Command> for InternalCommand

source§

fn from(value: Command) -> Self

Converts to this type from the input type.
source§

impl PartialEq for Command

source§

fn eq(&self, other: &Command) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl StructuralPartialEq for Command

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

source§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.