use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use std::path::Path;
use std::process::Command;
use worktrunk::testing::isolate_subprocess_env;
use wt_perf::{RepoConfig, create_repo, invalidate_caches_auto};
const STUB_CONFIG: &str = "[aliases]\nstub = \"echo hello\"\n";
const WITH_VARS_CONFIG: &str = r#"[aliases]
with_vars = "echo {{ branch }} {{ default_branch }} {{ commit }} {{ short_commit }} {{ primary_worktree_path }} {{ worktree_path }}"
"#;
const fn lean_worktrees(worktrees: usize) -> RepoConfig {
RepoConfig {
commits_on_main: 1,
files: 1,
branches: 0,
commits_per_branch: 0,
worktrees,
worktree_commits_ahead: 0,
worktree_uncommitted_files: 0,
}
}
fn wt_cmd(binary: &Path, repo: &Path, user_config: &Path, args: &[&str]) -> Command {
let mut cmd = Command::new(binary);
cmd.args(args).current_dir(repo);
isolate_subprocess_env(&mut cmd, Some(user_config));
cmd
}
fn run_and_check(mut cmd: Command, label: &str) {
let output = cmd.output().unwrap();
assert!(
output.status.success(),
"{label} failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
fn bench_dispatch(c: &mut Criterion) {
let mut group = c.benchmark_group("dispatch");
let binary = Path::new(env!("CARGO_BIN_EXE_wt"));
group.bench_function("wt_version", |b| {
b.iter(|| {
let mut cmd = Command::new(binary);
cmd.arg("--version");
isolate_subprocess_env(&mut cmd, None);
run_and_check(cmd, "wt_version");
});
});
for worktrees in [1usize, 100] {
let temp = create_repo(&lean_worktrees(worktrees));
let repo_path = temp.path().join("repo");
let stub_config = temp.path().join("stub-config.toml");
let vars_config = temp.path().join("with-vars-config.toml");
std::fs::write(&stub_config, STUB_CONFIG).unwrap();
std::fs::write(&vars_config, WITH_VARS_CONFIG).unwrap();
for (id_prefix, alias_name, user_config) in [
(None, "stub", &stub_config),
(Some("with_vars"), "with_vars", &vars_config),
] {
for cold in [false, true] {
let cache_label = if cold { "cold" } else { "warm" };
let id = match id_prefix {
Some(prefix) => format!("{prefix}/{cache_label}"),
None => cache_label.to_string(),
};
group.bench_with_input(BenchmarkId::new(id, worktrees), &worktrees, |b, _| {
let run = || {
run_and_check(
wt_cmd(binary, &repo_path, user_config, &[alias_name]),
"dispatch",
);
};
if cold {
b.iter_batched(
|| invalidate_caches_auto(&repo_path),
|_| run(),
criterion::BatchSize::PerIteration,
);
} else {
b.iter(run);
}
});
}
}
}
group.finish();
}
criterion_group! {
name = benches;
config = Criterion::default()
.sample_size(30)
.measurement_time(std::time::Duration::from_secs(15))
.warm_up_time(std::time::Duration::from_secs(3));
targets = bench_dispatch
}
criterion_main!(benches);