Skip to content

Commit 82244cf

Browse files
committed
feat(cli): add --ignore-failure to allow non-zero exit codes
Adds -i / --ignore-failure on exec and run commands, inspired by hyperfine flag of the same name. When set, a non-zero exit from the benchmarked process is logged as a warning and execution continues, instead of aborting. The gate lives on ExecutorConfig, mirroring allow_empty, and covers both the valgrind and walltime paths. A failure from valgrind itself still aborts - only the wrapped command status is relaxed. Closes #242
1 parent be3c3b2 commit 82244cf

6 files changed

Lines changed: 35 additions & 2 deletions

File tree

src/cli/exec/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ fn build_orchestrator_config(
8585
skip_run: args.shared.skip_run,
8686
skip_setup: args.shared.skip_setup,
8787
allow_empty: args.shared.allow_empty,
88+
ignore_failure: args.shared.ignore_failure,
8889
go_runner_version: args.shared.go_runner_version,
8990
show_full_output: args.shared.show_full_output,
9091
poll_results_options,

src/cli/run/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ impl RunArgs {
6666
skip_run: false,
6767
skip_setup: false,
6868
allow_empty: false,
69+
ignore_failure: false,
6970
go_runner_version: None,
7071
show_full_output: false,
7172
base: None,
@@ -119,6 +120,7 @@ fn build_orchestrator_config(
119120
skip_run: args.shared.skip_run,
120121
skip_setup: args.shared.skip_setup,
121122
allow_empty: args.shared.allow_empty,
123+
ignore_failure: args.shared.ignore_failure,
122124
go_runner_version: args.shared.go_runner_version,
123125
show_full_output: args.shared.show_full_output,
124126
poll_results_options,

src/cli/shared.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ pub struct ExecAndRunSharedArgs {
102102
#[arg(long, default_value = "false", hide = true)]
103103
pub allow_empty: bool,
104104

105+
/// Allow the benchmarked command to exit with a non-zero status code.
106+
///
107+
/// When set, a non-zero exit from the benchmarked process is logged as a
108+
/// warning and measurement continues, instead of aborting. Mirrors
109+
/// hyperfine's `-i / --ignore-failure`.
110+
#[arg(short = 'i', long, default_value = "false")]
111+
pub ignore_failure: bool,
112+
105113
/// The version of the go-runner to use (e.g., 1.2.3, 1.0.0-beta.1)
106114
/// If not specified, the latest version will be installed
107115
#[arg(long, env = "CODSPEED_GO_RUNNER_VERSION", value_parser = parse_version)]

src/executor/config.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ pub struct OrchestratorConfig {
7171
pub skip_setup: bool,
7272
/// If true, allow execution even when no benchmarks are found
7373
pub allow_empty: bool,
74+
/// If true, the benchmarked command is allowed to exit with a non-zero
75+
/// status code; a warning is logged and execution continues.
76+
pub ignore_failure: bool,
7477
/// The version of go-runner to install (if None, installs latest)
7578
pub go_runner_version: Option<Version>,
7679
/// If true, show full executor output instead of a rolling buffer window
@@ -106,6 +109,9 @@ pub struct ExecutorConfig {
106109
pub skip_setup: bool,
107110
/// If true, allow execution even when no benchmarks are found
108111
pub allow_empty: bool,
112+
/// If true, the benchmarked command is allowed to exit with a non-zero
113+
/// status code; a warning is logged and execution continues.
114+
pub ignore_failure: bool,
109115
/// The version of go-runner to install (if None, installs latest)
110116
pub go_runner_version: Option<Version>,
111117
/// Additional environment variables forwarded to executor subprocesses.
@@ -187,6 +193,7 @@ impl OrchestratorConfig {
187193
skip_run: self.skip_run,
188194
skip_setup: self.skip_setup,
189195
allow_empty: self.allow_empty,
196+
ignore_failure: self.ignore_failure,
190197
go_runner_version: self.go_runner_version.clone(),
191198
extra_env: self.extra_env.clone(),
192199
enable_introspection,
@@ -224,6 +231,7 @@ impl OrchestratorConfig {
224231
skip_run: false,
225232
skip_setup: false,
226233
allow_empty: false,
234+
ignore_failure: false,
227235
go_runner_version: None,
228236
show_full_output: false,
229237
poll_results_options: PollResultsOptions::new(false, None),

src/executor/valgrind/measure.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,14 @@ pub async fn measure(
189189
};
190190
debug!("Program exit code = {cmd_status}");
191191
if cmd_status != 0 {
192-
bail!("failed to execute the benchmark process, exit code: {cmd_status}");
192+
if config.ignore_failure {
193+
warn!(
194+
"benchmark process exited with non-zero code {cmd_status}; \
195+
continuing because --ignore-failure was set"
196+
);
197+
} else {
198+
bail!("failed to execute the benchmark process, exit code: {cmd_status}");
199+
}
193200
}
194201

195202
Ok(())

src/executor/wall_time/executor.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,14 @@ impl Executor for WallTimeExecutor {
180180
debug!("cmd exit status: {status:?}");
181181

182182
if !status.success() {
183-
bail!("failed to execute the benchmark process: {status}");
183+
if execution_context.config.ignore_failure {
184+
warn!(
185+
"benchmark process exited with {status}; \
186+
continuing because --ignore-failure was set"
187+
);
188+
} else {
189+
bail!("failed to execute the benchmark process: {status}");
190+
}
184191
}
185192

186193
Ok(())

0 commit comments

Comments
 (0)