Skip to content

Commit 98e4a25

Browse files
committed
Add --include and --exclude flags to the bench_runtime_local command
1 parent 6865d6b commit 98e4a25

File tree

4 files changed

+92
-22
lines changed

4 files changed

+92
-22
lines changed

collector/benchlib/src/benchmark.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@ pub fn benchmark_suite<F: FnOnce(&mut BenchmarkSuite)>(define_func: F) {
1515
suite.run().expect("Benchmark suite has failed");
1616
}
1717

18+
/// Type-erased function that performs a benchmark.
19+
struct BenchmarkWrapper {
20+
func: Box<dyn Fn() -> anyhow::Result<BenchmarkResult>>,
21+
}
22+
23+
type BenchmarkMap = HashMap<&'static str, BenchmarkWrapper>;
24+
1825
#[derive(Default)]
1926
pub struct BenchmarkSuite {
20-
benchmarks: HashMap<&'static str, BenchmarkWrapper>,
27+
benchmarks: BenchmarkMap,
2128
}
2229

2330
impl BenchmarkSuite {
@@ -54,33 +61,42 @@ impl BenchmarkSuite {
5461
let args = parse_cli()?;
5562
match args {
5663
Args::Benchmark(args) => {
57-
self.run_benchmark(args)?;
64+
run_benchmark(args, self.benchmarks)?;
5865
}
5966
}
6067

6168
Ok(())
6269
}
70+
}
6371

