Skip to content

Commit 87c44b0

Browse files
feat(divan): add benchmark filtering in instrumentation mode
1 parent fed8355 commit 87c44b0

File tree

6 files changed

+116
-26
lines changed

6 files changed

+116
-26
lines changed

Cargo.lock

Lines changed: 28 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cargo-codspeed/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ repository = "https://github.com/CodSpeedHQ/codspeed-rust"
1111
homepage = "https://codspeed.io"
1212
license = "MIT OR Apache-2.0"
1313
categories = [
14-
"development-tools",
15-
"development-tools::cargo-plugins",
16-
"development-tools::profiling",
17-
"development-tools::testing",
14+
"development-tools",
15+
"development-tools::cargo-plugins",
16+
"development-tools::profiling",
17+
"development-tools::testing",
1818
]
1919
keywords = ["codspeed", "benchmark", "cargo"]
2020

2121
[dependencies]
2222
cargo_metadata = "0.19.2"
23-
clap = { version = "=4.5.17", features = ["derive", "env"] }
23+
clap = { version = ">=4.5.17", features = ["derive", "env"] }
2424
termcolor = "1.4"
2525
anyhow = { workspace = true }
2626
itertools = { workspace = true }

crates/divan_compat/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ keywords = ["codspeed", "benchmark", "divan"]
2121
codspeed = { path = "../codspeed", version = "=3.0.5" }
2222
divan = { package = "codspeed-divan-compat-walltime", path = "./divan_fork", version = "=3.0.5" }
2323
codspeed-divan-compat-macros = { version = "=3.0.5", path = './macros' }
24+
regex = "1.11.3"
25+
clap = "4.5.48"
2426

2527
[[bench]]
2628
name = "basic_example"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use clap::{Arg, ArgAction, Command};
2+
3+
pub(crate) fn command() -> Command {
4+
fn option(name: &'static str) -> Arg {
5+
Arg::new(name).long(name)
6+
}
7+
8+
fn flag(name: &'static str) -> Arg {
9+
option(name).action(ArgAction::SetTrue)
10+
}
11+
12+
Command::new("divan")
13+
.arg(
14+
Arg::new("filter")
15+
.value_name("FILTER")
16+
.help("Only run benchmarks whose names match this pattern")
17+
.action(ArgAction::Append),
18+
)
19+
.arg(flag("exact").help("Filter benchmarks by exact name rather than by pattern"))
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use regex::Regex;
2+
3+
/// Filters which benchmark to run based on name.
4+
pub(crate) enum Filter {
5+
Regex(Regex),
6+
Exact(String),
7+
}
8+
9+
impl Filter {
10+
/// Returns `true` if a string matches this filter.
11+
pub fn is_match(&self, s: &str) -> bool {
12+
match self {
13+
Self::Regex(r) => r.is_match(s),
14+
Self::Exact(e) => e == s,
15+
}
16+
}
17+
}

crates/divan_compat/src/compat/mod.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,18 @@ pub mod __private {
1313
}
1414

1515
mod bench;
16+
mod cli;
17+
mod config;
1618
mod entry;
1719
mod uri;
1820
mod util;
1921

20-
use std::{cell::RefCell, rc::Rc};
21-
2222
pub use bench::*;
2323
use codspeed::codspeed::CodSpeed;
24+
use config::Filter;
2425
use entry::AnyBenchEntry;
26+
use regex::Regex;
27+
use std::{cell::RefCell, rc::Rc};
2528

2629
pub fn main() {
2730
// Outlined steps of original divan::main and their equivalent in codspeed instrumented mode
@@ -46,8 +49,37 @@ pub fn main() {
4649
// codspeed URI from entry metadata directly.
4750

4851
// 3. Filtering
49-
// We do not support finer filtering that bench targets for now, do nothing here, bench
50-
// filtering is managed by the `cargo-codspeed` wrappers before we reach this point.
52+
let should_run_benchmark_from_filters = {
53+
let mut command = cli::command();
54+
let matches = command.get_matches_mut();
55+
let is_exact = matches.get_flag("exact");
56+
57+
let parse_filter = |filter: &String| {
58+
if is_exact {
59+
Filter::Exact(filter.to_owned())
60+
} else {
61+
match Regex::new(filter) {
62+
Ok(r) => Filter::Regex(r),
63+
Err(error) => {
64+
let kind = clap::error::ErrorKind::ValueValidation;
65+
command.error(kind, error).exit();
66+
}
67+
}
68+
}
69+
};
70+
71+
let filters: Option<Vec<Filter>> = matches
72+
.get_many::<String>("filter")
73+
.map(|arg_filters| arg_filters.map(parse_filter).collect());
74+
75+
move |uri: &str| {
76+
if let Some(filters) = filters.as_ref() {
77+
filters.iter().any(|filter| filter.is_match(uri))
78+
} else {
79+
true
80+
}
81+
}
82+
};
5183

5284
// 4. Scan the tree and execute benchmarks
5385
let codspeed = Rc::new(RefCell::new(CodSpeed::new()));
@@ -66,6 +98,10 @@ pub fn main() {
6698
entry::BenchEntryRunner::Plain(bench_fn) => {
6799
let uri = uri::generate(&entry, entry.display_name());
68100

101+
if !should_run_benchmark_from_filters(&uri) {
102+
continue;
103+
}
104+
69105
bench_fn(bench::Bencher::new(&codspeed, uri));
70106
}
71107
entry::BenchEntryRunner::Args(bench_runner) => {
@@ -74,6 +110,10 @@ pub fn main() {
74110
for (arg_index, arg_name) in bench_runner.arg_names().iter().enumerate() {
75111
let uri = uri::generate(&entry, arg_name);
76112

113+
if !should_run_benchmark_from_filters(&uri) {
114+
continue;
115+
}
116+
77117
let bencher = bench::Bencher::new(&codspeed, uri);
78118

79119
bench_runner.bench(bencher, arg_index);

0 commit comments

Comments
 (0)