Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unwind info manager implementation and use it #129

Merged
merged 1 commit into from
Jan 15, 2025
Merged
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
83 changes: 55 additions & 28 deletions src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use parking_lot::RwLock;
use std::collections::hash_map::Entry;
use std::collections::hash_map::OccupiedEntry;
use std::collections::HashMap;
use std::env::temp_dir;
use std::fs;
use std::io::ErrorKind;
use std::mem::size_of;
use std::mem::ManuallyDrop;
use std::mem::MaybeUninit;
Expand All @@ -20,7 +22,6 @@ use itertools::Itertools;
use libbpf_rs::num_possible_cpus;
use libbpf_rs::skel::SkelBuilder;
use libbpf_rs::skel::{OpenSkel, Skel};
use libbpf_rs::ErrorKind;
use libbpf_rs::MapCore;
use libbpf_rs::MapHandle;
use libbpf_rs::MapType;
Expand All @@ -41,8 +42,8 @@ use crate::process::{
ProcessStatus,
};
use crate::profile::*;
use crate::unwind_info::compact_unwind_info;
use crate::unwind_info::log_unwind_info_sections;
use crate::unwind_info::manager::UnwindInfoManager;
use crate::unwind_info::types::CompactUnwindRow;
use crate::util::{get_online_cpus, summarize_address_range};
use lightswitch_object::{ExecutableId, ObjectFile};
Expand Down Expand Up @@ -121,9 +122,11 @@ pub struct Profiler {
/// evictions which might reduce the quality of the profiles and in more work
/// for the profiler.
max_native_unwind_info_size_mb: i32,
unwind_info_manager: UnwindInfoManager,
}

pub struct ProfilerConfig {
pub cache_dir: PathBuf,
pub libbpf_debug: bool,
pub bpf_logging: bool,
pub duration: Duration,
Expand All @@ -142,7 +145,9 @@ pub struct ProfilerConfig {

impl Default for ProfilerConfig {
fn default() -> Self {
let cache_dir = temp_dir().join("lightswitch");
Self {
cache_dir,
libbpf_debug: false,
bpf_logging: false,
duration: Duration::MAX,
Expand Down Expand Up @@ -288,6 +293,25 @@ impl Profiler {
}

pub fn new(profiler_config: ProfilerConfig, stop_signal_receive: Receiver<()>) -> Self {
debug!("Cache directory {}", profiler_config.cache_dir.display());
if let Err(e) = fs::create_dir(&profiler_config.cache_dir) {
if e.kind() != ErrorKind::AlreadyExists {
error!(
"could not create cache dir at {}",
profiler_config.cache_dir.display()
);
}
}
let unwind_cache_dir = profiler_config.cache_dir.join("unwind-info").to_path_buf();
if let Err(e) = fs::create_dir(&unwind_cache_dir) {
if e.kind() != ErrorKind::AlreadyExists {
error!(
"could not create cache dir at {}",
unwind_cache_dir.display()
);
}
}

let mut native_unwinder_open_object = ManuallyDrop::new(Box::new(MaybeUninit::uninit()));
let mut tracers_open_object = ManuallyDrop::new(Box::new(MaybeUninit::uninit()));

Expand Down Expand Up @@ -387,6 +411,7 @@ impl Profiler {
native_unwind_info_bucket_sizes: profiler_config.native_unwind_info_bucket_sizes,
debug_info_manager: profiler_config.debug_info_manager,
max_native_unwind_info_size_mb: profiler_config.max_native_unwind_info_size_mb,
unwind_info_manager: UnwindInfoManager::new(&unwind_cache_dir, None),
}
}

Expand Down Expand Up @@ -430,7 +455,7 @@ impl Profiler {
match perf_buffer.poll(Duration::from_millis(100)) {
Ok(_) => {}
Err(err) => {
if err.kind() != ErrorKind::Interrupted {
if err.kind() != libbpf_rs::ErrorKind::Interrupted {
error!("polling events perf buffer failed with {:?}", err);
break;
}
Expand Down Expand Up @@ -459,7 +484,7 @@ impl Profiler {
match tracers_events_perf_buffer.poll(Duration::from_millis(100)) {
Ok(_) => {}
Err(err) => {
if err.kind() != ErrorKind::Interrupted {
if err.kind() != libbpf_rs::ErrorKind::Interrupted {
error!("polling tracers perf buffer failed with {:?}", err);
break;
}
Expand Down Expand Up @@ -1257,32 +1282,34 @@ impl Profiler {
)
.entered();

let unwind_info: Vec<CompactUnwindRow> =
match compact_unwind_info(&executable_path_open.to_string_lossy()) {
Ok(unwind_info) => unwind_info,
Err(e) => {
let executable_path_str = executable_path;
let known_naughty = executable_path_str.contains("libicudata");

// tracing doesn't support a level chosen at runtime: https://github.com/tokio-rs/tracing/issues/2730
if known_naughty {
debug!(
"failed to get unwind information for {} with {}",
executable_path_str, e
);
} else {
info!(
"failed to get unwind information for {} with {}",
executable_path_str, e
);
let unwind_info = self
.unwind_info_manager
.fetch_unwind_info(&executable_path_open, executable_id);
let unwind_info: Vec<CompactUnwindRow> = match unwind_info {
Ok(unwind_info) => unwind_info,
Err(e) => {
let executable_path_str = executable_path;
let known_naughty = executable_path_str.contains("libicudata");

// tracing doesn't support a level chosen at runtime: https://github.com/tokio-rs/tracing/issues/2730
if known_naughty {
debug!(
"failed to get unwind information for {} with {}",
executable_path_str, e
);
} else {
info!(
"failed to get unwind information for {} with {}",
executable_path_str, e
);

if let Err(e) = log_unwind_info_sections(&executable_path_open) {
warn!("log_unwind_info_sections failed with {}", e);
}
if let Err(e) = log_unwind_info_sections(&executable_path_open) {
warn!("log_unwind_info_sections failed with {}", e);
}
return;
}
};
return;
}
};
span.exit();

let bucket =
Expand Down Expand Up @@ -1536,7 +1563,7 @@ impl Profiler {
let object_file = match ObjectFile::new(&PathBuf::from(abs_path.clone())) {
Ok(f) => f,
Err(e) => {
warn!("object_file {} failed with {:?}", abs_path, e);
warn!("object_file {} failed with {}", abs_path, e);
// Rather than returning here, we prefer to be able to profile some
// parts of the binary
continue;
Expand Down
Loading