Skip to content

Commit 31e39a0

Browse files
committed
fix(valgrind): use %p in log file path to avoid multi-process overwrite
Each (potentially forked) process now writes to its own valgrind.<pid>.log instead of clobbering a shared log file. On failure, dump these per-process logs via a dump_valgrind_logs helper when debug logging is enabled.
1 parent 82af5a5 commit 31e39a0

1 file changed

Lines changed: 25 additions & 5 deletions

File tree

src/executor/valgrind/measure.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::executor::valgrind::helpers::ignored_objects_path::get_objects_path_t
88
use crate::executor::valgrind::helpers::python::is_free_threaded_python;
99
use crate::instruments::mongo_tracer::MongoTracer;
1010
use crate::prelude::*;
11+
use log::log_enabled;
1112
use std::fs::canonicalize;
1213
use std::io::Write;
1314
use std::os::unix::fs::PermissionsExt;
@@ -85,6 +86,27 @@ echo -n "$status" > "$2"
8586
Ok(script_file.into_temp_path())
8687
}
8788

89+
/// Dumps every per-process `valgrind.<pid>.log` in the folder to help debug a failure.
90+
fn dump_valgrind_logs(profile_folder: &Path) {
91+
if !log_enabled!(log::Level::Debug) {
92+
return;
93+
}
94+
95+
for entry in std::fs::read_dir(profile_folder).into_iter().flatten() {
96+
let Ok(path) = entry.map(|e| e.path()) else {
97+
continue;
98+
};
99+
let name = path
100+
.file_name()
101+
.and_then(|n| n.to_str())
102+
.unwrap_or_default();
103+
if name.starts_with("valgrind.") && name.ends_with(".log") {
104+
let contents = std::fs::read_to_string(&path).unwrap_or_default();
105+
debug!("{}: {contents}", path.display());
106+
}
107+
}
108+
}
109+
88110
pub async fn measure(
89111
config: &ExecutorConfig,
90112
profile_folder: &Path,
@@ -120,7 +142,8 @@ pub async fn measure(
120142
}
121143
// Configure valgrind
122144
let valgrind_args = get_valgrind_args(&config.simulation_tool, config);
123-
let log_path = profile_folder.join("valgrind.log");
145+
// Use the %p placeholder for per-process logs to avoid conflicts.
146+
let log_path = profile_folder.join("valgrind.%p.log");
124147
cmd.arg("valgrind").args(valgrind_args.iter());
125148
if config.simulation_tool == SimulationTool::Callgrind {
126149
cmd.args(
@@ -173,10 +196,7 @@ pub async fn measure(
173196

174197
// Check the valgrind exit code
175198
if !status.success() {
176-
let valgrind_log = profile_folder.join("valgrind.log");
177-
let valgrind_log = std::fs::read_to_string(&valgrind_log).unwrap_or_default();
178-
debug!("valgrind.log: {valgrind_log}");
179-
199+
dump_valgrind_logs(profile_folder);
180200
bail!("failed to execute valgrind");
181201
}
182202

0 commit comments

Comments
 (0)