Skip to content

Commit 3d405e6

Browse files
committed
feat: add cli args for perf
1 parent 5aa4152 commit 3d405e6

4 files changed

Lines changed: 79 additions & 28 deletions

File tree

src/run/config.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use url::Url;
66
use crate::run::run_environment::RepositoryProvider;
77
use crate::run::RunArgs;
88

9-
use super::RunnerMode;
9+
use super::{RunnerMode, UnwindingMode};
1010

1111
#[derive(Debug)]
1212
pub struct Config {
@@ -18,6 +18,8 @@ pub struct Config {
1818

1919
pub mode: RunnerMode,
2020
pub instruments: Instruments,
21+
pub unwinding_mode: Option<UnwindingMode>,
22+
pub enable_perf: bool,
2123

2224
pub profile_folder: Option<PathBuf>,
2325
pub skip_upload: bool,
@@ -50,6 +52,8 @@ impl Config {
5052
command: "".into(),
5153
mode: RunnerMode::Instrumentation,
5254
instruments: Instruments::test(),
55+
unwinding_mode: None,
56+
enable_perf: false,
5357
profile_folder: None,
5458
skip_upload: false,
5559
skip_run: false,
@@ -86,6 +90,8 @@ impl TryFrom<RunArgs> for Config {
8690
working_directory: args.working_directory,
8791
mode: args.mode,
8892
instruments,
93+
unwinding_mode: args.perf_run_args.unwinding_mode,
94+
enable_perf: args.perf_run_args.enable_perf,
8995
command: args.command.join(" "),
9096
profile_folder: args.profile_folder,
9197
skip_upload: args.skip_upload,
@@ -105,6 +111,7 @@ fn extract_owner_and_repository_from_arg(owner_and_repository: &str) -> Result<(
105111
#[cfg(test)]
106112
mod tests {
107113
use crate::run::instruments::MongoDBConfig;
114+
use crate::run::PerfRunArgs;
108115

109116
use super::*;
110117

@@ -124,6 +131,10 @@ mod tests {
124131
skip_upload: false,
125132
skip_run: false,
126133
skip_setup: false,
134+
perf_run_args: PerfRunArgs {
135+
enable_perf: false,
136+
unwinding_mode: None,
137+
},
127138
command: vec!["cargo".into(), "codspeed".into(), "bench".into()],
128139
})
129140
.unwrap();
@@ -154,6 +165,10 @@ mod tests {
154165
skip_upload: true,
155166
skip_run: true,
156167
skip_setup: true,
168+
perf_run_args: PerfRunArgs {
169+
enable_perf: false,
170+
unwinding_mode: Some(UnwindingMode::FramePointer),
171+
},
157172
command: vec!["cargo".into(), "codspeed".into(), "bench".into()],
158173
})
159174
.unwrap();

src/run/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,29 @@ fn show_banner() {
3838
debug!("codspeed v{}", VERSION);
3939
}
4040

41+
#[derive(Debug, Copy, Clone, PartialEq, ValueEnum, Default)]
42+
pub enum UnwindingMode {
43+
/// Use the frame pointer for unwinding. Requires the binary to be compiled with frame pointers enabled.
44+
#[clap(name = "fp")]
45+
FramePointer,
46+
47+
/// Use DWARF unwinding. This does not require any special compilation flags and is enabled by default.
48+
#[default]
49+
Dwarf,
50+
}
51+
52+
#[derive(Args, Debug, Clone)]
53+
pub struct PerfRunArgs {
54+
/// Enable the performance runner, which uses `perf` to collect performance data.
55+
/// This is only supported on Linux.
56+
#[arg(long, env = "CODSPEED_PERF_ENABLED", default_value_t = false)]
57+
enable_perf: bool,
58+
59+
/// The unwinding mode that should be used with perf to collect the call stack.
60+
#[arg(long, env = "CODSPEED_PERF_UNWINDING_MODE")]
61+
unwinding_mode: Option<UnwindingMode>,
62+
}
63+
4164
#[derive(Args, Debug)]
4265
pub struct RunArgs {
4366
/// The upload URL to use for uploading the results, useful for on-premises installations
@@ -104,6 +127,9 @@ pub struct RunArgs {
104127
#[arg(long, default_value = "false", hide = true)]
105128
pub skip_setup: bool,
106129

130+
#[command(flatten)]
131+
pub perf_run_args: PerfRunArgs,
132+
107133
/// The bench command to run
108134
pub command: Vec<String>,
109135
}
@@ -139,6 +165,10 @@ impl RunArgs {
139165
skip_upload: false,
140166
skip_run: false,
141167
skip_setup: false,
168+
perf_run_args: PerfRunArgs {
169+
enable_perf: false,
170+
unwinding_mode: None,
171+
},
142172
command: vec![],
143173
}
144174
}

src/run/runner/wall_time/executor.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,8 @@ pub struct WallTimeExecutor {
1717

1818
impl WallTimeExecutor {
1919
pub fn new() -> Self {
20-
let use_perf = if cfg!(target_os = "linux") {
21-
std::env::var("CODSPEED_USE_PERF").is_ok()
22-
} else {
23-
false
24-
};
25-
debug!("Running the cmd with perf: {}", use_perf);
26-
2720
Self {
28-
perf: use_perf.then(PerfRunner::new),
21+
perf: cfg!(target_os = "linux").then(PerfRunner::new),
2922
}
3023
}
3124
}
@@ -66,13 +59,14 @@ impl Executor for WallTimeExecutor {
6659
}
6760

6861
let bench_cmd = get_bench_command(config)?;
69-
let status = if let Some(perf) = &self.perf {
70-
perf.run(cmd, &bench_cmd).await
71-
} else {
72-
cmd.args(["-c", &bench_cmd]);
73-
debug!("cmd: {:?}", cmd);
74-
75-
run_command_with_log_pipe(cmd).await
62+
let status = match (config.enable_perf, &self.perf) {
63+
(true, Some(perf)) => perf.run(cmd, &bench_cmd, config).await,
64+
_ => {
65+
cmd.args(["-c", &bench_cmd]);
66+
debug!("cmd: {:?}", cmd);
67+
68+
run_command_with_log_pipe(cmd).await
69+
}
7670
};
7771

7872
let status =

src/run/runner/wall_time/perf/mod.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#![cfg_attr(not(unix), allow(dead_code, unused_mut))]
22

33
use crate::prelude::*;
4+
use crate::run::config::Config;
45
use crate::run::runner::helpers::run_command_with_log_pipe::run_command_with_log_pipe_and_callback;
56
use crate::run::runner::helpers::setup::run_with_sudo;
67
use crate::run::runner::valgrind::helpers::ignored_objects_path::get_objects_path_to_ignore;
78
use crate::run::runner::valgrind::helpers::perf_maps::harvest_perf_maps_for_pids;
9+
use crate::run::UnwindingMode;
810
use anyhow::Context;
911
use fifo::{PerfFifo, RunnerFifo};
1012
use futures::stream::FuturesUnordered;
@@ -72,7 +74,12 @@ impl PerfRunner {
7274
}
7375
}
7476

75-
pub async fn run(&self, mut cmd: Command, bench_cmd: &str) -> anyhow::Result<ExitStatus> {
77+
pub async fn run(
78+
&self,
79+
mut cmd: Command,
80+
bench_cmd: &str,
81+
config: &Config,
82+
) -> anyhow::Result<ExitStatus> {
7683
let perf_fifo = PerfFifo::new()?;
7784
let runner_fifo = RunnerFifo::new()?;
7885

@@ -83,18 +90,23 @@ impl PerfRunner {
8390
.prefix(PERF_DATA_PREFIX)
8491
.tempfile_in(&self.perf_dir)?;
8592

86-
// Detect the mode based on the command to be executed
87-
let cg_mode = if bench_cmd.contains("cargo") {
88-
"dwarf"
89-
} else if bench_cmd.contains("pytest") {
90-
"fp"
91-
} else {
92-
panic!(
93-
"Perf not supported. Failed to detect call graph mode for command: {}",
94-
bench_cmd
95-
)
93+
// Infer the unwinding mode from the benchmark cmd
94+
let cg_mode = match (config.unwinding_mode, &bench_cmd) {
95+
(Some(mode), _) => mode,
96+
(None, cmd) if cmd.contains("pytest") => UnwindingMode::FramePointer,
97+
(None, cmd) if cmd.contains("cargo") => UnwindingMode::Dwarf,
98+
(None, _) => {
99+
// Default to dwarf unwinding since it works well with most binaries.
100+
debug!("No call graph mode detected, defaulting to dwarf");
101+
UnwindingMode::Dwarf
102+
}
103+
};
104+
105+
let cg_mode = match cg_mode {
106+
UnwindingMode::FramePointer => "fp",
107+
UnwindingMode::Dwarf => "dwarf",
96108
};
97-
debug!("Using call graph mode: {}", cg_mode);
109+
debug!("Using call graph mode: {:?}", cg_mode);
98110

99111
let quiet_flag = {
100112
let log_level = std::env::var("CODSPEED_LOG")

0 commit comments

Comments
 (0)