Skip to content

Commit 8b37208

Browse files
feat: parse the perf file memory mappings
Stop reading `/proc/<pid>/maps` during execution.
1 parent 6e5891e commit 8b37208

7 files changed

Lines changed: 28 additions & 212 deletions

File tree

src/cli/exec/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,7 @@ pub async fn execute_with_harness(
103103
}
104104

105105
debug!("config: {:#?}", execution_context.config);
106-
let executor = executor::get_executor_from_mode(
107-
&execution_context.config.mode,
108-
executor::ExecutorCommand::Exec,
109-
);
106+
let executor = executor::get_executor_from_mode(&execution_context.config.mode);
110107

111108
let get_exec_harness_installer_url = || {
112109
format!(

src/cli/run/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,7 @@ pub async fn run(
152152
debug!("config: {:#?}", execution_context.config);
153153

154154
// Execute benchmarks
155-
let executor = executor::get_executor_from_mode(
156-
&execution_context.config.mode,
157-
executor::ExecutorCommand::Run,
158-
);
155+
let executor = executor::get_executor_from_mode(&execution_context.config.mode);
159156

160157
let poll_results_fn = async |upload_result: &UploadResult| {
161158
poll_results::poll_results(api_client, upload_result, output_json).await

src/executor/mod.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,11 @@ impl Display for RunnerMode {
4242

4343
pub const EXECUTOR_TARGET: &str = "executor";
4444

45-
/// Whether the executor is used for a `run` or an `exec`
46-
/// FIXME: This should not really be a concern for the executor itself
47-
pub enum ExecutorCommand {
48-
Run,
49-
Exec,
50-
}
51-
52-
pub fn get_executor_from_mode(mode: &RunnerMode, command: ExecutorCommand) -> Box<dyn Executor> {
45+
pub fn get_executor_from_mode(mode: &RunnerMode) -> Box<dyn Executor> {
5346
match mode {
5447
#[allow(deprecated)]
5548
RunnerMode::Instrumentation | RunnerMode::Simulation => Box::new(ValgrindExecutor),
56-
RunnerMode::Walltime => {
57-
let output_pipedata = match command {
58-
ExecutorCommand::Run => true,
59-
ExecutorCommand::Exec => false,
60-
};
61-
Box::new(WallTimeExecutor::new_with_output_pipedata(output_pipedata))
62-
}
49+
RunnerMode::Walltime => Box::new(WallTimeExecutor::new()),
6350
RunnerMode::Memory => Box::new(MemoryExecutor),
6451
}
6552
}

src/executor/wall_time/executor.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,7 @@ pub struct WallTimeExecutor {
7878
impl WallTimeExecutor {
7979
pub fn new() -> Self {
8080
Self {
81-
perf: cfg!(target_os = "linux").then(|| PerfRunner::new(true)),
82-
}
83-
}
84-
85-
pub fn new_with_output_pipedata(output_pipedata: bool) -> Self {
86-
Self {
87-
perf: cfg!(target_os = "linux").then(|| PerfRunner::new(output_pipedata)),
81+
perf: cfg!(target_os = "linux").then(PerfRunner::new),
8882
}
8983
}
9084

src/executor/wall_time/perf/memory_mappings.rs

Lines changed: 0 additions & 75 deletions
This file was deleted.

src/executor/wall_time/perf/mod.rs

Lines changed: 22 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,21 @@ use crate::executor::wall_time::perf::perf_executable::get_working_perf_executab
1717
use crate::prelude::*;
1818
use anyhow::Context;
1919
use fifo::PerfFifo;
20-
use libc::pid_t;
20+
use parse_perf_file::MemmapRecordsOutput;
2121
use perf_executable::get_compression_flags;
2222
use perf_executable::get_event_flags;
23-
use perf_map::ProcessSymbols;
2423
use rayon::prelude::*;
2524
use runner_shared::artifacts::ArtifactExt;
2625
use runner_shared::artifacts::ExecutionTimestamps;
2726
use runner_shared::debug_info::ModuleDebugInfo;
2827
use runner_shared::fifo::Command as FifoCommand;
2928
use runner_shared::fifo::IntegrationMode;
3029
use runner_shared::metadata::PerfMetadata;
31-
use runner_shared::unwind_data::UnwindData;
3230
use std::path::Path;
3331
use std::path::PathBuf;
3432
use std::{cell::OnceCell, collections::HashMap, process::ExitStatus};
3533

3634
mod jit_dump;
37-
mod memory_mappings;
3835
mod parse_perf_file;
3936
mod setup;
4037

@@ -46,15 +43,10 @@ pub mod perf_map;
4643
pub mod unwind_data;
4744

4845
const PERF_METADATA_CURRENT_VERSION: u64 = 1;
49-
const PERF_DATA_FILE_NAME: &str = "perf.data";
5046
const PERF_PIPEDATA_FILE_NAME: &str = "perf.pipedata";
5147

5248
pub struct PerfRunner {
5349
benchmark_data: OnceCell<BenchmarkData>,
54-
/// Whether to output the perf data to a streamable .pipedata file
55-
/// This can be removed once we have upstreamed the the linux-perf-data crate changes to parse
56-
/// from pipedata directly, to only support pipedata.
57-
output_pipedata: bool,
5850
}
5951

6052
impl PerfRunner {
@@ -89,9 +81,8 @@ impl PerfRunner {
8981
Ok(())
9082
}
9183

92-
pub fn new(output_pipedata: bool) -> Self {
84+
pub fn new() -> Self {
9385
Self {
94-
output_pipedata,
9586
benchmark_data: OnceCell::new(),
9687
}
9788
}
@@ -160,36 +151,18 @@ impl PerfRunner {
160151
perf_fifo.ctl_path().to_string_lossy(),
161152
perf_fifo.ack_path().to_string_lossy()
162153
),
154+
"-o",
155+
"-", // Output to stdout for piping
156+
"--",
163157
]);
164158

165-
if self.output_pipedata {
166-
perf_wrapper_builder.args([
167-
"-o", "-", // forces pipe mode
168-
]);
169-
} else {
170-
perf_wrapper_builder.args([
171-
"-o",
172-
self.get_perf_file_path(profile_folder)
173-
.to_string_lossy()
174-
.as_ref(),
175-
]);
176-
}
177-
178-
perf_wrapper_builder.arg("--");
179159
cmd_builder.wrap_with(perf_wrapper_builder);
180160

181-
// Output the perf data to the profile folder
182-
let perf_data_file_path = self.get_perf_file_path(profile_folder);
183-
184-
let raw_command = if self.output_pipedata {
185-
format!(
186-
"set -o pipefail && {} | cat > {}",
187-
&cmd_builder.as_command_line(),
188-
perf_data_file_path.to_string_lossy()
189-
)
190-
} else {
191-
cmd_builder.as_command_line()
192-
};
161+
let raw_command = format!(
162+
"set -o pipefail && {} | cat > {}",
163+
&cmd_builder.as_command_line(),
164+
self.get_perf_file_path(profile_folder).to_string_lossy()
165+
);
193166

194167
let mut wrapped_builder = CommandBuilder::new("bash");
195168
wrapped_builder.args(["-c", &raw_command]);
@@ -205,8 +178,7 @@ impl PerfRunner {
205178
let on_process_started = |mut child: std::process::Child| async move {
206179
// If we output pipedata, we do not parse the perf map during teardown yet, so we need to parse memory
207180
// maps as we receive the `CurrentBenchmark` fifo commands.
208-
let (data, exit_status) =
209-
Self::handle_fifo(runner_fifo, perf_fifo, self.output_pipedata, &mut child).await?;
181+
let (data, exit_status) = Self::handle_fifo(runner_fifo, perf_fifo, &mut child).await?;
210182
self.benchmark_data.set(data).unwrap_or_else(|_| {
211183
error!("Failed to set benchmark data in PerfRunner");
212184
});
@@ -247,12 +219,8 @@ impl PerfRunner {
247219
async fn handle_fifo(
248220
mut runner_fifo: RunnerFifo,
249221
mut perf_fifo: PerfFifo,
250-
parse_memory_maps: bool,
251222
child: &mut std::process::Child,
252223
) -> anyhow::Result<(BenchmarkData, std::process::ExitStatus)> {
253-
let mut symbols_by_pid = HashMap::<pid_t, ProcessSymbols>::new();
254-
let mut unwind_data_by_pid = HashMap::<pid_t, Vec<UnwindData>>::new();
255-
256224
let on_cmd = async |cmd: &FifoCommand| {
257225
#[allow(deprecated)]
258226
match cmd {
@@ -262,19 +230,6 @@ impl PerfRunner {
262230
FifoCommand::StopBenchmark => {
263231
perf_fifo.stop_events().await?;
264232
}
265-
FifoCommand::CurrentBenchmark { pid, .. } => {
266-
#[cfg(target_os = "linux")]
267-
if parse_memory_maps
268-
&& !symbols_by_pid.contains_key(pid)
269-
&& !unwind_data_by_pid.contains_key(pid)
270-
{
271-
memory_mappings::process_memory_mappings(
272-
*pid,
273-
&mut symbols_by_pid,
274-
&mut unwind_data_by_pid,
275-
)?;
276-
}
277-
}
278233
FifoCommand::PingPerf => {
279234
if perf_fifo.ping().await.is_err() {
280235
return Ok(Some(FifoCommand::Err));
@@ -299,27 +254,19 @@ impl PerfRunner {
299254
BenchmarkData {
300255
fifo_data,
301256
marker_result,
302-
symbols_by_pid,
303-
unwind_data_by_pid,
304257
},
305258
exit_status,
306259
))
307260
}
308261

309262
fn get_perf_file_path<P: AsRef<Path>>(&self, profile_folder: P) -> PathBuf {
310-
if self.output_pipedata {
311-
profile_folder.as_ref().join(PERF_PIPEDATA_FILE_NAME)
312-
} else {
313-
profile_folder.as_ref().join(PERF_DATA_FILE_NAME)
314-
}
263+
profile_folder.as_ref().join(PERF_PIPEDATA_FILE_NAME)
315264
}
316265
}
317266

318267
pub struct BenchmarkData {
319268
fifo_data: FifoBenchmarkData,
320269
marker_result: ExecutionTimestamps,
321-
pub symbols_by_pid: HashMap<pid_t, ProcessSymbols>,
322-
pub unwind_data_by_pid: HashMap<pid_t, Vec<UnwindData>>,
323270
}
324271

325272
#[derive(Debug)]
@@ -336,28 +283,16 @@ impl BenchmarkData {
336283
) -> Result<(), BenchmarkDataSaveError> {
337284
self.marker_result.save_to(&path).unwrap();
338285

339-
let parsed_perf_map_output =
340-
if self.symbols_by_pid.is_empty() && self.unwind_data_by_pid.is_empty() {
341-
debug!("Reading perf data from file for mmap extraction");
342-
Some(
343-
parse_perf_file::parse_for_memmap2(perf_file_path).map_err(|e| {
344-
error!("Failed to parse perf file: {e}");
345-
BenchmarkDataSaveError::FailedToParsePerfFile
346-
})?,
347-
)
348-
} else {
349-
None
350-
};
351-
352-
let (symbols_by_pid, unwind_data_by_pid) =
353-
if let Some(parsed_perf_map_output) = parsed_perf_map_output.as_ref() {
354-
(
355-
&parsed_perf_map_output.symbols_by_pid,
356-
&parsed_perf_map_output.unwind_data_by_pid,
357-
)
358-
} else {
359-
(&self.symbols_by_pid, &self.unwind_data_by_pid)
360-
};
286+
debug!("Reading perf data from file for mmap extraction");
287+
let MemmapRecordsOutput {
288+
symbols_by_pid,
289+
unwind_data_by_pid,
290+
} = {
291+
parse_perf_file::parse_for_memmap2(perf_file_path).map_err(|e| {
292+
error!("Failed to parse perf file: {e}");
293+
BenchmarkDataSaveError::FailedToParsePerfFile
294+
})?
295+
};
361296

362297
let path_ref = path.as_ref();
363298
debug!("Saving symbols addresses");

src/executor/wall_time/perf/parse_perf_file.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::perf_map::ProcessSymbols;
22
use super::unwind_data::UnwindDataExt;
3-
use crate::executor::helpers::run_with_sudo::run_with_sudo;
43
use crate::prelude::*;
54
use libc::pid_t;
65
use linux_perf_data::PerfFileReader;
@@ -19,30 +18,12 @@ pub(super) fn parse_for_memmap2<P: AsRef<Path>>(perf_file_path: P) -> Result<Mem
1918
let mut symbols_by_pid = HashMap::<pid_t, ProcessSymbols>::new();
2019
let mut unwind_data_by_pid = HashMap::<pid_t, Vec<UnwindData>>::new();
2120

22-
//FIXME: Remove this once again when we parse directly from pipedata
23-
{
24-
let tmp_perf_file_path = perf_file_path.as_ref().to_string_lossy();
25-
26-
// We ran perf with sudo, so we have to change the ownership of the perf.data
27-
run_with_sudo(
28-
"chown",
29-
[
30-
"-R",
31-
&format!(
32-
"{}:{}",
33-
nix::unistd::Uid::current(),
34-
nix::unistd::Gid::current()
35-
),
36-
&tmp_perf_file_path,
37-
],
38-
)?;
39-
}
4021
let reader = std::fs::File::open(perf_file_path.as_ref()).unwrap();
4122

4223
let PerfFileReader {
4324
mut perf_file,
4425
mut record_iter,
45-
} = PerfFileReader::parse_file(reader)?;
26+
} = PerfFileReader::parse_pipe(reader)?;
4627

4728
while let Some(record) = record_iter.next_record(&mut perf_file).unwrap() {
4829
let PerfFileRecord::EventRecord { record, .. } = record else {

0 commit comments

Comments
 (0)