Skip to content

Commit

Permalink
use a configurable option to set blacklist
Browse files Browse the repository at this point in the history
Signed-off-by: YangKeao <[email protected]>
  • Loading branch information
YangKeao committed Oct 29, 2021
1 parent 59bad74 commit 1b7b26c
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 63 deletions.
4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ default = ["cpp"]
flamegraph = ["inferno"]
protobuf = ["prost", "prost-derive", "prost-build"]
cpp = ["symbolic-demangle/cpp"]
ignore-libc = ["findshlibs"]

[dependencies]
backtrace = "0.3"
Expand All @@ -25,14 +24,13 @@ nix = "0.23"
parking_lot = "0.11"
tempfile = "3.1"
thiserror = "1.0"
findshlibs = "0.10"

inferno = { version = "0.10", default-features = false, features = ["nameattr"], optional = true }
prost = { version = "0.9", optional = true }
prost-derive = { version = "0.9", optional = true }
criterion = {version = "0.3", optional = true}

findshlibs = {version = "0.10", optional = true}

[dependencies.symbolic-demangle]
version = "8.0"
default-features = false
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ mod timer;
pub use self::collector::{Collector, StackHashCounter};
pub use self::error::{Error, Result};
pub use self::frames::{Frames, Symbol};
pub use self::profiler::ProfilerGuard;
pub use self::profiler::{ProfilerGuard, ProfilerGuardBuilder};
pub use self::report::{Report, ReportBuilder};

#[cfg(feature = "flamegraph")]
Expand Down
161 changes: 102 additions & 59 deletions src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use backtrace::Frame;
use nix::sys::signal;
use parking_lot::RwLock;

#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
use findshlibs::{Segment, SharedLibrary, TargetSharedLibrary};

use crate::collector::Collector;
Expand All @@ -27,10 +27,93 @@ pub struct Profiler {

running: bool,

#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
blacklist_segments: Vec<(usize, usize)>,
}

pub struct ProfilerGuardBuilder {
frequency: c_int,
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
blacklist_segments: Vec<(usize, usize)>,
}

impl Default for ProfilerGuardBuilder {
fn default() -> ProfilerGuardBuilder {
ProfilerGuardBuilder {
frequency: 99,

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
blacklist_segments: Vec::new(),
}
}
}

impl ProfilerGuardBuilder {
pub fn frequency(self, frequency: c_int) -> Self {
Self { frequency, ..self }
}
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub fn blacklist<T: AsRef<str>>(self, blacklist: &[T]) -> Self {
let blacklist_segments = {
let mut segments = Vec::new();
TargetSharedLibrary::each(|shlib| {
let in_blacklist = match shlib.name().to_str() {
Some(name) => {
let mut in_blacklist = false;
for blocked_name in blacklist.iter() {
if name.contains(blocked_name.as_ref()) {
in_blacklist = true;
}
}

in_blacklist
}

None => false,
};
if in_blacklist {
for seg in shlib.segments() {
let avam = seg.actual_virtual_memory_address(shlib);
let start = avam.0;
let end = start + seg.len();
segments.push((start, end));
}
}
});
segments
};

Self {
blacklist_segments,
..self
}
}
pub fn build(self) -> Result<ProfilerGuard<'static>> {
trigger_lazy();

match PROFILER.write().as_mut() {
Err(err) => {
log::error!("Error in creating profiler: {}", err);
Err(Error::CreatingError)
}
Ok(profiler) => {
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
{
profiler.blacklist_segments = self.blacklist_segments;
}

match profiler.start() {
Ok(()) => Ok(ProfilerGuard::<'static> {
profiler: &PROFILER,
timer: Some(Timer::new(self.frequency)),
}),
Err(err) => Err(err),
}
}
}
}
}

/// RAII structure used to stop profiling when dropped. It is the only interface to access profiler.
pub struct ProfilerGuard<'a> {
profiler: &'a RwLock<Result<Profiler>>,
Expand All @@ -45,21 +128,7 @@ fn trigger_lazy() {
impl ProfilerGuard<'_> {
/// Start profiling with given sample frequency.
pub fn new(frequency: c_int) -> Result<ProfilerGuard<'static>> {
trigger_lazy();

match PROFILER.write().as_mut() {
Err(err) => {
log::error!("Error in creating profiler: {}", err);
Err(Error::CreatingError)
}
Ok(profiler) => match profiler.start() {
Ok(()) => Ok(ProfilerGuard::<'static> {
profiler: &PROFILER,
timer: Some(Timer::new(frequency)),
}),
Err(err) => Err(err),
},
}
ProfilerGuardBuilder::default().frequency(frequency).build()
}

/// Generate a report
Expand All @@ -74,10 +143,17 @@ impl<'a> Drop for ProfilerGuard<'a> {

match self.profiler.write().as_mut() {
Err(_) => {}
Ok(profiler) => match profiler.stop() {
Ok(()) => {}
Err(err) => log::error!("error while stopping profiler {}", err),
},
Ok(profiler) => {
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
{
profiler.blacklist_segments = Vec::new();
}

match profiler.stop() {
Ok(()) => {}
Err(err) => log::error!("error while stopping profiler {}", err),
}
}
}
}
}
Expand Down Expand Up @@ -125,7 +201,7 @@ fn write_thread_name(current_thread: libc::pthread_t, name: &mut [libc::c_char])
#[no_mangle]
#[allow(clippy::uninit_assumed_init)]
#[cfg_attr(
not(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux")),
not(all(target_arch = "x86_64", target_os = "linux")),
allow(unused_variables)
)]
extern "C" fn perf_signal_handler(
Expand All @@ -135,7 +211,7 @@ extern "C" fn perf_signal_handler(
) {
if let Some(mut guard) = PROFILER.try_write() {
if let Ok(profiler) = guard.as_mut() {
#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
if !ucontext.is_null() {
let ucontext: *mut libc::ucontext_t = ucontext as *mut libc::ucontext_t;
let addr =
Expand Down Expand Up @@ -173,52 +249,19 @@ extern "C" fn perf_signal_handler(
}
}

#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
const SHLIB_BLACKLIST: [&str; 3] = ["libc", "libgcc_s", "libpthread"];

impl Profiler {
fn new() -> Result<Self> {
#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
let blacklist_segments = {
let mut segments = Vec::new();
TargetSharedLibrary::each(|shlib| {
let in_blacklist = match shlib.name().to_str() {
Some(name) => {
let mut in_blacklist = false;
for blocked_name in SHLIB_BLACKLIST.iter() {
if name.contains(blocked_name) {
in_blacklist = true;
}
}

in_blacklist
}

None => false,
};
if in_blacklist {
for seg in shlib.segments() {
let avam = seg.actual_virtual_memory_address(shlib);
let start = avam.0;
let end = start + seg.len();
segments.push((start, end));
}
}
});
segments
};

Ok(Profiler {
data: Collector::new()?,
sample_counter: 0,
running: false,

#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
blacklist_segments,
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
blacklist_segments: Vec::new(),
})
}

#[cfg(all(feature = "ignore-libc", target_arch = "x86_64", target_os = "linux"))]
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
fn is_blacklisted(&self, addr: usize) -> bool {
for libs in &self.blacklist_segments {
if addr > libs.0 && addr < libs.1 {
Expand Down

0 comments on commit 1b7b26c

Please sign in to comment.