Skip to content

Commit 43a2ff0

Browse files
feat(cargo-codspeed): add support for --bench target selection
1 parent e0fe030 commit 43a2ff0

File tree

6 files changed

+145
-45
lines changed

6 files changed

+145
-45
lines changed

crates/cargo-codspeed/src/app.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use cargo_metadata::MetadataCommand;
33
use clap::{Args, Parser, Subcommand};
44
use std::{ffi::OsString, process::exit};
55

6-
use crate::build::build_benches;
6+
use crate::build::{build_benches, BuildConfig};
77

88
#[derive(Parser)]
99
#[command(author, version, about, long_about = None)]
@@ -35,8 +35,16 @@ pub(crate) struct PackageFilters {
3535
pub(crate) package: Vec<String>,
3636
}
3737

38+
#[derive(Args)]
39+
pub(crate) struct BenchTargetFilters {
40+
/// Select only the specified benchmark target (all benchmark targets by default)
41+
#[arg(long, help_heading = TARGET_HELP)]
42+
pub(crate) bench: Option<Vec<String>>,
43+
}
44+
3845
const FEATURE_HELP: &str = "Feature Selection";
3946
const COMPILATION_HELP: &str = "Compilation Options";
47+
const TARGET_HELP: &str = "Target Selection";
4048
#[derive(Subcommand)]
4149
enum Commands {
4250
/// Build the benchmarks
@@ -63,13 +71,20 @@ enum Commands {
6371
/// Build the benchmarks with the specified profile
6472
#[arg(long, default_value = "bench", help_heading = COMPILATION_HELP)]
6573
profile: String,
74+
75+
#[command(flatten)]
76+
bench_target_filters: BenchTargetFilters,
6677
},
6778
/// Run the previously built benchmarks
6879
Run {
6980
/// If specified, only run benches containing this string in their names
70-
bench_name: Option<String>,
81+
benchname: Option<String>,
82+
7183
#[command(flatten)]
7284
package_filters: PackageFilters,
85+
86+
#[command(flatten)]
87+
bench_target_filters: BenchTargetFilters,
7388
},
7489
}
7590

