Skip to content

Commit 7fc87c3

Browse files
committed
feat(cargo-codspeed): allow build with multiple modes
1 parent a8754dd commit 7fc87c3

File tree

4 files changed

+159
-82
lines changed

4 files changed

+159
-82
lines changed

crates/cargo-codspeed/src/app.rs

Lines changed: 121 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
use crate::{measurement_mode::MeasurementMode, prelude::*, run::run_benches};
1+
use crate::{
2+
measurement_mode::{BuildMode, MeasurementMode},
3+
prelude::*,
4+
run::run_benches,
5+
};
26
use cargo_metadata::MetadataCommand;
3-
use clap::{Args, Parser, Subcommand};
7+
use clap::{ArgAction, Args, Parser, Subcommand};
48
use std::{ffi::OsString, process::exit};
59

610
use crate::build::{build_benches, BuildConfig};
@@ -12,17 +16,107 @@ struct Cli {
1216
#[arg(short, long, global = true)]
1317
quiet: bool,
1418

15-
/// The measurement tool to use for measuring performance.
16-
/// Automatically set to `walltime` on macro runners
17-
#[arg(short, long, global = true, env = "CODSPEED_RUNNER_MODE")]
18-
measurement_mode: Option<MeasurementMode>,
19-
2019
#[command(subcommand)]
2120
command: Commands,
2221
}
2322

23+
impl Cli {
24+
pub fn run(self) -> Result<()> {
25+
let metadata = MetadataCommand::new().exec()?;
26+
match self.command {
27+
Commands::Build {
28+
package_filters,
29+
bench_target_filters,
30+
features,
31+
all_features,
32+
jobs,
33+
no_default_features,
34+
profile,
35+
locked,
36+
offline,
37+
frozen,
38+
measurement_mode,
39+
} => {
40+
let passthrough_flags = {
41+
let mut passthrough_flags = Vec::new();
42+
if all_features {
43+
passthrough_flags.push("--all-features".to_string());
44+
}
45+
if no_default_features {
46+
passthrough_flags.push("--no-default-features".to_string());
47+
}
48+
if locked {
49+
passthrough_flags.push("--locked".to_string());
50+
}
51+
if offline {
52+
passthrough_flags.push("--offline".to_string());
53+
}
54+
if frozen {
55+
passthrough_flags.push("--frozen".to_string());
56+
}
57+
if let Some(jobs) = jobs {
58+
passthrough_flags.push(format!("--jobs={jobs}"));
59+
}
60+
passthrough_flags
61+
};
62+
let features =
63+
features.map(|f| f.split([' ', ',']).map(|s| s.to_string()).collect_vec());
64+
65+
let modes = measurement_mode.iter().map(|m| m.to_string()).join(", ");
66+
eprintln!(
67+
"[cargo-codspeed] Measurement mode{}: {modes}\n",
68+
if measurement_mode.len() > 1 { "s" } else { "" }
69+
);
70+
71+
let build_modes: Vec<BuildMode> = measurement_mode
72+
.into_iter()
73+
.map(BuildMode::from)
74+
.unique()
75+
.collect();
76+
let build_modes = if build_modes.is_empty() {
77+
vec![BuildMode::default()]
78+
} else {
79+
build_modes
80+
};
81+
82+
for build_mode in build_modes {
83+
build_benches(
84+
&metadata,
85+
BuildConfig {
86+
package_filters: package_filters.clone(),
87+
bench_target_filters: bench_target_filters.clone(),
88+
features: features.clone(),
89+
profile: profile.clone(),
90+
quiet: self.quiet,
91+
build_mode,
92+
passthrough_flags: passthrough_flags.clone(),
93+
},
94+
)?;
95+
}
96+
Ok(())
97+
}
98+
Commands::Run {
99+
benchname,
100+
package_filters,
101+
bench_target_filters,
102+
measurement_mode,
103+
} => {
104+
let mode = measurement_mode.unwrap_or_default();
105+
eprintln!("[cargo-codspeed] Measurement mode: {mode:?}\n");
106+
run_benches(
107+
&metadata,
108+
benchname,
109+
package_filters,
110+
bench_target_filters,
111+
mode,
112+
)
113+
}
114+
}
115+
}
116+
}
117+
24118
const PACKAGE_HELP: &str = "Package Selection";
25-
#[derive(Args)]
119+
#[derive(Args, Clone)]
26120
pub(crate) struct PackageFilters {
27121
/// Select all packages in the workspace
28122
#[arg(long, help_heading = PACKAGE_HELP)]
@@ -35,7 +129,7 @@ pub(crate) struct PackageFilters {
35129
pub(crate) package: Vec<String>,
36130
}
37131

38-
#[derive(Args)]
132+
#[derive(Args, Clone)]
39133
pub(crate) struct BenchTargetFilters {
40134
/// Select only the specified benchmark target (all benchmark targets by default)
41135
#[arg(long, help_heading = TARGET_HELP)]
@@ -89,6 +183,18 @@ enum Commands {
89183

90184
#[command(flatten)]
91185
bench_target_filters: BenchTargetFilters,
186+
187+
/// The measurement tool(s) to use for measuring performance.
188+
/// Can be specified multiple times or comma-separated.
189+
#[arg(
190+
short = 'm',
191+
long = "measurement-mode",
192+
value_delimiter = ',',
193+
action = ArgAction::Append,
194+
help_heading = COMPILATION_HELP,
195+
env = "CODSPEED_RUNNER_MODE"
196+
)]
197+
measurement_mode: Vec<MeasurementMode>,
92198
},
93199
/// Run the previously built benchmarks
94200
Run {
@@ -100,80 +206,17 @@ enum Commands {
100206

101207
#[command(flatten)]
102208
bench_target_filters: BenchTargetFilters,
209+
210+
/// The measurement tool to use for measuring performance.
211+
/// Automatically set to `walltime` on macro runners
212+
#[arg(short = 'm', long = "measurement-mode", env = "CODSPEED_RUNNER_MODE")]
213+
measurement_mode: Option<MeasurementMode>,
103214
},
104215
}
105216

