#![allow(missing_docs)]
pub mod bin_bench;
pub mod error;
pub mod lib_bench;
pub use iai_callgrind_runner::api::{
BinaryBenchmark as InternalBinaryBenchmark,
BinaryBenchmarkBench as InternalBinaryBenchmarkBench,
BinaryBenchmarkConfig as InternalBinaryBenchmarkConfig,
BinaryBenchmarkGroup as InternalBinaryBenchmarkGroup,
BinaryBenchmarkGroups as InternalBinaryBenchmarkGroups,
CachegrindRegressionConfig as InternalCachegrindRegressionConfig,
CallgrindRegressionConfig as InternalCallgrindRegressionConfig, Command as InternalCommand,
Delay as InternalDelay, DhatRegressionConfig as InternalDhatRegressionConfig,
EntryPoint as InternalEntryPoint, ExitWith as InternalExitWith, Fixtures as InternalFixtures,
FlamegraphConfig as InternalFlamegraphConfig,
LibraryBenchmark as InternalLibraryBenchmarkBenches,
LibraryBenchmarkBench as InternalLibraryBenchmarkBench,
LibraryBenchmarkConfig as InternalLibraryBenchmarkConfig,
LibraryBenchmarkGroup as InternalLibraryBenchmarkGroup,
LibraryBenchmarkGroups as InternalLibraryBenchmarkGroups, OutputFormat as InternalOutputFormat,
RawArgs as InternalRawArgs, Sandbox as InternalSandbox, Tool as InternalTool,
ToolFlamegraphConfig as InternalToolFlamegraphConfig,
ToolOutputFormat as InternalToolOutputFormat,
ToolRegressionConfig as InternalToolRegressionConfig, Tools as InternalTools,
};
#[derive(Debug, Clone)]
pub struct InternalMacroLibBench {
pub id_display: Option<&'static str>,
pub args_display: Option<&'static str>,
pub func: fn(),
pub config: Option<fn() -> InternalLibraryBenchmarkConfig>,
}
#[derive(Debug, Clone)]
pub struct InternalMacroBinBench {
pub id_display: Option<&'static str>,
pub args_display: Option<&'static str>,
pub func: fn() -> crate::Command,
pub setup: Option<fn()>,
pub teardown: Option<fn()>,
pub config: Option<fn() -> InternalBinaryBenchmarkConfig>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ModulePath(String);
impl ModulePath {
pub fn new(path: &str) -> Self {
Self(path.to_owned())
}
#[must_use]
pub fn join(&self, path: &str) -> Self {
Self(format!("{}::{path}", self.0))
}
}
impl std::fmt::Display for ModulePath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
pub enum BenchmarkKind {
BinaryBenchmark,
LibraryBenchmark,
}
pub struct Runner {
cmd: std::process::Command,
module_path: String,
}
impl Runner {
pub fn new(
exe: Option<&str>,
kind: &BenchmarkKind,
package_dir: &str,
package_name: &str,
file: &str,
module_path: &str,
bench_bin: String,
) -> Self {
const LIBRARY_VERSION: &str = "0.16.1";
let mut cmd = std::process::Command::new(exe.unwrap_or("iai-callgrind-runner"));
cmd.arg(LIBRARY_VERSION);
match kind {
BenchmarkKind::BinaryBenchmark => {
cmd.arg("--bin-bench");
}
BenchmarkKind::LibraryBenchmark => {
cmd.arg("--lib-bench");
}
}
cmd.arg(package_dir);
cmd.arg(package_name);
cmd.arg(file);
cmd.arg(module_path);
cmd.arg(bench_bin);
Self {
cmd,
module_path: module_path.to_owned(),
}
}
pub fn exec(mut self, encoded: Vec<u8>) -> Result<(), error::Errors> {
let mut child = self
.cmd
.arg(encoded.len().to_string())
.stdin(std::process::Stdio::piped())
.spawn()
.map_err(|e| {
let mut errors = error::Errors::default();
errors.add(error::Error::new(
&ModulePath::new(&self.module_path),
&format!(
"Failed to run benchmarks: {e}.\n\nIs iai-callgrind-runner installed and \
iai-callgrind-runner in your $PATH?.\nYou can set the environment \
variable IAI_CALLGRIND_RUNNER to the absolute path of the \
iai-callgrind-runner executable.\n\nMake sure you have followed the \
installation instructions in the guide:\n\
https://iai-callgrind.github.io/iai-callgrind/latest/html/installation/iai_callgrind.html",
),
));
errors
})?;
let mut stdin = child
.stdin
.take()
.expect("Opening stdin to submit encoded benchmark");
std::thread::spawn(move || {
use std::io::Write;
stdin
.write_all(&encoded)
.expect("Writing encoded benchmark to stdin");
});
let status = child.wait().expect(
"Internal error: Waiting for child process to exit should succeed. If the problem \
persists please submit a bug report.",
);
if !status.success() {
let code = status.code().unwrap_or(1i32);
std::process::exit(code);
}
Ok(())
}
}