Skip to content

Commit 6d16080

Browse files
committed
Add --match CLI argument for exact matching benchmark names
To avoid problems with prefixes/suffixes in programmatic usage of the collector.
1 parent c492914 commit 6d16080

File tree

3 files changed

+95
-37
lines changed

3 files changed

+95
-37
lines changed

collector/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ The following options alter the behaviour of the `bench_local` subcommand.
135135
dedicated to artifact sizes (ending with `-tiny`).
136136
- `--id <ID>` the identifier that will be used to identify the results in the
137137
database.
138+
- `--match <BENCHMARKS>`: comma-separated list of benchmark names that should be
139+
executed. The names have to match exactly. Cannot be combined with
140+
`--include`/`--exclude`/`--exclude-suffix`.
138141
- `--include <INCLUDE>`: the inverse of `--exclude`. The argument is a
139142
comma-separated list of benchmark prefixes. When this option is specified, a
140143
benchmark is included in the run only if its name matches one of the given

collector/src/bin/collector.rs

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use collector::compile::benchmark::scenario::Scenario;
4040
use collector::compile::benchmark::target::Target;
4141
use collector::compile::benchmark::{
4242
compile_benchmark_dir, get_compile_benchmarks, ArtifactType, Benchmark, BenchmarkName,
43+
CompileBenchmarkFilter,
4344
};
4445
use collector::compile::execute::bencher::BenchProcessor;
4546
use collector::compile::execute::profiler::{ProfileProcessor, Profiler};
@@ -337,6 +338,16 @@ struct LocalOptions {
337338
#[arg(long, value_delimiter = ',')]
338339
include: Vec<String>,
339340

341+
/// Include only benchmarks in this comma-separated list
342+
#[arg(
343+
long,
344+
value_delimiter = ',',
345+
conflicts_with("include"),
346+
conflicts_with("exclude"),
347+
conflicts_with("exclude_suffix")
348+
)]
349+
r#match: Vec<String>,
350+
340351
/// Include only benchmarks belonging to the given categories.
341352
#[arg(long, value_parser = EnumArgParser::<Category>::default(), default_value = "Primary,Secondary")]
342353
category: MultiEnumValue<Category>,
@@ -688,6 +699,25 @@ enum DownloadSubcommand {
688699
},
689700
}
690701

