From d2642669d3338c5918cdfa50634116bf0697c1a8 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Mon, 9 Mar 2026 18:30:42 +0100 Subject: [PATCH 1/4] feat: pass java options benchmark --- src/executor/helpers/env.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/executor/helpers/env.rs b/src/executor/helpers/env.rs index 07283b43..5204e1d9 100644 --- a/src/executor/helpers/env.rs +++ b/src/executor/helpers/env.rs @@ -29,6 +29,19 @@ pub fn get_base_injected_env( "0".into() }, ), + // Java: Enable frame pointers and perf map generation for flamegraph profiling. + // - UnlockDiagnosticVMOptions must come before DumpPerfMapAtExit (diagnostic option). + // - PreserveFramePointer: Preserves frame pointers for profiling. + // - DumpPerfMapAtExit: Writes /tmp/perf-.map on JVM exit for symbol resolution. + // - DebugNonSafepoints: Enables debug info for JIT-compiled non-safepoint code. + ( + "JAVA_TOOL_OPTIONS", + if mode == RunnerMode::Walltime { + "-XX:+PreserveFramePointer -XX:+UnlockDiagnosticVMOptions -XX:+DumpPerfMapAtExit -XX:+DebugNonSafepoints".into() + } else { + "".into() + }, + ), ("ARCH", ARCH.into()), ("CODSPEED_ENV", "runner".into()), ( From e5d6deba9554eac1f2947a22e3987574339e723e Mon Sep 17 00:00:00 2001 From: not-matthias Date: Tue, 10 Mar 2026 18:12:39 +0100 Subject: [PATCH 2/4] fix: support spaces in base injected env --- src/executor/helpers/run_with_env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/executor/helpers/run_with_env.rs b/src/executor/helpers/run_with_env.rs index a1b1aa61..5bfd7f5a 100644 --- a/src/executor/helpers/run_with_env.rs +++ b/src/executor/helpers/run_with_env.rs @@ -54,7 +54,7 @@ fn create_env_file(extra_env: &HashMap<&'static str, String>) -> Result>() .join("\n"); From b51c7d8029fe7829e5bb6d18ee5fb6654e7e3d80 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Wed, 11 Mar 2026 18:51:53 +0100 Subject: [PATCH 3/4] chore: use frame-pointer unwinding with Java --- src/executor/wall_time/perf/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/executor/wall_time/perf/mod.rs b/src/executor/wall_time/perf/mod.rs index bfbfc9aa..c23e254e 100644 --- a/src/executor/wall_time/perf/mod.rs +++ b/src/executor/wall_time/perf/mod.rs @@ -96,6 +96,9 @@ impl PerfRunner { // Infer the unwinding mode from the benchmark cmd let (cg_mode, stack_size) = if let Some(mode) = config.perf_unwinding_mode { (mode, None) + } else if config.command.contains("gradle") | config.command.contains("java") | config.command.contains("maven") { + // In Java, we must use FP unwinding otherwise we'll have broken call stacks. + (UnwindingMode::FramePointer, None) } else if config.command.contains("cargo") { (UnwindingMode::Dwarf, None) } else if config.command.contains("pytest") From cf6217a2ba13bd7a15b0ba611c62332ccf82d630 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Wed, 11 Mar 2026 18:55:32 +0100 Subject: [PATCH 4/4] chore: add debug output for /proc/maps in walltime Print the benchmark process memory map when CODSPEED_DEBUG is enabled. This helps with debugging missing symbols by showing which modules are loaded at which addresses. --- src/executor/wall_time/perf/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/executor/wall_time/perf/mod.rs b/src/executor/wall_time/perf/mod.rs index c23e254e..39267ce4 100644 --- a/src/executor/wall_time/perf/mod.rs +++ b/src/executor/wall_time/perf/mod.rs @@ -219,6 +219,16 @@ impl PerfRunner { let on_cmd = async |cmd: &FifoCommand| { #[allow(deprecated)] match cmd { + // Print /proc/{pid}/maps for the benchmark process. This helps with debugging missing symbols, as + // it allows finding the module in which an address is located. + FifoCommand::CurrentBenchmark { pid, .. } if is_codspeed_debug_enabled() => { + let maps_path = format!("/proc/{pid}/maps"); + match std::fs::read_to_string(&maps_path) { + Ok(maps) => debug!("/proc/{pid}/maps:\n{maps}"), + Err(e) => debug!("Failed to read {maps_path}: {e}"), + } + return Ok(None); + } FifoCommand::StartBenchmark => { perf_fifo.start_events().await?; }