Skip to content

Commit

Permalink
Add support for marker files on Linux.
Browse files Browse the repository at this point in the history
If the profiled process opens a file whose name starts with marker- and ends with .txt,
and we see an MMAP or MMAP2 record for that file in the profile, read marker span
information from it.
  • Loading branch information
mstange committed Mar 4, 2024
1 parent 260e0bf commit 50364c2
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 29 deletions.
61 changes: 40 additions & 21 deletions samply/src/linux_shared/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,11 +569,8 @@ where

pub fn handle_mmap(&mut self, e: MmapRecord, timestamp: u64) {
let mut path = e.path.as_slice();
if let Some(jitdump_path) = get_path_if_jitdump(&path) {
let process = self.processes.get_by_pid(e.pid, &mut self.profile);
process
.jitdump_manager
.add_jitdump_path(jitdump_path, self.extra_binary_artifact_dir.clone());
if self.check_jitdump_or_marker_file(&path, e.pid, e.tid) {
// Not a DSO.
return;
}

Expand Down Expand Up @@ -618,16 +615,13 @@ where

pub fn handle_mmap2(&mut self, e: Mmap2Record, timestamp: u64) {
let path = e.path.as_slice();
if let Some(jitdump_path) = get_path_if_jitdump(&path) {
let process = self.processes.get_by_pid(e.pid, &mut self.profile);
process
.jitdump_manager
.add_jitdump_path(jitdump_path, self.extra_binary_artifact_dir.clone());
if self.check_jitdump_or_marker_file(&path, e.pid, e.tid) {
// Not a DSO.
return;
}

if e.page_offset == 0 {
self.check_for_pe_mapping(&e.path.as_slice(), e.address);
self.check_for_pe_mapping(&path, e.address);
}

const PROT_EXEC: u32 = 0b100;
Expand Down Expand Up @@ -660,6 +654,41 @@ where
);
}

fn check_jitdump_or_marker_file(&mut self, path: &[u8], pid: i32, tid: i32) -> bool {
let Ok(path) = std::str::from_utf8(path) else {
return false;
};

let filename = match path.rfind('/') {
Some(pos) => &path[pos + 1..],
None => path,
};

if filename.starts_with("jit-") && filename.ends_with(".dump") {
let jitdump_path = Path::new(path);
let process = self.processes.get_by_pid(pid, &mut self.profile);
process
.jitdump_manager
.add_jitdump_path(jitdump_path, self.extra_binary_artifact_dir.clone());
return true;
}

if filename.starts_with("marker-") && filename.ends_with(".txt") {
let marker_file_path = Path::new(path);
let process = self.processes.get_by_pid(pid, &mut self.profile);
let thread = process.threads.get_thread_by_tid(tid, &mut self.profile);
let profile_thread = thread.profile_thread;
process.add_marker_file_path(
profile_thread,
marker_file_path,
self.extra_binary_artifact_dir.clone(),
);
return true;
}

false
}

pub fn handle_context_switch(&mut self, e: ContextSwitchRecord, common: CommonData) {
let pid = common.pid.expect("Can't handle samples without pids");
let tid = common.tid.expect("Can't handle samples without tids");
Expand Down Expand Up @@ -1269,13 +1298,3 @@ fn get_pe_mapping_size(path_slice: &[u8]) -> Option<u64> {
_ => None,
}
}

fn get_path_if_jitdump(path: &[u8]) -> Option<&Path> {
let path = Path::new(std::str::from_utf8(path).ok()?);
let filename = path.file_name()?.to_str()?;
if filename.starts_with("jit-") && filename.ends_with(".dump") {
Some(path)
} else {
None
}
}
39 changes: 36 additions & 3 deletions samply/src/linux_shared/process.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::{Path, PathBuf};

use framehop::Unwinder;
use fxprof_processed_profile::{
CounterHandle, LibraryHandle, MarkerTiming, ProcessHandle, Profile, ThreadHandle, Timestamp,
Expand All @@ -11,8 +13,9 @@ use crate::shared::jit_function_add_marker::JitFunctionAddMarker;
use crate::shared::jit_function_recycler::JitFunctionRecycler;
use crate::shared::jitdump_manager::JitDumpManager;
use crate::shared::lib_mappings::{LibMappingAdd, LibMappingInfo, LibMappingOp, LibMappingOpQueue};
use crate::shared::marker_file::get_markers;
use crate::shared::perf_map::try_load_perf_map;
use crate::shared::process_sample_data::ProcessSampleData;
use crate::shared::process_sample_data::{MarkerSpanOnThread, ProcessSampleData};
use crate::shared::recycling::{ProcessRecyclingData, ThreadRecycler};
use crate::shared::timestamp_converter::TimestampConverter;

Expand All @@ -31,6 +34,7 @@ where
pub pid: i32,
pub unresolved_samples: UnresolvedSamples,
pub jit_function_recycler: Option<JitFunctionRecycler>,
marker_file_paths: Vec<(ThreadHandle, PathBuf, Option<PathBuf>)>,
pub prev_mm_filepages_size: i64,
pub prev_mm_anonpages_size: i64,
pub prev_mm_swapents_size: i64,
Expand Down Expand Up @@ -58,8 +62,9 @@ where
name,
pid,
threads: ProcessThreads::new(pid, process_handle, main_thread_handle, thread_recycler),
jit_function_recycler,
unresolved_samples: Default::default(),
jit_function_recycler,
marker_file_paths: Vec::new(),
prev_mm_filepages_size: 0,
prev_mm_anonpages_size: 0,
prev_mm_swapents_size: 0,
Expand Down Expand Up @@ -125,6 +130,16 @@ where
);
}

pub fn add_marker_file_path(
&mut self,
thread: ThreadHandle,
path: &Path,
fallback_dir: Option<PathBuf>,
) {
self.marker_file_paths
.push((thread, path.to_owned(), fallback_dir));
}

pub fn notify_dead(&mut self, end_time: Timestamp, profile: &mut Profile) {
self.threads.notify_process_dead(end_time, profile);
profile.set_process_end_time(self.profile_process, end_time);
Expand Down Expand Up @@ -162,12 +177,30 @@ where
timestamp_converter,
);

let mut marker_spans = Vec::new();
for (thread_handle, marker_file_path, fallback_dir) in self.marker_file_paths {
if let Ok(marker_spans_from_this_file) = get_markers(
&marker_file_path,
fallback_dir.as_deref(),
*timestamp_converter,
) {
marker_spans.extend(marker_spans_from_this_file.into_iter().map(|span| {
MarkerSpanOnThread {
thread_handle,
start_time: span.start_time,
end_time: span.end_time,
name: span.name,
}
}));
}
}

let process_sample_data = ProcessSampleData::new(
std::mem::take(&mut self.unresolved_samples),
std::mem::take(&mut self.lib_mapping_ops),
jitdump_ops,
perf_map_mappings,
Vec::new(),
marker_spans,
);

let thread_recycler = self.threads.finish();
Expand Down
1 change: 0 additions & 1 deletion samply/src/mac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ mod dyld_bindings;
mod error;
pub mod kernel_error;
mod mach_ipc;
mod marker_file;
mod proc_maps;
mod process_launcher;
pub mod profiler;
Expand Down
4 changes: 2 additions & 2 deletions samply/src/mac/task_profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::shared::jitdump_manager::JitDumpManager;
use crate::shared::lib_mappings::{
LibMappingAdd, LibMappingInfo, LibMappingOp, LibMappingOpQueue, LibMappingRemove,
};
use crate::shared::marker_file::get_markers;
use crate::shared::perf_map::try_load_perf_map;
use crate::shared::process_sample_data::{MarkerSpanOnThread, ProcessSampleData};
use crate::shared::recording_props::{ConversionProps, RecordingProps};
Expand All @@ -39,7 +40,6 @@ use crate::shared::unresolved_samples::{UnresolvedSamples, UnresolvedStacks};

use super::error::SamplingError;
use super::kernel_error::{IntoResult, KernelError};
use super::marker_file::get_markers;
use super::proc_maps::{
DyldInfo, DyldInfoManager, Modification, ModuleSvmaInfo, StackwalkerRef, VmSubData,
};
Expand Down Expand Up @@ -586,7 +586,7 @@ impl TaskProfiler {
let mut marker_spans = Vec::new();
for (thread_handle, marker_file_path) in self.marker_file_paths {
if let Ok(marker_spans_from_this_file) =
get_markers(&marker_file_path, self.timestamp_converter)
get_markers(&marker_file_path, None, self.timestamp_converter)
{
marker_spans.extend(marker_spans_from_this_file.into_iter().map(|span| {
MarkerSpanOnThread {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use std::fs::File;
use std::io::{BufRead, BufReader, Lines};
use std::path::Path;

use crate::shared::timestamp_converter::TimestampConverter;
use super::timestamp_converter::TimestampConverter;
use super::utils::open_file_with_fallback;

#[derive(Debug, Clone)]
pub struct MarkerSpan {
Expand Down Expand Up @@ -58,9 +59,10 @@ impl Iterator for MarkerFile {

pub fn get_markers(
marker_file: &Path,
extra_dir: Option<&Path>,
timestamp_converter: TimestampConverter,
) -> Result<Vec<MarkerSpan>, std::io::Error> {
let f = std::fs::File::open(marker_file)?;
let (f, _true_path) = open_file_with_fallback(marker_file, extra_dir)?;
let marker_file = MarkerFile::parse(f, timestamp_converter);
let mut marker_spans: Vec<MarkerSpan> = marker_file.collect();
marker_spans.sort_by_key(|m| m.start_time);
Expand Down
1 change: 1 addition & 0 deletions samply/src/shared/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod jit_function_add_marker;
pub mod jit_function_recycler;
pub mod jitdump_manager;
pub mod lib_mappings;
pub mod marker_file;
pub mod perf_map;
pub mod process_sample_data;
pub mod recording_props;
Expand Down

0 comments on commit 50364c2

Please sign in to comment.