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
108 changes: 108 additions & 0 deletions src/executor/helpers/linux_sysctl.rs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to gate this whole mod behind the feature flag but not every single line, because now we end up gating almost every single line with #[cfg(target_os = "linux")] 😅

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::executor::helpers::run_with_sudo::run_with_sudo;
use crate::prelude::*;
use anyhow::Context;
use std::process::Command;

/// Restores a sysctl to its initial value when dropped.
#[derive(Debug)]
#[must_use = "the sysctl is restored when this guard is dropped"]
pub(crate) struct LinuxSysctl {
name: &'static str,
previous: Option<i64>,
}

impl LinuxSysctl {
pub(crate) fn set(name: &'static str, target_value: i64) -> Result<Self> {
let previous = ensure_sysctl(name, target_value)?;

Ok(Self { name, previous })
}

pub(crate) fn is_changed(&self) -> bool {
self.previous.is_some()
}
}

impl Drop for LinuxSysctl {
fn drop(&mut self) {
let Some(value) = self.previous else {
return;
};

if let Err(error) = ensure_sysctl(self.name, value) {
warn!("Failed to restore {}={value}: {error}", self.name);
}
}
}

pub fn ensure_linux_profiling_sysctls() -> Result<Vec<LinuxSysctl>> {
if !cfg!(target_os = "linux") {
return Ok(Vec::new());
}

let mut sysctls = Vec::new();

for (name, target_value) in [
("kernel.kptr_restrict", 0),
("kernel.perf_event_paranoid", -1),
] {
let sysctl = LinuxSysctl::set(name, target_value)?;
if sysctl.is_changed() {
sysctls.push(sysctl);
}
}

Ok(sysctls)
}

/// Sets a sysctl, returning the value it held before, or `None` when it was
/// already at `target_value` and nothing was written.
pub(crate) fn ensure_sysctl(name: &str, target_value: i64) -> Result<Option<i64>> {
let current_value = sysctl_read(name)?;
if current_value == target_value {
return Ok(None);
}

let assignment = format!("{name}={target_value}");
run_with_sudo("sysctl", ["-w", assignment.as_str()])?;

Ok(Some(current_value))
}

fn sysctl_read(name: &str) -> Result<i64> {
let output = Command::new("sysctl").arg(name).output()?;
let output = String::from_utf8(output.stdout)?;

parse_sysctl_value(&output)
}

fn parse_sysctl_value(output: &str) -> Result<i64> {
let (_, value) = output
.split_once('=')
.context("Couldn't find the value in sysctl output")?;

Ok(value.trim().parse::<i64>()?)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parses_sysctl_value() {
assert_eq!(parse_sysctl_value("kernel.kptr_restrict = 0\n").unwrap(), 0);
}

#[test]
fn parses_negative_sysctl_value() {
assert_eq!(
parse_sysctl_value("kernel.perf_event_paranoid = -1\n").unwrap(),
-1
);
}

#[test]
fn rejects_sysctl_output_without_value_separator() {
assert!(parse_sysctl_value("kernel.kptr_restrict 0\n").is_err());
}
}
1 change: 1 addition & 0 deletions src/executor/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod harvest_perf_maps_for_pids;
pub mod homebrew;
pub mod introspected_golang;
pub mod introspected_nodejs;
pub mod linux_sysctl;
pub mod profile_folder;
pub mod run_command_with_log_pipe;
pub mod run_with_env;
Expand Down
3 changes: 3 additions & 0 deletions src/executor/memory/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::executor::helpers::get_bench_command::get_bench_command;
use crate::executor::helpers::run_command_with_log_pipe::run_command_with_log_pipe_and_callback;
use crate::executor::helpers::run_with_env::prefix_command_with_env;
use crate::executor::helpers::run_with_sudo::is_root_user;
use crate::executor::memory::tunables::MemoryTunables;
use crate::executor::shared::fifo::RunnerFifo;
use crate::executor::{ExecutionContext, Executor};
use crate::instruments::mongo_tracer::MongoTracer;
Expand Down Expand Up @@ -159,6 +160,8 @@ impl Executor for MemoryExecutor {
execution_context: &ExecutionContext,
_mongo_tracer: &Option<MongoTracer>,
) -> Result<()> {
let _tunables = MemoryTunables::apply();

// Create the results/ directory inside the profile folder to avoid having memtrack create it with wrong permissions
std::fs::create_dir_all(execution_context.profile_folder.join("results"))?;

Expand Down
1 change: 1 addition & 0 deletions src/executor/memory/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod executor;
pub(crate) mod setup;
pub(crate) mod tunables;
Loading