Skip to content

Commit 5fc9454

Browse files
committed
refactor(walltime): share Linux profiler sysctl setup
Move the Linux profiling sysctl setup out of the perf profiler and into a shared walltime profiler helper. This lets both perf and samply prepare kernel symbol access and non-root profiling consistently while preserving the existing sudo-based behavior.
1 parent af25ae3 commit 5fc9454

4 files changed

Lines changed: 81 additions & 25 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use crate::prelude::*;
2+
3+
#[cfg(target_os = "linux")]
4+
use crate::executor::helpers::run_with_sudo::run_with_sudo;
5+
#[cfg(any(test, target_os = "linux"))]
6+
use anyhow::Context;
7+
#[cfg(target_os = "linux")]
8+
use std::process::Command;
9+
10+
pub fn ensure_linux_profiling_sysctls() -> Result<()> {
11+
#[cfg(target_os = "linux")]
12+
{
13+
ensure_sysctl("kernel.kptr_restrict", 0)?;
14+
ensure_sysctl("kernel.perf_event_paranoid", -1)?;
15+
}
16+
17+
Ok(())
18+
}
19+
20+
#[cfg(target_os = "linux")]
21+
fn ensure_sysctl(name: &str, target_value: i64) -> Result<()> {
22+
if sysctl_read(name)? == target_value {
23+
return Ok(());
24+
}
25+
26+
let assignment = format!("{name}={target_value}");
27+
run_with_sudo("sysctl", ["-w", assignment.as_str()])
28+
}
29+
30+
#[cfg(target_os = "linux")]
31+
fn sysctl_read(name: &str) -> Result<i64> {
32+
let output = Command::new("sysctl").arg(name).output()?;
33+
let output = String::from_utf8(output.stdout)?;
34+
35+
parse_sysctl_value(&output)
36+
}
37+
38+
#[cfg(any(test, target_os = "linux"))]
39+
fn parse_sysctl_value(output: &str) -> Result<i64> {
40+
let (_, value) = output
41+
.split_once('=')
42+
.context("Couldn't find the value in sysctl output")?;
43+
44+
Ok(value.trim().parse::<i64>()?)
45+
}
46+
47+
#[cfg(test)]
48+
mod tests {
49+
use super::*;
50+
51+
#[test]
52+
fn parses_sysctl_value() {
53+
assert_eq!(parse_sysctl_value("kernel.kptr_restrict = 0\n").unwrap(), 0);
54+
}
55+
56+
#[test]
57+
fn parses_negative_sysctl_value() {
58+
assert_eq!(
59+
parse_sysctl_value("kernel.perf_event_paranoid = -1\n").unwrap(),
60+
-1
61+
);
62+
}
63+
64+
#[test]
65+
fn rejects_sysctl_output_without_value_separator() {
66+
assert!(parse_sysctl_value("kernel.kptr_restrict 0\n").is_err());
67+
}
68+
}

src/executor/wall_time/profiler/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! (perf, samply, instruments, ...) and produces a unified set of artifacts
55
//! in the profile folder.
66
7+
mod linux_sysctl;
78
pub mod perf;
89
pub mod samply;
910

src/executor/wall_time/profiler/perf/mod.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ use crate::executor::helpers::detect_executable::command_has_executable;
88
use crate::executor::helpers::env::is_codspeed_debug_enabled;
99
use crate::executor::helpers::env::suppress_go_perf_unwinding_warning;
1010
use crate::executor::helpers::harvest_perf_maps_for_pids::harvest_perf_maps_for_pids;
11-
use crate::executor::helpers::run_with_sudo::run_with_sudo;
1211
use crate::executor::helpers::run_with_sudo::wrap_with_sudo;
1312
use crate::executor::shared::fifo::FifoBenchmarkData;
1413
use crate::executor::wall_time::profiler::Profiler;
1514
use crate::executor::wall_time::profiler::WALLTIME_METADATA_CURRENT_VERSION;
15+
use crate::executor::wall_time::profiler::linux_sysctl::ensure_linux_profiling_sysctls;
1616
use crate::executor::wall_time::profiler::perf::perf_executable::get_working_perf_executable;
1717
use crate::prelude::*;
1818
use crate::system::SystemInfo;
@@ -81,30 +81,7 @@ impl Profiler for PerfProfiler {
8181
setup_cache_dir: Option<&Path>,
8282
) -> anyhow::Result<()> {
8383
setup::install_perf(system_info, setup_cache_dir).await?;
84-
85-
let sysctl_read = |name: &str| -> anyhow::Result<i64> {
86-
let output = std::process::Command::new("sysctl").arg(name).output()?;
87-
let output = String::from_utf8(output.stdout)?;
88-
89-
Ok(output
90-
.split(" = ")
91-
.last()
92-
.context("Couldn't find the value in sysctl output")?
93-
.trim()
94-
.parse::<i64>()?)
95-
};
96-
97-
// Allow access to kernel symbols
98-
if sysctl_read("kernel.kptr_restrict")? != 0 {
99-
run_with_sudo("sysctl", ["-w", "kernel.kptr_restrict=0"])?;
100-
}
101-
102-
// Allow non-root profiling
103-
if sysctl_read("kernel.perf_event_paranoid")? != -1 {
104-
run_with_sudo("sysctl", ["-w", "kernel.perf_event_paranoid=-1"])?;
105-
}
106-
107-
Ok(())
84+
ensure_linux_profiling_sysctls()
10885
}
10986

11087
async fn wrap(

src/executor/wall_time/profiler/samply/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use crate::executor::ExecutorConfig;
44
use crate::executor::helpers::command::CommandBuilder;
55
use crate::executor::shared::fifo::FifoBenchmarkData;
66
use crate::executor::wall_time::profiler::Profiler;
7+
use crate::executor::wall_time::profiler::linux_sysctl::ensure_linux_profiling_sysctls;
78
use crate::prelude::*;
9+
use crate::system::SystemInfo;
810
use async_trait::async_trait;
911
use runner_shared::artifacts::ArtifactExt;
1012
use runner_shared::artifacts::ExecutionTimestamps;
@@ -32,6 +34,14 @@ impl SamplyProfiler {
3234

3335
#[async_trait(?Send)]
3436
impl Profiler for SamplyProfiler {
37+
async fn setup(
38+
&self,
39+
_system_info: &SystemInfo,
40+
_setup_cache_dir: Option<&Path>,
41+
) -> anyhow::Result<()> {
42+
ensure_linux_profiling_sysctls()
43+
}
44+
3545
async fn wrap(
3646
&mut self,
3747
mut cmd_builder: CommandBuilder,

0 commit comments

Comments
 (0)