Skip to content

Commit f46d4db

Browse files
authored
Merge pull request #1279 from nnethercote/include-exclude-prefix-matching
Make `--include` and `--exclude` use exact matching.
2 parents 2624092 + d58a840 commit f46d4db

File tree

2 files changed

+53
-38
lines changed

2 files changed

+53
-38
lines changed

collector/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,15 @@ The following options alter the behaviour of the `bench_local` subcommand.
109109
supports postgres as a backend and the URL can be specified (beginning with
110110
`postgres://`), but this is unlikely to be useful for local collection.
111111
- `--exclude <EXCLUDE>`: this is used to run a subset of the benchmarks. The
112-
argument is a comma-separated list of benchmark names. When this option is
113-
specified, a benchmark is excluded from the run if its name matches one or
114-
more of the given names.
112+
argument is a comma-separated list of benchmark prefixes. When this option is
113+
specified, a benchmark is excluded from the run if its name matches one of
114+
the given prefixes.
115115
- `--id <ID>` the identifier that will be used to identify the results in the
116116
database.
117117
- `--include <INCLUDE>`: the inverse of `--exclude`. The argument is a
118-
comma-separated list of benchmark names. When this option is specified, a
119-
benchmark is included in the run only if its name matches one or more of the
120-
given names.
118+
comma-separated list of benchmark prefixes. When this option is specified, a
119+
benchmark is included in the run only if its name matches one of the given
120+
prefixes.
121121
- `--profiles <PROFILES>`: the profiles to be benchmarked. The possible choices
122122
are one or more (comma-separated) of `Check`, `Debug`, `Doc`, `Opt`, and
123123
`All`. The default is `Check,Debug,Opt`.

collector/src/main.rs

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use clap::Parser;
55
use collector::category::Category;
66
use database::{ArtifactId, Commit};
77
use log::debug;
8-
use std::collections::HashSet;
8+
use std::collections::HashMap;
99
use std::fs;
1010
use std::fs::File;
1111
use std::io::BufWriter;
@@ -331,26 +331,37 @@ fn get_benchmarks(
331331
paths.push((path, name));
332332
}
333333

334-
let mut includes = include.map(|list| list.split(',').collect::<HashSet<&str>>());
335-
let mut excludes = exclude.map(|list| list.split(',').collect::<HashSet<&str>>());
334+
// For each --include/--exclude entry, we count how many times it's used,
335+
// to enable `check_for_unused` below.
336+
fn to_hashmap(xyz: Option<&str>) -> Option<HashMap<&str, usize>> {
337+
xyz.map(|list| {
338+
list.split(',')
339+
.map(|x| (x, 0))
340+
.collect::<HashMap<&str, usize>>()
341+
})
342+
}
343+
344+
let mut includes = to_hashmap(include);
345+
let mut excludes = to_hashmap(exclude);
336346

337347
for (path, name) in paths {
338348
let mut skip = false;
339-
if let Some(includes) = includes.as_mut() {
340-
if !includes.remove(name.as_str()) {
341-
debug!(
342-
"benchmark {} - not named by --include argument, skipping",
343-
name
344-
);
345-
skip = true;
349+
350+
let name_matches = |prefixes: &mut HashMap<&str, usize>| {
351+
for (prefix, n) in prefixes.iter_mut() {
352+
if name.as_str().starts_with(prefix) {
353+
*n += 1;
354+
return true;
355+
}
346356
}
347-
}
357+
false
358+
};
348359

360+
if let Some(includes) = includes.as_mut() {
361+
skip |= !name_matches(includes);
362+
}
349363
if let Some(excludes) = excludes.as_mut() {
350-
if excludes.remove(name.as_str()) {
351-
debug!("benchmark {} - named by --exclude argument, skipping", name);
352-
skip = true;
353-
}
364+
skip |= name_matches(excludes);
354365
}
355366
if skip {
356367
continue;
@@ -360,22 +371,26 @@ fn get_benchmarks(
360371
benchmarks.push(Benchmark::new(name, path)?);
361372
}
362373

363-
if let Some(includes) = includes {
364-
if !includes.is_empty() {
365-
bail!(
366-
"Warning: one or more invalid --include entries: {:?}",
367-
includes
368-
);
369-
}
370-
}
371-
if let Some(excludes) = excludes {
372-
if !excludes.is_empty() {
373-
bail!(
374-
"Warning: one or more invalid --exclude entries: {:?}",
375-
excludes
376-
);
374+
// All prefixes must be used at least once. This is to catch typos.
375+
let check_for_unused = |option, prefixes: Option<HashMap<&str, usize>>| {
376+
if let Some(prefixes) = prefixes {
377+
let unused: Vec<_> = prefixes
378+
.into_iter()
379+
.filter_map(|(i, n)| if n == 0 { Some(i) } else { None })
380+
.collect();
381+
if !unused.is_empty() {
382+
bail!(
383+
"Warning: one or more unused --{} entries: {:?}",
384+
option,
385+
unused
386+
);
387+
}
377388
}
378-
}
389+
Ok(())
390+
};
391+
392+
check_for_unused("include", includes)?;
393+
check_for_unused("exclude", excludes)?;
379394

380395
benchmarks.sort_by_key(|benchmark| benchmark.name.clone());
381396

@@ -729,11 +744,11 @@ struct LocalOptions {
729744
#[clap(long, parse(from_os_str))]
730745
cargo: Option<PathBuf>,
731746

732-
/// Exclude all benchmarks in this comma-separated list
747+
/// Exclude all benchmarks matching a prefix in this comma-separated list
733748
#[clap(long)]
734749
exclude: Option<String>,
735750

736-
/// Include only benchmarks in this comma-separated list
751+
/// Include only benchmarks matching a prefix in this comma-separated list
737752
#[clap(long)]
738753
include: Option<String>,
739754

0 commit comments

Comments
 (0)