@@ -83,6 +98,7 @@ pub fn run(args: impl Iterator<Item = OsString>) -> Result<()> {
8398
let res = match cli.command {
8499
Commands::Build {
85100
package_filters,
101+
bench_target_filters,
86102
features,
87103
all_features,
88104
jobs,
@@ -110,18 +126,28 @@ pub fn run(args: impl Iterator<Item = OsString>) -> Result<()> {
110126
features.map(|f| f.split([' ', ',']).map(|s| s.to_string()).collect_vec());
111127
build_benches(
112128
&metadata,
113-
package_filters,
114-
features,
115-
profile,
116-
cli.quiet,
117-
measurement_mode,
118-
passthrough_flags,
129+
BuildConfig {
130+
package_filters,
131+
bench_target_filters,
132+
features,
133+
profile,
134+
quiet: cli.quiet,
135+
measurement_mode,
136+
passthrough_flags,
137+
},
119138
)
120139
}
121140
Commands::Run {
122-
bench_name,
141+
benchname,
142+
package_filters,
143+
bench_target_filters,
144+
} => run_benches(
145+
&metadata,
146+
benchname,
123147
package_filters,
124-
} => run_benches(&metadata, bench_name, package_filters, measurement_mode),
148+
bench_target_filters,
149+
measurement_mode,
150+
),
125151
};
126152

127153
if let Err(e) = res {

crates/cargo-codspeed/src/build.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
app::PackageFilters,
2+
app::{BenchTargetFilters, PackageFilters},
33
helpers::{clear_dir, get_codspeed_target_dir},
44
measurement_mode::MeasurementMode,
55
prelude::*,
@@ -8,6 +8,7 @@ use cargo_metadata::{camino::Utf8PathBuf, Message, Metadata, TargetKind};
88
use std::process::{exit, Command, Stdio};
99

1010
struct BuildOptions<'a> {
11+
bench_target_filters: BenchTargetFilters,
1112
package_filters: PackageFilters,
1213
features: &'a Option<Vec<String>>,
1314
profile: &'a str,
@@ -20,6 +21,16 @@ struct BuiltBench {
2021
executable_path: Utf8PathBuf,
2122
}
2223

24+
pub struct BuildConfig {
25+
pub package_filters: PackageFilters,
26+
pub bench_target_filters: BenchTargetFilters,
27+
pub features: Option<Vec<String>>,
28+
pub profile: String,
29+
pub quiet: bool,
30+
pub measurement_mode: MeasurementMode,
31+
pub passthrough_flags: Vec<String>,
32+
}
33+
2334
impl BuildOptions<'_> {
2435
/// Builds the benchmarks by invoking cargo
2536
/// Returns a list of built benchmarks, with path to associated executables
@@ -167,7 +178,15 @@ impl BuildOptions<'_> {
167178
/// This command explicitly ignores the `self.benches`: all benches are built
168179
fn build_command(&self, measurement_mode: MeasurementMode) -> Command {
169180
let mut cargo = Command::new("cargo");
170-
cargo.args(["build", "--benches"]);
181+
cargo.arg("build");
182+
183+
if let Some(bench_target_filters) = &self.bench_target_filters.bench {
184+
for bench_target_filter in bench_target_filters {
185+
cargo.args(["--bench", bench_target_filter]);
186+
}
187+
} else {
188+
cargo.args(["--benches"]);
189+
}
171190

172191
self.add_rust_flags(&mut cargo, measurement_mode);
173192

@@ -205,22 +224,15 @@ impl PackageFilters {
205224
}
206225
}
207226

208-
pub fn build_benches(
209-
metadata: &Metadata,
210-
package_filters: PackageFilters,
211-
features: Option<Vec<String>>,
212-
profile: String,
213-
quiet: bool,
214-
measurement_mode: MeasurementMode,
215-
passthrough_flags: Vec<String>,
216-
) -> Result<()> {
227+
pub fn build_benches(metadata: &Metadata, config: BuildConfig) -> Result<()> {
217228
let built_benches = BuildOptions {
218-
package_filters,
219-
features: &features,
220-
profile: &profile,
221-
passthrough_flags: &passthrough_flags,
229+
bench_target_filters: config.bench_target_filters,
230+
package_filters: config.package_filters,
231+
features: &config.features,
232+
profile: &config.profile,
233+
passthrough_flags: &config.passthrough_flags,
222234
}
223-
.build(metadata, quiet, measurement_mode)?;
235+
.build(metadata, config.quiet, config.measurement_mode)?;
224236

225237
if built_benches.is_empty() {
226238
bail!(
@@ -229,7 +241,7 @@ pub fn build_benches(
229241
);
230242
}
231243

232-
let codspeed_target_dir = get_codspeed_target_dir(metadata, measurement_mode);
244+
let codspeed_target_dir = get_codspeed_target_dir(metadata, config.measurement_mode);
233245
let built_bench_count = built_benches.len();
234246

235247
// Create and clear packages codspeed target directories

crates/cargo-codspeed/src/run.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::{
2-
app::PackageFilters, helpers::get_codspeed_target_dir, measurement_mode::MeasurementMode,
2+
app::{BenchTargetFilters, PackageFilters},
3+
helpers::get_codspeed_target_dir,
4+
measurement_mode::MeasurementMode,
35
prelude::*,
46
};
57
use anyhow::Context;
@@ -15,7 +17,7 @@ use std::os::unix::process::ExitStatusExt;
1517

1618
struct BenchToRun {
1719
bench_path: PathBuf,
18-
bench_name: String,
20+
bench_target_name: String,
1921
working_directory: PathBuf,
2022
package_name: String,
2123
}
@@ -47,8 +49,9 @@ impl PackageFilters {
4749

4850
fn benches_to_run(
4951
&self,
50-
codspeed_target_dir: PathBuf,
5152
metadata: &Metadata,
53+
bench_target_filters: BenchTargetFilters,
54+
codspeed_target_dir: PathBuf,
5255
) -> Result<Vec<BenchToRun>> {
5356
let packages = self.packages_from_flags(metadata)?;
5457

@@ -63,18 +66,23 @@ impl PackageFilters {
6366
for entry in read_dir {
6467
let entry = entry?;
6568
let bench_path = entry.path();
66-
let bench_name = bench_path
69+
let bench_target_name = bench_path
6770
.file_name()
6871
.unwrap()
6972
.to_str()
7073
.unwrap()
7174
.to_string();
75+
if let Some(bench_target_filter) = &bench_target_filters.bench {
76+
if !bench_target_filter.contains(&bench_target_name) {
77+
continue;
78+
}
79+
}
7280
if !bench_path.is_dir() {
7381
benches.push(BenchToRun {
7482
package_name: package_name.clone(),
7583
working_directory: working_directory.into(),
7684
bench_path,
77-
bench_name,
85+
bench_target_name,
7886
});
7987
}
8088
}
@@ -89,26 +97,28 @@ pub fn run_benches(
8997
metadata: &Metadata,
9098
bench_name_filter: Option<String>,
9199
package_filters: PackageFilters,
100+
bench_target_filters: BenchTargetFilters,
92101
measurement_mode: MeasurementMode,
93102
) -> Result<()> {
94103
let codspeed_target_dir = get_codspeed_target_dir(metadata, measurement_mode);
95104
let workspace_root = metadata.workspace_root.as_std_path();
96105
if measurement_mode == MeasurementMode::Walltime {
97106
WalltimeResults::clear(workspace_root)?;
98107
}
99-
let benches = package_filters.benches_to_run(codspeed_target_dir, metadata)?;
108+
let benches =
109+
package_filters.benches_to_run(metadata, bench_target_filters, codspeed_target_dir)?;
100110
if benches.is_empty() {
101111
bail!("No benchmarks found. Run `cargo codspeed build` first.");
102112
}
103113

104114
eprintln!("Collected {} benchmark suite(s) to run", benches.len());
105115

106116
for bench in benches.iter() {
107-
let bench_name = &bench.bench_name;
117+
let bench_target_name = &bench.bench_target_name;
108118
// workspace_root is needed since file! returns the path relatively to the workspace root
109119
// while CARGO_MANIFEST_DIR returns the path to the sub package
110120
let workspace_root = metadata.workspace_root.clone();
111-
eprintln!("Running {} {}", &bench.package_name, bench_name);
121+
eprintln!("Running {} {}", &bench.package_name, bench_target_name);
112122
let mut command = std::process::Command::new(&bench.bench_path);
113123
command
114124
.env("CODSPEED_CARGO_WORKSPACE_ROOT", workspace_root)
@@ -146,7 +156,7 @@ pub fn run_benches(
146156
}
147157
}
148158
})?;
149-
eprintln!("Done running {bench_name}");
159+
eprintln!("Done running {bench_target_name}");
150160
}
151161
eprintln!("Finished running {} benchmark suite(s)", benches.len());
152162

crates/cargo-codspeed/tests/simple-bencher.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn test_simple_build_single() {
4545
let dir = setup(DIR, Project::Simple);
4646
cargo_codspeed(&dir)
4747
.arg("build")
48-
.arg("another_bencher_example")
48+
.args(["--bench", "another_bencher_example"])
4949
.assert()
5050
.success()
5151
.stderr(contains("Built 1 benchmark suite(s)"))
@@ -58,12 +58,12 @@ fn test_simple_build_and_run_single() {
5858
let dir = setup(DIR, Project::Simple);
5959
cargo_codspeed(&dir)
6060
.arg("build")
61-
.arg("another_bencher_example")
61+
.args(["--bench", "another_bencher_example"])
6262
.assert()
6363
.success();
6464
cargo_codspeed(&dir)
6565
.arg("run")
66-
.arg("another_bencher_example")
66+
.args(["--bench", "another_bencher_example"])
6767
.assert()
6868
.success()
6969
.stderr(contains("Finished running 1 benchmark suite(s)"))

crates/cargo-codspeed/tests/simple-criterion.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn test_criterion_build_single() {
4545
let dir = setup(DIR, Project::Simple);
4646
cargo_codspeed(&dir)
4747
.arg("build")
48-
.arg("another_criterion_example")
48+
.args(["--bench", "another_criterion_example"])
4949
.assert()
5050
.success()
5151
.stderr(contains("Built 1 benchmark suite(s)"))
@@ -58,19 +58,45 @@ fn test_criterion_build_and_run_single() {
5858
let dir = setup(DIR, Project::Simple);
5959
cargo_codspeed(&dir)
6060
.arg("build")
61-
.arg("another_criterion_example")
61+
.args(["--bench", "another_criterion_example"])
6262
.assert()
6363
.success();
6464
cargo_codspeed(&dir)
6565
.arg("run")
66-
.arg("another_criterion_example")
66+
.args(["--bench", "another_criterion_example"])
6767
.assert()
6868
.success()
6969
.stderr(contains("Finished running 1 benchmark suite(s)"))
7070
.stderr(contains("another_criterion_example"));
7171
teardown(dir);
7272
}
7373

74+
#[test]
75+
fn test_criterion_build_and_run_filtered_by_name() {
76+
let dir = setup(DIR, Project::Simple);
77+
cargo_codspeed(&dir).arg("build").assert().success();
78+
cargo_codspeed(&dir)
79+
.arg("run")
80+
.arg("fib 20")
81+
.assert()
82+
.success()
83+
.stderr(contains("Finished running 2 benchmark suite(s)"));
84+
teardown(dir);
85+
}
86+
87+
#[test]
88+
fn test_criterion_build_and_run_filtered_by_partial_name() {
89+
let dir = setup(DIR, Project::Simple);
90+
cargo_codspeed(&dir).arg("build").assert().success();
91+
cargo_codspeed(&dir)
92+
.arg("run")
93+
.arg("bubble")
94+
.assert()
95+
.success()
96+
.stderr(contains("Finished running 2 benchmark suite(s)"));
97+
teardown(dir);
98+
}
99+
74100
#[test]
75101
fn test_criterion_cargo_bench_no_run() {
76102
let dir = setup(DIR, Project::Simple);

0 commit comments

Comments
 (0)