From 3f70c22858c93c44a22cf9c8ebcd1073b056909f Mon Sep 17 00:00:00 2001 From: Guillaume Lagrange Date: Fri, 7 Nov 2025 11:52:37 +0100 Subject: [PATCH] feat: add more events to perf monitoring --- src/run/runner/wall_time/perf/mod.rs | 7 ++- .../runner/wall_time/perf/perf_executable.rs | 43 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/run/runner/wall_time/perf/mod.rs b/src/run/runner/wall_time/perf/mod.rs index 7e4c8220..c3117d9f 100644 --- a/src/run/runner/wall_time/perf/mod.rs +++ b/src/run/runner/wall_time/perf/mod.rs @@ -19,6 +19,7 @@ use fifo::{PerfFifo, RunnerFifo}; use libc::pid_t; use nix::sys::time::TimeValLike; use nix::time::clock_gettime; +use perf_executable::get_event_flags; use perf_map::ProcessSymbols; use runner_shared::debug_info::ModuleDebugInfo; use runner_shared::fifo::Command as FifoCommand; @@ -120,11 +121,15 @@ impl PerfRunner { let working_perf_executable = get_working_perf_executable().context("Failed to find a working perf executable")?; - let mut perf_wrapper_builder = CommandBuilder::new(working_perf_executable); + let mut perf_wrapper_builder = CommandBuilder::new(&working_perf_executable); perf_wrapper_builder.arg("record"); if !is_codspeed_debug_enabled() { perf_wrapper_builder.arg("--quiet"); } + // Add events flag if all required events are available + if let Some(events_flag) = get_event_flags(&working_perf_executable)? { + perf_wrapper_builder.arg(events_flag); + } perf_wrapper_builder.args([ "--timestamp", // Required for matching the markers and URIs to the samples. diff --git a/src/run/runner/wall_time/perf/perf_executable.rs b/src/run/runner/wall_time/perf/perf_executable.rs index 6da51cd6..623e5c48 100644 --- a/src/run/runner/wall_time/perf/perf_executable.rs +++ b/src/run/runner/wall_time/perf/perf_executable.rs @@ -62,3 +62,46 @@ pub fn get_working_perf_executable() -> Option { debug!("perf is installed but not functioning correctly"); None } + +/// Detects if the required perf events are available on this system. +/// Returns Some("-e {cycles,cache-references,cache-misses}") if all three events are available, +/// None otherwise. +pub fn get_event_flags(perf_executable: &OsString) -> anyhow::Result> { + const CYCLES_EVENT_NAME: &str = "cycles"; + const CACHE_REFERENCES_EVENT_NAME: &str = "cache-references"; + const CACHE_MISSES_EVENT_NAME: &str = "cache-misses"; + + let perf_events = [ + CYCLES_EVENT_NAME, + CACHE_REFERENCES_EVENT_NAME, + CACHE_MISSES_EVENT_NAME, + ]; + + let output = Command::new(perf_executable) + .arg("list") + .output() + .context("Failed to run perf list")?; + + let stdout = String::from_utf8_lossy(&output.stdout); + + // Check if all required events are available + let missing_events: Vec<&str> = perf_events + .iter() + .filter(|&&event| !stdout.lines().any(|line| line.trim().starts_with(event))) + .copied() + .collect(); + + if !missing_events.is_empty() { + debug!( + "Not all required perf events available. Missing: [{}], using default events", + missing_events.join(", ") + ); + return Ok(None); + } + + debug!( + "All required perf events available: {}", + perf_events.join(", ") + ); + Ok(Some(format!("-e {{{}}}", perf_events.join(",")))) +}