Skip to content

Commit 697b351

Browse files
fix(exec-harness): improve simulation script support and detect subprocesses
1 parent bc0a847 commit 697b351

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

crates/exec-harness/preload/codspeed_preload.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
//
88
// Environment variables:
99
// CODSPEED_BENCH_URI - The benchmark URI to report (required)
10-
// CODSPEED_PRELOAD_LOCK - Set by the first process to prevent child processes
11-
// from re-initializing instrumentation
1210

1311
#include <stdlib.h>
1412
#include <unistd.h>
@@ -22,8 +20,6 @@
2220
#define RUNNING_ON_VALGRIND 0
2321
#endif
2422

25-
static const char *LOCK_ENV = "CODSPEED_PRELOAD_LOCK";
26-
2723
// These constants are defined by the build script (build.rs) via -D flags
2824
#ifndef CODSPEED_URI_ENV
2925
#error "CODSPEED_URI_ENV must be defined by the build system"
@@ -54,14 +50,6 @@ __attribute__((constructor)) static void codspeed_preload_init(void) {
5450
return;
5551
}
5652

57-
// Check if another process already owns the instrumentation
58-
if (getenv(LOCK_ENV)) {
59-
return;
60-
}
61-
62-
// Set the lock to prevent child processes from initializing
63-
setenv(LOCK_ENV, "1", 1);
64-
6553
g_bench_uri = getenv(URI_ENV);
6654
if (!g_bench_uri) {
6755
return;

crates/exec-harness/src/analysis/mod.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::BenchmarkCommand;
66
use crate::constants;
77
use crate::uri;
88
use instrument_hooks_bindings::InstrumentHooks;
9+
use std::path::PathBuf;
910
use std::process::Command;
1011

1112
mod ld_preload_check;
@@ -57,7 +58,11 @@ pub fn perform_with_valgrind(commands: Vec<BenchmarkCommand>) -> Result<()> {
5758
cmd.env("PYTHONPERFSUPPORT", "1");
5859
cmd.env(constants::URI_ENV, &name_and_uri.uri);
5960

60-
let status = cmd.status().context("Failed to execute command")?;
61+
let mut child = cmd.spawn().context("Failed to spawn command")?;
62+
63+
let status = child.wait().context("Failed to execute command")?;
64+
65+
bail_if_command_spawned_subprocesses_under_valgrind(child.id())?;
6166

6267
if !status.success() {
6368
bail!("Command exited with non-zero status: {status}");
@@ -66,3 +71,35 @@ pub fn perform_with_valgrind(commands: Vec<BenchmarkCommand>) -> Result<()> {
6671

6772
Ok(())
6873
}
74+
75+
fn bail_if_command_spawned_subprocesses_under_valgrind(pid: u32) -> Result<()> {
76+
let Some(profile_folder) = std::env::var_os("CODSPEED_PROFILE_FOLDER") else {
77+
debug!("CODSPEED_PROFILE_FOLDER is not set, skipping subprocess detection");
78+
return Ok(());
79+
};
80+
81+
let profile_folder = PathBuf::from(profile_folder);
82+
83+
// Bail if any <pid>.out where <pid> > pid of the benchmark process exists in the profile
84+
// folder, which indicates that the benchmark process spawned subprocesses.
85+
for entry in std::fs::read_dir(profile_folder)? {
86+
let entry = entry?;
87+
let file_name = entry.file_name();
88+
let file_name = file_name.to_string_lossy();
89+
90+
if let Some(stripped) = file_name.strip_suffix(".out") {
91+
if let Ok(subprocess_pid) = stripped.parse::<u32>() {
92+
if subprocess_pid > pid {
93+
bail!(
94+
"The codspeed CLI in CPU Simulation mode does not support measuring processes that spawn other processes yet.\n\n\
95+
Please either:\n\
96+
- Use the walltime measurement mode, or\n\
97+
- Benchmark a process that does not create subprocesses"
98+
)
99+
}
100+
}
101+
}
102+
}
103+
104+
Ok(())
105+
}

0 commit comments

Comments
 (0)