1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! One cache benchmark's owned workload and process boundary.
mod evidence;
mod local;
mod workload;
use std::ffi::OsString;
use std::path::PathBuf;
use clap::{Parser, Subcommand};
use crate::{RailError, RailResult};
#[derive(Debug, Parser)]
#[command(
name = "cargo rail-bench",
version,
about = "Compare native Cargo, Cargo-Rail and sccache on an isolated cache workload"
)]
struct Cli {
#[command(subcommand)]
command: Option<Operation>,
}
#[derive(Debug, Subcommand)]
enum Operation {
/// Compare local caches on Unix; retain samples and correctness evidence.
Local(local::Options),
/// Prepare the bundled workload and prefetch locked dependencies without timing.
Prepare {
/// New workspace directory; its parent must exist.
#[arg(long)]
output: PathBuf,
/// Shared bundled Git dependency directory; existing repositories must match the bundled revision.
#[arg(long)]
git_source: Option<PathBuf>,
/// Use cached registry packages; the bundled local Git dependency is still prefetched.
#[arg(long)]
offline: bool,
},
}
/// Execute the installed benchmark command from process arguments.
///
/// With no subcommand, run the local comparison with its default options.
///
/// Preparation creates the selected workload and Git source paths and prefetches
/// locked dependencies into the selected Cargo home. Existing workspaces are refused;
/// failed preparation is retained for diagnosis.
pub fn run(arguments: impl IntoIterator<Item = OsString>) -> RailResult<()> {
let mut arguments = arguments.into_iter().collect::<Vec<_>>();
if arguments.get(1).is_some_and(|argument| argument == "rail-bench") {
arguments.remove(1);
}
match Cli::parse_from(arguments).command {
None => run(["cargo-rail-bench", "local"].map(OsString::from)),
Some(Operation::Local(options)) => local::run(options),
Some(Operation::Prepare {
output,
git_source,
offline,
}) => {
let git_source = match git_source {
Some(path) => path,
None => {
let mut name = output
.file_name()
.ok_or_else(|| RailError::message("workload output has no directory name"))?
.to_os_string();
name.push(".git-source");
output.with_file_name(name)
}
};
let workspace = workload::materialize(&output, &git_source, offline).map_err(|error| {
error.context(format!(
"preparing {}; any partial workload and Git source are retained",
output.display()
))
})?;
println!("Prepared cache benchmark workload: {}", workspace.display());
Ok(())
}
}
}