From e546275a5dc069489bbe3689090641d1ca1394a4 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Mon, 9 May 2022 17:03:27 +0800 Subject: [PATCH 1/6] add custom demangler Signed-off-by: YangKeao --- Cargo.toml | 2 +- src/frames.rs | 7 +++++++ src/report.rs | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54f52bc1..c5e4cf3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ backtrace = { version = "0.3", optional = true } once_cell = "1.9" libc = "^0.2.66" log = "0.4" -nix = { version = "0.24", default-features = false, features = ["signal"] } +nix = { version = "0.24", default-features = false, features = ["signal", "fs"] } parking_lot = "0.12" tempfile = "3.1" thiserror = "1.0" diff --git a/src/frames.rs b/src/frames.rs index 83ed61a9..e18c337e 100644 --- a/src/frames.rs +++ b/src/frames.rs @@ -104,6 +104,13 @@ impl Symbol { } pub fn name(&self) -> String { + self.name_with_demangle(demangle) + } + + pub fn name_with_demangle(&self, demangle: T) -> String + where + T: Fn(&str) -> Cow + 'static, + { demangle(&String::from_utf8_lossy(self.raw_name())).into_owned() } diff --git a/src/report.rs b/src/report.rs index a19b940e..d41e664f 100644 --- a/src/report.rs +++ b/src/report.rs @@ -1,9 +1,11 @@ // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. +use std::borrow::Cow; use std::collections::HashMap; use std::fmt::{Debug, Formatter}; use parking_lot::RwLock; +use symbolic_demangle::demangle; use crate::frames::{Frames, UnresolvedFrames}; use crate::profiler::Profiler; @@ -32,6 +34,8 @@ pub struct UnresolvedReport { /// A builder of `Report` and `UnresolvedReport`. It builds report from a running `Profiler`. pub struct ReportBuilder<'a> { frames_post_processor: Option>, + demangle: Box Cow>, + profiler: &'a RwLock>, timing: ReportTiming, } @@ -40,6 +44,8 @@ impl<'a> ReportBuilder<'a> { pub(crate) fn new(profiler: &'a RwLock>, timing: ReportTiming) -> Self { Self { frames_post_processor: None, + demangle: Box::new(demangle), + profiler, timing, } @@ -57,6 +63,29 @@ impl<'a> ReportBuilder<'a> { self } + /// Set `demangle` of a `ReportBuilder`. Before finally building a report, + /// `demangle` will be applied to every symbol. + /// # Examples + /// + /// ``` + /// # use std::borrow::Cow; + /// fn demangle(symbol:&str) -> Cow<'_, str> { + /// println!("demangling {}", symbol); + /// Cow::from(symbol) + /// }; + /// + /// let guard = pprof::ProfilerGuard::new(100).unwrap(); + /// guard.report().demangle(demangle).build().unwrap(); + /// ``` + pub fn demangle(&mut self, demangle: T) -> &mut Self + where + T: Fn(&str) -> Cow + 'static, + { + self.demangle = Box::new(demangle); + + self + } + /// Build an `UnresolvedReport` pub fn build_unresolved(&self) -> Result { let mut hash_map = HashMap::new(); @@ -232,7 +261,7 @@ mod protobuf { dedup_str.insert(key.thread_name_or_id()); for frame in key.frames.iter() { for symbol in frame { - dedup_str.insert(symbol.name()); + dedup_str.insert(symbol.name_with_demangle(&self.demangle)); dedup_str.insert(symbol.sys_name().into_owned()); dedup_str.insert(symbol.filename().into_owned()); } @@ -260,7 +289,7 @@ mod protobuf { let mut locs = vec![]; for frame in key.frames.iter() { for symbol in frame { - let name = symbol.name(); + let name = symbol.name_with_demangle(&self.demangle); if let Some(loc_idx) = functions.get(&name) { locs.push(*loc_idx); continue; From 421c110fcd7bf86f4c2158b05bbc7e7ec124bc54 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Tue, 10 May 2022 14:43:17 +0800 Subject: [PATCH 2/6] move the demangler settings to the report builder Signed-off-by: YangKeao --- src/frames.rs | 69 ++++++++++++++++++++++++++++----------------------- src/report.rs | 7 +++--- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/frames.rs b/src/frames.rs index e18c337e..34c619cf 100644 --- a/src/frames.rs +++ b/src/frames.rs @@ -86,7 +86,10 @@ impl Hash for UnresolvedFrames { #[derive(Debug, Clone)] pub struct Symbol { /// This name is raw name of a symbol (which hasn't been demangled). - pub name: Option>, + pub raw_name: Option>, + + /// This name is demangled name of a symbol. + pub name: Option, /// The address of the function. It is not 100% trustworthy. pub addr: Option<*mut c_void>, @@ -100,18 +103,11 @@ pub struct Symbol { impl Symbol { pub fn raw_name(&self) -> &[u8] { - self.name.as_deref().unwrap_or(b"Unknown") - } - - pub fn name(&self) -> String { - self.name_with_demangle(demangle) + self.raw_name.as_deref().unwrap_or(b"Unknown") } - pub fn name_with_demangle(&self, demangle: T) -> String - where - T: Fn(&str) -> Cow + 'static, - { - demangle(&String::from_utf8_lossy(self.raw_name())).into_owned() + pub fn name(&self) -> &str { + self.name.as_deref().unwrap_or("Unknown") } pub fn sys_name(&self) -> Cow { @@ -137,8 +133,24 @@ where T: crate::backtrace::Symbol, { fn from(symbol: &T) -> Self { + Self::from_with_demangle(symbol, demangle) + } +} + +impl Symbol { + pub fn from_with_demangle(symbol: &T, demangle: F) -> Self + where + T: crate::backtrace::Symbol, + F: Fn(&str) -> Cow, + { + let raw_name = symbol.name(); + let name = symbol + .name() + .map(|name| demangle(&String::from_utf8_lossy(&name)).to_string()); + Symbol { - name: symbol.name(), + raw_name, + name, addr: symbol.addr(), lineno: symbol.lineno(), filename: symbol.filename(), @@ -186,6 +198,15 @@ impl Frames { impl From for Frames { fn from(frames: UnresolvedFrames) -> Self { + Self::from_with_demangle(frames, demangle) + } +} + +impl Frames { + pub fn from_with_demangle(frames: UnresolvedFrames, demangle: F) -> Self + where + F: Fn(&str) -> Cow + Copy, + { let mut fs = Vec::new(); let mut frame_iter = frames.frames.iter(); @@ -194,7 +215,7 @@ impl From for Frames { let mut symbols: Vec = Vec::new(); frame.resolve_symbol(|symbol| { - let symbol = Symbol::from(symbol); + let symbol = Symbol::from_with_demangle(symbol, demangle); symbols.push(symbol); }); @@ -246,31 +267,17 @@ mod tests { #[test] fn demangle_rust() { - let symbol = Symbol { - name: Some(b"_ZN3foo3barE".to_vec()), - addr: None, - lineno: None, - filename: None, - }; - - assert_eq!(&symbol.name(), "foo::bar") + let demangled = demangle("_ZN3foo3barE"); + assert_eq!(demangled, "foo::bar") } #[test] fn demangle_cpp() { let name = - b"_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_" - .to_vec(); - - let symbol = Symbol { - name: Some(name), - addr: None, - lineno: None, - filename: None, - }; + "_ZNK3MapI10StringName3RefI8GDScriptE10ComparatorIS0_E16DefaultAllocatorE3hasERKS0_"; assert_eq!( - &symbol.name(), + demangle(name), "Map, Comparator, DefaultAllocator>::has(StringName const&) const" ) } diff --git a/src/report.rs b/src/report.rs index d41e664f..364e66ba 100644 --- a/src/report.rs +++ b/src/report.rs @@ -137,7 +137,8 @@ impl<'a> ReportBuilder<'a> { profiler.data.try_iter()?.for_each(|entry| { let count = entry.count; if count > 0 { - let mut key = Frames::from(entry.item.clone()); + let mut key = + Frames::from_with_demangle(entry.item.clone(), &self.demangle); if let Some(processor) = &self.frames_post_processor { processor(&mut key); } @@ -261,7 +262,7 @@ mod protobuf { dedup_str.insert(key.thread_name_or_id()); for frame in key.frames.iter() { for symbol in frame { - dedup_str.insert(symbol.name_with_demangle(&self.demangle)); + dedup_str.insert(symbol.name()); dedup_str.insert(symbol.sys_name().into_owned()); dedup_str.insert(symbol.filename().into_owned()); } @@ -289,7 +290,7 @@ mod protobuf { let mut locs = vec![]; for frame in key.frames.iter() { for symbol in frame { - let name = symbol.name_with_demangle(&self.demangle); + let name = symbol.name(); if let Some(loc_idx) = functions.get(&name) { locs.push(*loc_idx); continue; From 101ca50840e8385b85b7142878297de187e8d288 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Thu, 19 May 2022 01:57:23 +0800 Subject: [PATCH 3/6] fix clippy Signed-off-by: YangKeao --- src/frames.rs | 2 +- src/report.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frames.rs b/src/frames.rs index 34c619cf..9b6258c4 100644 --- a/src/frames.rs +++ b/src/frames.rs @@ -160,7 +160,7 @@ impl Symbol { impl Display for Symbol { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str(&self.name()) + f.write_str(self.name()) } } diff --git a/src/report.rs b/src/report.rs index 364e66ba..3de6861b 100644 --- a/src/report.rs +++ b/src/report.rs @@ -262,7 +262,7 @@ mod protobuf { dedup_str.insert(key.thread_name_or_id()); for frame in key.frames.iter() { for symbol in frame { - dedup_str.insert(symbol.name()); + dedup_str.insert(symbol.name().to_string()); dedup_str.insert(symbol.sys_name().into_owned()); dedup_str.insert(symbol.filename().into_owned()); } @@ -301,7 +301,7 @@ mod protobuf { let function_id = fn_tbl.len() as u64 + 1; let function = protos::Function { id: function_id, - name: *strings.get(name.as_str()).unwrap() as i64, + name: *strings.get(name).unwrap() as i64, system_name: *strings.get(sys_name.as_ref()).unwrap() as i64, filename: *strings.get(filename.as_ref()).unwrap() as i64, ..protos::Function::default() From 503b1ebc66f4dff2a355b1727332c4d68ee31cd8 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Thu, 19 May 2022 01:59:03 +0800 Subject: [PATCH 4/6] keep compatibility Signed-off-by: YangKeao --- src/frames.rs | 6 +++--- src/report.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/frames.rs b/src/frames.rs index 9b6258c4..59841b4b 100644 --- a/src/frames.rs +++ b/src/frames.rs @@ -106,8 +106,8 @@ impl Symbol { self.raw_name.as_deref().unwrap_or(b"Unknown") } - pub fn name(&self) -> &str { - self.name.as_deref().unwrap_or("Unknown") + pub fn name(&self) -> String { + self.name.as_deref().unwrap_or("Unknown").to_string() } pub fn sys_name(&self) -> Cow { @@ -160,7 +160,7 @@ impl Symbol { impl Display for Symbol { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.write_str(self.name()) + f.write_str(&self.name()) } } diff --git a/src/report.rs b/src/report.rs index 3de6861b..364e66ba 100644 --- a/src/report.rs +++ b/src/report.rs @@ -262,7 +262,7 @@ mod protobuf { dedup_str.insert(key.thread_name_or_id()); for frame in key.frames.iter() { for symbol in frame { - dedup_str.insert(symbol.name().to_string()); + dedup_str.insert(symbol.name()); dedup_str.insert(symbol.sys_name().into_owned()); dedup_str.insert(symbol.filename().into_owned()); } @@ -301,7 +301,7 @@ mod protobuf { let function_id = fn_tbl.len() as u64 + 1; let function = protos::Function { id: function_id, - name: *strings.get(name).unwrap() as i64, + name: *strings.get(name.as_str()).unwrap() as i64, system_name: *strings.get(sys_name.as_ref()).unwrap() as i64, filename: *strings.get(filename.as_ref()).unwrap() as i64, ..protos::Function::default() From a5b1ae8244c23d8a349e2cf1d931cf9fc4063ca2 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Thu, 19 May 2022 02:00:01 +0800 Subject: [PATCH 5/6] support custom demangler Signed-off-by: YangKeao --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a383f25b..ee011266 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Support custom demangler (#126) + ## [0.9.0] - 2022-05-09 ### Added From 55b3ed20ecc57e736b62ed38f9927d3135d03a41 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Mon, 30 May 2022 13:49:54 +0800 Subject: [PATCH 6/6] add CHANGELOG Signed-off-by: YangKeao --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10b68860..29461e48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- Add `demangle` setter to the `ReportBuilder` to allow using custom demangler (#126) + ### Changed - Remove `backtrace-rs` feature, as the default choice when not specified (#130)