702+
impl<'a> From<&'a LocalOptions> for CompileBenchmarkFilter<'a> {
703+
fn from(value: &'a LocalOptions) -> Self {
704+
if !value.r#match.is_empty() {
705+
Self::Exact(&value.r#match)
706+
} else if !value.include.is_empty()
707+
|| !value.exclude.is_empty()
708+
|| !value.exclude_suffix.is_empty()
709+
{
710+
Self::Fuzzy {
711+
include: &value.include,
712+
exclude: &value.exclude,
713+
exclude_suffix: &value.exclude_suffix,
714+
}
715+
} else {
716+
Self::All
717+
}
718+
}
719+
}
720+
691721
fn main_result() -> anyhow::Result<i32> {
692722
env_logger::init();
693723

@@ -884,12 +914,7 @@ fn main_result() -> anyhow::Result<i32> {
884914
target_triple,
885915
)?;
886916

887-
let mut benchmarks = get_compile_benchmarks(
888-
&compile_benchmark_dir,
889-
&local.include,
890-
&local.exclude,
891-
&local.exclude_suffix,
892-
)?;
917+
let mut benchmarks = get_compile_benchmarks(&compile_benchmark_dir, (&local).into())?;
893918
benchmarks.retain(|b| local.category.0.contains(&b.category()));
894919

895920
let artifact_id = ArtifactId::Commit(Commit {
@@ -1006,9 +1031,11 @@ fn main_result() -> anyhow::Result<i32> {
10061031

10071032
let mut benchmarks = get_compile_benchmarks(
10081033
&compile_benchmark_dir,
1009-
&split_args(include),
1010-
&split_args(exclude),
1011-
&[],
1034+
CompileBenchmarkFilter::Fuzzy {
1035+
include: &split_args(include),
1036+
exclude: &split_args(exclude),
1037+
exclude_suffix: &[],
1038+
},
10121039
)?;
10131040
benchmarks.retain(|b| b.category().is_primary_or_secondary());
10141041

@@ -1102,12 +1129,7 @@ fn main_result() -> anyhow::Result<i32> {
11021129
let scenarios = &opts.scenarios.0;
11031130
let backends = &opts.codegen_backends.0;
11041131

1105-
let mut benchmarks = get_compile_benchmarks(
1106-
&compile_benchmark_dir,
1107-
&local.include,
1108-
&local.exclude,
1109-
&local.exclude_suffix,
1110-
)?;
1132+
let mut benchmarks = get_compile_benchmarks(&compile_benchmark_dir, (&local).into())?;
11111133
benchmarks.retain(|b| local.category.0.contains(&b.category()));
11121134

11131135
let mut errors = BenchmarkErrors::new();
@@ -1315,12 +1337,7 @@ fn binary_stats_compile(
13151337
Profile::Opt => CargoProfile::Release,
13161338
_ => return Err(anyhow::anyhow!("Only Debug and Opt profiles are supported")),
13171339
};
1318-
let benchmarks = get_compile_benchmarks(
1319-
&compile_benchmark_dir(),
1320-
&local.include,
1321-
&local.exclude,
1322-
&local.exclude_suffix,
1323-
)?;
1340+
let benchmarks = get_compile_benchmarks(&compile_benchmark_dir(), (&local).into())?;
13241341
for benchmark in benchmarks {
13251342
println!("Stats for benchmark `{}`", benchmark.name);
13261343
println!("{}", "-".repeat(20));
@@ -1713,7 +1730,7 @@ fn bench_published_artifact(
17131730
};
17141731

17151732
// Exclude benchmarks that don't work with a stable compiler.
1716-
let mut compile_benchmarks = get_compile_benchmarks(dirs.compile, &[], &[], &[])?;
1733+
let mut compile_benchmarks = get_compile_benchmarks(dirs.compile, CompileBenchmarkFilter::All)?;
17171734
compile_benchmarks.retain(|b| b.category().is_stable());
17181735

17191736
let runtime_suite = rt.block_on(load_runtime_benchmarks(

collector/src/compile/benchmark/mod.rs

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -466,14 +466,22 @@ pub fn compile_benchmark_dir() -> PathBuf {
466466
PathBuf::from("collector/compile-benchmarks")
467467
}
468468

469+
pub enum CompileBenchmarkFilter<'a> {
470+
All,
471+
/// Select benchmarks exactly matching the given benchmark names.
472+
Exact(&'a [String]),
473+
/// Select benchmarks matching the given prefixes/suffixes.
474+
Fuzzy {
475+
include: &'a [String],
476+
exclude: &'a [String],
477+
exclude_suffix: &'a [String],
478+
},
479+
}
480+
469481
pub fn get_compile_benchmarks(
470482
benchmark_dir: &Path,
471-
include: &[String],
472-
exclude: &[String],
473-
exclude_suffix: &[String],
483+
filter: CompileBenchmarkFilter<'_>,
474484
) -> anyhow::Result<Vec<Benchmark>> {
475-
let mut benchmarks = Vec::new();
476-
477485
let mut paths = Vec::new();
478486
for entry in std::fs::read_dir(benchmark_dir)
479487
.with_context(|| format!("failed to list benchmark dir '{}'", benchmark_dir.display()))?
@@ -493,6 +501,40 @@ pub fn get_compile_benchmarks(
493501
paths.push((path, name));
494502
}
495503

504+
let mut benchmarks = match filter {
505+
CompileBenchmarkFilter::All => paths
506+
.into_iter()
507+
.map(|(path, name)| Ok(Benchmark::new(name, path)?))
508+
.collect::<anyhow::Result<Vec<Benchmark>>>()?,
509+
CompileBenchmarkFilter::Exact(names) => paths
510+
.into_iter()
511+
.filter(|(_, name)| names.contains(name))
512+
.map(|(path, name)| Ok(Benchmark::new(name, path)?))
513+
.collect::<anyhow::Result<Vec<Benchmark>>>()?,
514+
CompileBenchmarkFilter::Fuzzy {
515+
include,
516+
exclude,
517+
exclude_suffix,
518+
} => select_benchmarks_fuzzy(paths, include, exclude, exclude_suffix)?,
519+
};
520+
521+
benchmarks.sort_by_key(|benchmark| benchmark.name.clone());
522+
523+
if benchmarks.is_empty() {
524+
eprintln!("Warning: no benchmarks selected! Try less strict filters.");
525+
}
526+
527+
Ok(benchmarks)
528+
}
529+
530+
fn select_benchmarks_fuzzy(
531+
paths: Vec<(PathBuf, String)>,
532+
include: &[String],
533+
exclude: &[String],
534+
exclude_suffix: &[String],
535+
) -> anyhow::Result<Vec<Benchmark>> {
536+
let mut benchmarks = Vec::new();
537+
496538
// For each --include/--exclude entry, we count how many times it's used,
497539
// to enable `check_for_unused` below.
498540
fn to_hashmap(xyz: &[String]) -> HashMap<&str, usize> {
@@ -551,12 +593,6 @@ Expected zero or more entries or substrings from list: {:?}."#,
551593
check_for_unused("exclude", excludes)?;
552594
check_for_unused("exclude-suffix", exclude_suffixes)?;
553595

554-
benchmarks.sort_by_key(|benchmark| benchmark.name.clone());
555-
556-
if benchmarks.is_empty() {
557-
eprintln!("Warning: no benchmarks selected! Try less strict filters.");
558-
}
559-
560596
Ok(benchmarks)
561597
}
562598

@@ -578,17 +614,19 @@ fn substring_matches(
578614

579615
#[cfg(test)]
580616
mod tests {
581-
use crate::compile::benchmark::get_compile_benchmarks;
617+
use crate::compile::benchmark::{get_compile_benchmarks, CompileBenchmarkFilter};
582618
use std::path::Path;
583619

584620
#[test]
585621
fn check_compile_benchmarks() {
586622
// Check that we can deserialize all perf-config.json files in the compile benchmark
587623
// directory.
588624
let root = env!("CARGO_MANIFEST_DIR");
589-
let benchmarks =
590-
get_compile_benchmarks(&Path::new(root).join("compile-benchmarks"), &[], &[], &[])
591-
.unwrap();
625+
let benchmarks = get_compile_benchmarks(
626+
&Path::new(root).join("compile-benchmarks"),
627+
CompileBenchmarkFilter::All,
628+
)
629+
.unwrap();
592630
assert!(!benchmarks.is_empty());
593631
}
594632
}

0 commit comments

Comments
 (0)