64-
fn run_benchmark(self, args: BenchmarkArgs) -> anyhow::Result<()> {
65-
let mut items: Vec<_> = self.benchmarks.into_iter().collect();
66-
items.sort_unstable_by_key(|item| item.0);
72+
fn run_benchmark(args: BenchmarkArgs, benchmarks: BenchmarkMap) -> anyhow::Result<()> {
73+
let mut items: Vec<(&'static str, BenchmarkWrapper)> = benchmarks
74+
.into_iter()
75+
.filter(|(name, _)| passes_filter(name, args.exclude.as_deref(), args.include.as_deref()))
76+
.collect();
77+
items.sort_unstable_by_key(|item| item.0);
6778

68-
let mut results: Vec<BenchmarkResult> = Vec::with_capacity(items.len());
69-
for (name, def) in items {
70-
for i in 0..args.iterations {
71-
let result = (def.func)()?;
72-
log::info!("Benchmark (run {i}) `{}` completed: {:?}", name, result);
73-
results.push(result);
74-
}
79+
let mut results: Vec<BenchmarkResult> = Vec::with_capacity(items.len());
80+
for (name, def) in items {
81+
for i in 0..args.iterations {
82+
let result = (def.func)()?;
83+
log::info!("Benchmark (run {i}) `{name}` completed: {result:?}");
84+
results.push(result);
7585
}
76-
77-
println!("{}", serde_json::to_string(&results)?);
78-
Ok(())
7986
}
87+
88+
println!("{}", serde_json::to_string(&results)?);
89+
Ok(())
8090
}
8191

82-
struct BenchmarkWrapper {
83-
func: Box<dyn Fn() -> anyhow::Result<BenchmarkResult>>,
92+
/// Tests if the name of the benchmark passes through the include and exclude filter flags.
93+
fn passes_filter(name: &str, exclude: Option<&str>, include: Option<&str>) -> bool {
94+
match (exclude, include) {
95+
(Some(exclude), Some(include)) => name.starts_with(include) && !name.starts_with(exclude),
96+
(None, Some(include)) => name.starts_with(include),
97+
(Some(exclude), None) => !name.starts_with(&exclude),
98+
(None, None) => true,
99+
}
84100
}
85101

86102
/// Copied from `iai`, so that we don't have to use unstable features.

collector/benchlib/src/cli.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ pub struct BenchmarkArgs {
1111
/// How many times should each benchmark be repeated.
1212
#[clap(long, default_value = "5")]
1313
pub iterations: u32,
14+
15+
/// Exclude all benchmarks matching a prefix in this comma-separated list
16+
#[clap(long)]
17+
pub exclude: Option<String>,
18+
19+
/// Include only benchmarks matching a prefix in this comma-separated list
20+
#[clap(long)]
21+
pub include: Option<String>,
1422
}
1523

1624
pub fn parse_cli() -> anyhow::Result<Args> {

collector/src/bin/collector.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,10 +562,19 @@ struct BenchRustcOption {
562562
enum Commands {
563563
/// Benchmarks the performance of programs generated by a local rustc
564564
BenchRuntimeLocal {
565+
/// The path to the local rustc to measure
565566
rustc: String,
566567
/// Identifier to associate benchmark results with
567568
#[clap(long)]
568569
id: Option<String>,
570+
571+
/// Exclude all benchmarks matching a prefix in this comma-separated list
572+
#[clap(long)]
573+
exclude: Option<String>,
574+
575+
/// Include only benchmarks matching a prefix in this comma-separated list
576+
#[clap(long)]
577+
include: Option<String>,
569578
},
570579
/// Benchmarks a local rustc
571580
BenchLocal {
@@ -692,8 +701,19 @@ fn main_result() -> anyhow::Result<i32> {
692701
let target_triple = format!("{}-unknown-linux-gnu", std::env::consts::ARCH);
693702

694703
match args.command {
695-
Commands::BenchRuntimeLocal { rustc, id } => {
696-
bench_runtime(&rustc, id.as_deref(), runtime_benchmark_dir)?;
704+
Commands::BenchRuntimeLocal {
705+
rustc,
706+
id,
707+
exclude,
708+
include,
709+
} => {
710+
bench_runtime(
711+
&rustc,
712+
id.as_deref(),
713+
exclude,
714+
include,
715+
runtime_benchmark_dir,
716+
)?;
697717
Ok(0)
698718
}
699719
Commands::BenchLocal {

collector/src/runtime.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,56 @@ struct BenchmarkBinary {
1010
path: PathBuf,
1111
}
1212

13-
pub fn bench_runtime(rustc: &str, id: Option<&str>, benchmark_dir: PathBuf) -> anyhow::Result<()> {
13+
/// Perform a series of runtime benchmarks using the provided `rustc` compiler.
14+
/// The runtime benchmarks are looked up in `benchmark_dir`, which is expected to be a path
15+
/// to a Cargo crate. All binaries built by that crate will are expected to be runtime benchmark
16+
/// suites that leverage `benchlib`.
17+
pub fn bench_runtime(
18+
rustc: &str,
19+
id: Option<&str>,
20+
exclude: Option<String>,
21+
include: Option<String>,
22+
benchmark_dir: PathBuf,
23+
) -> anyhow::Result<()> {
1424
let toolchain = get_local_toolchain(&[Profile::Opt], rustc, None, None, id, "")?;
1525
let output = compile_runtime_benchmarks(&toolchain, &benchmark_dir)?;
1626
let binaries = gather_binaries(&output)?;
1727

1828
for binary in binaries {
1929
let name = binary.path.file_name().and_then(|s| s.to_str()).unwrap();
2030

21-
let data: Vec<BenchmarkResult> = execute_runtime_binary(&binary.path, name)?;
31+
let data: Vec<BenchmarkResult> =
32+
execute_runtime_binary(&binary.path, name, exclude.as_deref(), include.as_deref())?;
2233
// TODO: do something with the result
2334
println!("{name}: {:?}", data);
2435
}
2536

2637
Ok(())
2738
}
2839

29-
fn execute_runtime_binary(binary: &Path, name: &str) -> anyhow::Result<Vec<BenchmarkResult>> {
40+
/// Execute a single runtime benchmark suite defined in a binary crate located in
41+
/// `runtime-benchmarks`. The binary is expected to use benchlib's `BenchmarkSuite` to execute
42+
/// a set of runtime benchmarks and return a list of `BenchmarkResult`s encoded as JSON.
43+
fn execute_runtime_binary(
44+
binary: &Path,
45+
name: &str,
46+
exclude: Option<&str>,
47+
include: Option<&str>,
48+
) -> anyhow::Result<Vec<BenchmarkResult>> {
3049
// Turn off ASLR
3150
let mut command = Command::new("setarch");
3251
command.arg(std::env::consts::ARCH);
3352
command.arg("-R");
3453
command.arg(binary);
3554
command.arg("benchmark");
3655

56+
if let Some(exclude) = exclude {
57+
command.args(&["--exclude", exclude]);
58+
}
59+
if let Some(include) = include {
60+
command.args(&["--include", include]);
61+
}
62+
3763
let result = command.output()?;
3864

3965
if !result.status.success() {

0 commit comments

Comments
 (0)