Skip to content

Commit 903716f

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 b0720e3 commit 903716f

3 files changed

Lines changed: 66 additions & 21 deletions

File tree

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: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
debug!("Found perf path on retry: {}", path.trim());
36+
return Some(path.trim().to_string());
37+
}
38+
}
39+
}
40+
41+
debug!("perf is installed but not functioning correctly");
42+
None
43+
}

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

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,27 @@
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;
8+
if let Some(perf_path) = get_working_perf_executable() {
9+
if let Ok(version_output) = Command::new(perf_path).arg("--version").output() {
10+
if !version_output.status.success() {
11+
debug!(
12+
"Failed to get perf version. stderr: {}",
13+
String::from_utf8_lossy(&version_output.stderr)
14+
);
15+
16+
return false;
17+
}
18+
19+
let version = String::from_utf8_lossy(&version_output.stdout);
20+
debug!("Found perf version: {}", version.trim());
21+
true
22+
} else {
23+
false
2324
}
24-
25-
let version = String::from_utf8_lossy(&version_output.stdout);
26-
debug!("Found perf version: {}", version.trim());
27-
true
2825
} else {
2926
false
3027
}

0 commit comments

Comments
 (0)