Skip to content

Commit 1552740

Browse files
committed
fix(perf): ensure perf is always found on the machine
Workaround for https://bugs.launchpad.net/ubuntu/+source/linux-hwe-6.14/+bug/2117159/
1 parent 1932db1 commit 1552740

File tree

3 files changed

+68
-25
lines changed

3 files changed

+68
-25
lines changed

src/run/runner/wall_time/perf/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::run::runner::helpers::run_with_sudo::run_with_sudo;
99
use crate::run::runner::valgrind::helpers::ignored_objects_path::get_objects_path_to_ignore;
1010
use crate::run::runner::valgrind::helpers::perf_maps::harvest_perf_maps_for_pids;
1111
use crate::run::runner::wall_time::perf::jit_dump::harvest_perf_jit_for_pids;
12+
use crate::run::runner::wall_time::perf::perf_executable::get_working_perf_executable;
1213
use crate::run::runner::wall_time::perf::unwind_data::UnwindDataExt;
1314
use anyhow::Context;
1415
use fifo::{PerfFifo, RunnerFifo};
@@ -31,6 +32,7 @@ mod setup;
3132

3233
pub mod elf_helper;
3334
pub mod fifo;
35+
pub mod perf_executable;
3436
pub mod perf_map;
3537
pub mod unwind_data;
3638

@@ -118,8 +120,11 @@ impl PerfRunner {
118120
""
119121
};
120122

123+
let perf_executable =
124+
get_working_perf_executable().context("Failed to find a working perf executable")?;
125+
121126
let perf_args = [
122-
"perf",
127+
perf_executable.as_str(),
123128
"record",
124129
quiet_flag,
125130
"--timestamp",
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::prelude::*;
2+
3+
use std::process::Command;
4+
5+
const FIND_PERF_CMD: &str =
6+
"find /usr/lib -executable -path \"/usr/lib/linux-tools-*/perf\" | sort | tail -n1";
7+
8+
/// Attempts to find the path to the `perf` executable that is installed and working.
9+
/// Returns None if `perf` is not installed or not functioning correctly.
10+
pub fn get_working_perf_executable() -> Option<String> {
11+
let is_installed = Command::new("which")
12+
.arg("perf")
13+
.output()
14+
.is_ok_and(|output| output.status.success());
15+
if !is_installed {
16+
debug!("perf is not installed");
17+
return None;
18+
}
19+
20+
debug!("perf is installed, checking if it is functioning correctly");
21+
if Command::new("perf")
22+
.arg("--version") // here we use --version to check if perf is working
23+
.output()
24+
.is_ok_and(|output| output.status.success())
25+
{
26+
return Some("perf".to_string());
27+
} else {
28+
// The following is a workaround for this outstanding Ubuntu issue: https://bugs.launchpad.net/ubuntu/+source/linux-hwe-6.14/+bug/2117159/
29+
debug!(
30+
"perf command is not functioning correctly, trying to find alternative path using \"{FIND_PERF_CMD}\""
31+
);
32+
if let Ok(perf_path) = Command::new("sh").arg("-c").arg(FIND_PERF_CMD).output() {
33+
if perf_path.status.success() {
34+
let path = String::from_utf8_lossy(&perf_path.stdout)
35+
.trim()
36+
.to_string();
37+
debug!("Found perf path on retry: {path}");
38+
// Check if this perf is working by getting its version
39+
if let Ok(version_output) = Command::new(&path).arg("--version").output() {
40+
if !version_output.status.success() {
41+
debug!(
42+
"Failed to get perf version from alternative path. stderr: {}",
43+
String::from_utf8_lossy(&version_output.stderr)
44+
);
45+
return None;
46+
}
47+
48+
let version = String::from_utf8_lossy(&version_output.stdout)
49+
.trim()
50+
.to_string();
51+
debug!("Found perf version from alternative path: {version}");
52+
return Some(path);
53+
}
54+
}
55+
}
56+
}
57+
58+
debug!("perf is installed but not functioning correctly");
59+
None
60+
}

src/run/runner/wall_time/perf/setup.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,11 @@
11
use crate::run::runner::helpers::apt;
2+
use crate::run::runner::wall_time::perf::perf_executable::get_working_perf_executable;
23
use crate::{prelude::*, run::check_system::SystemInfo};
34

45
use std::{path::Path, process::Command};
56

67
fn is_perf_installed() -> bool {
7-
let is_installed = Command::new("which")
8-
.arg("perf")
9-
.output()
10-
.is_ok_and(|output| output.status.success());
11-
if !is_installed {
12-
debug!("perf is not installed");
13-
return false;
14-
}
15-
16-
if let Ok(version_output) = Command::new("perf").arg("--version").output() {
17-
if !version_output.status.success() {
18-
debug!(
19-
"Failed to get perf version. stderr: {}",
20-
String::from_utf8_lossy(&version_output.stderr)
21-
);
22-
return false;
23-
}
24-
25-
let version = String::from_utf8_lossy(&version_output.stdout);
26-
debug!("Found perf version: {}", version.trim());
27-
true
28-
} else {
29-
false
30-
}
8+
get_working_perf_executable().is_some()
319
}
3210

3311
pub async fn install_perf(system_info: &SystemInfo, setup_cache_dir: Option<&Path>) -> Result<()> {

0 commit comments

Comments
 (0)