106217
pub fn run(args: impl Iterator<Item = OsString>) -> Result<()> {
107-
let metadata = MetadataCommand::new().exec()?;
108218
let cli = Cli::try_parse_from(args)?;
109-
110-
let measurement_mode = cli.measurement_mode.unwrap_or_default();
111-
eprintln!("[cargo-codspeed] Measurement mode: {measurement_mode:?}\n");
112-
113-
let res = match cli.command {
114-
Commands::Build {
115-
package_filters,
116-
bench_target_filters,
117-
features,
118-
all_features,
119-
jobs,
120-
no_default_features,
121-
profile,
122-
locked,
123-
offline,
124-
frozen,
125-
} => {
126-
let passthrough_flags = {
127-
let mut passthrough_flags = Vec::new();
128-
if all_features {
129-
passthrough_flags.push("--all-features".to_string());
130-
}
131-
if no_default_features {
132-
passthrough_flags.push("--no-default-features".to_string());
133-
}
134-
if locked {
135-
passthrough_flags.push("--locked".to_string());
136-
}
137-
if offline {
138-
passthrough_flags.push("--offline".to_string());
139-
}
140-
if frozen {
141-
passthrough_flags.push("--frozen".to_string());
142-
}
143-
if let Some(jobs) = jobs {
144-
passthrough_flags.push(format!("--jobs={jobs}"));
145-
}
146-
passthrough_flags
147-
};
148-
let features =
149-
features.map(|f| f.split([' ', ',']).map(|s| s.to_string()).collect_vec());
150-
build_benches(
151-
&metadata,
152-
BuildConfig {
153-
package_filters,
154-
bench_target_filters,
155-
features,
156-
profile,
157-
quiet: cli.quiet,
158-
measurement_mode,
159-
passthrough_flags,
160-
},
161-
)
162-
}
163-
Commands::Run {
164-
benchname,
165-
package_filters,
166-
bench_target_filters,
167-
} => run_benches(
168-
&metadata,
169-
benchname,
170-
package_filters,
171-
bench_target_filters,
172-
measurement_mode,
173-
),
174-
};
175-
176-
if let Err(e) = res {
219+
if let Err(e) = cli.run() {
177220
eprintln!("Error: {e}");
178221
exit(1);
179222
}

crates/cargo-codspeed/src/build.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
app::{BenchTargetFilters, PackageFilters},
33
helpers::{clear_dir, get_codspeed_target_dir},
4-
measurement_mode::{BuildMode, MeasurementMode},
4+
measurement_mode::BuildMode,
55
prelude::*,
66
};
77
use anyhow::Context;
@@ -23,13 +23,14 @@ struct BuiltBench {
2323
executable_path: Utf8PathBuf,
2424
}
2525

26+
#[derive(Clone)]
2627
pub struct BuildConfig {
2728
pub package_filters: PackageFilters,
2829
pub bench_target_filters: BenchTargetFilters,
2930
pub features: Option<Vec<String>>,
3031
pub profile: String,
3132
pub quiet: bool,
32-
pub measurement_mode: MeasurementMode,
33+
pub build_mode: BuildMode,
3334
pub passthrough_flags: Vec<String>,
3435
}
3536

@@ -301,7 +302,7 @@ impl PackageFilters {
301302
}
302303

303304
pub fn build_benches(metadata: &Metadata, config: BuildConfig) -> Result<()> {
304-
let build_mode = config.measurement_mode.into();
305+
let build_mode = config.build_mode;
305306
let built_benches = BuildOptions {
306307
bench_target_filters: config.bench_target_filters,
307308
package_filters: config.package_filters,

crates/cargo-codspeed/src/measurement_mode.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use clap::ValueEnum;
22
use serde::Serialize;
33
use std::fmt;
44

5-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
66
pub enum BuildMode {
7+
#[default]
78
Analysis,
89
Walltime,
910
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use predicates::str::contains;
2+
3+
mod helpers;
4+
use helpers::*;
5+
6+
const DIR: &str = "tests/simple-criterion.in";
7+
8+
#[test]
9+
fn test_build_multiple_measurement_modes() {
10+
let dir = setup(DIR, Project::Simple);
11+
cargo_codspeed(&dir)
12+
.args(["build", "-m", "simulation", "-m", "walltime"])
13+
.assert()
14+
.success()
15+
.stderr(contains(
16+
"[cargo-codspeed] Measurement modes: simulation, walltime",
17+
));
18+
teardown(dir);
19+
}
20+
21+
#[test]
22+
fn test_build_multiple_measurement_modes_comma_separated() {
23+
let dir = setup(DIR, Project::Simple);
24+
cargo_codspeed(&dir)
25+
.args(["build", "-m", "simulation,walltime"])
26+
.assert()
27+
.success()
28+
.stderr(contains(
29+
"[cargo-codspeed] Measurement modes: simulation, walltime",
30+
));
31+
teardown(dir);
32+
}

0 commit comments

Comments
 (0)