Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/run/runner/wall_time/perf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
43 changes: 43 additions & 0 deletions src/run/runner/wall_time/perf/perf_executable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,46 @@ pub fn get_working_perf_executable() -> Option<OsString> {
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<Option<String>> {
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(","))))
}