From e97cc342669d2f1ca909d32a82f7a6dbcf41cd8d Mon Sep 17 00:00:00 2001 From: Yang Keao Date: Tue, 15 Dec 2020 17:28:37 +0800 Subject: [PATCH 1/5] implement heap profiler Signed-off-by: Yang Keao --- Cargo.toml | 6 +- examples/heap_profiler.rs | 43 ++++++++++ profile.pb | Bin 0 -> 9455 bytes src/collector.rs | 34 ++++++++ src/heap_profiler.rs | 166 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 + src/profiler.rs | 12 +-- src/report.rs | 3 +- 8 files changed, 259 insertions(+), 9 deletions(-) create mode 100644 examples/heap_profiler.rs create mode 100644 profile.pb create mode 100644 src/heap_profiler.rs diff --git a/Cargo.toml b/Cargo.toml index b583473d..65be5ce7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,9 @@ lazy_static = "1.4" libc = "^0.2.66" log = "0.4" nix = "0.19" -parking_lot = "0.11" tempfile = "3.1" thiserror = "1.0" +spin = "0.7" inferno = { version = "0.10", default-features = false, features = ["nameattr"], optional = true } prost = { version = "0.6", optional = true } @@ -53,6 +53,10 @@ required-features = ["protobuf"] name = "multithread_flamegraph" required-features = ["flamegraph"] +[[example]] +name = "heap_profiler" +required-features = ["protobuf", "flamegraph"] + [[bench]] name = "collector" path = "benches/collector.rs" diff --git a/examples/heap_profiler.rs b/examples/heap_profiler.rs new file mode 100644 index 00000000..e82c1825 --- /dev/null +++ b/examples/heap_profiler.rs @@ -0,0 +1,43 @@ +// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. + +use pprof::AllocRecorder; +use pprof::protos::Message; +use std::alloc::System; +use std::fs::File; +use std::io::Write; + +#[global_allocator] +static ALLOC: AllocRecorder = AllocRecorder::new(System); + +fn main() { + let guard = ALLOC.profile().unwrap(); + + memory_leak(65536); + + match guard.report().build() { + Ok(report) => { + let mut file = File::create("profile.pb").unwrap(); + let profile = report.pprof().unwrap(); + + let mut content = Vec::new(); + profile.encode(&mut content).unwrap(); + file.write_all(&content).unwrap(); + + let file = File::create("flamegraph.svg").unwrap(); + report.flamegraph(file).unwrap(); + + println!("{:?}", report); + } + Err(_) => {} + }; +} + +fn memory_leak(size: usize) { + let b = Box::new(vec![0; size]); + Box::leak(b); + + if size > 0 { + memory_leak(size / 2); + memory_leak(size / 2); + } +} \ No newline at end of file diff --git a/profile.pb b/profile.pb new file mode 100644 index 0000000000000000000000000000000000000000..97e7cf22bc942778ba3c1690c1b6ef235f83ac53 GIT binary patch literal 9455 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 WVfC42c^Z6bGT80X=^*LGo&Nw3R*$Fv literal 0 HcmV?d00001 diff --git a/src/collector.rs b/src/collector.rs index c77a7eae..ee56477c 100644 --- a/src/collector.rs +++ b/src/collector.rs @@ -342,6 +342,40 @@ mod tests { } } + #[test] + fn collector_minus_test() { + let mut collector = Collector::new().unwrap(); + let mut real_map = BTreeMap::new(); + + for item in 0..(1 << 12) * 4 { + for _ in 0..(item % 4) { + collector.add(item, 2).unwrap(); + } + } + + for item in 0..(1 << 12) * 4 { + for _ in 0..(item % 4) { + collector.add(item, -1).unwrap(); + } + } + + collector.try_iter().unwrap().for_each(|entry| { + add_map(&mut real_map, &entry); + }); + + for item in 0..(1 << 12) * 4 { + let count = (item % 4) as isize; + match real_map.get(&item) { + Some(value) => { + assert_eq!(count, *value); + } + None => { + assert_eq!(count, 0); + } + } + } + } + extern "C" { static mut __malloc_hook: Option *mut c_void>; diff --git a/src/heap_profiler.rs b/src/heap_profiler.rs new file mode 100644 index 00000000..9e873902 --- /dev/null +++ b/src/heap_profiler.rs @@ -0,0 +1,166 @@ +// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. + +use std::alloc::{GlobalAlloc, Layout}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::ops::Deref; + +use backtrace::Frame; +use spin::RwLock; + +use crate::MAX_DEPTH; +use crate::Result; +use crate::profiler::Profiler; +use crate::Error; +use crate::ReportBuilder; + +lazy_static::lazy_static! { + pub(crate) static ref HEAP_PROFILER: RwLock> = RwLock::new(Profiler::new()); +} + +pub struct AllocRecorder { + inner: T, + profiling: AtomicBool, +} + +impl AllocRecorder { + pub const fn new(inner: T) -> AllocRecorder { + AllocRecorder { + inner, + profiling: AtomicBool::new(false), + } + } + + pub fn profile(&self) -> Result> { + match HEAP_PROFILER.write().as_mut() { + Err(err) => { + log::error!("Error in creating profiler: {}", err); + return Err(Error::CreatingError) + } + Ok(profiler) => match profiler.start() { + Ok(()) => { + self.start(); + + Ok(HeapProfilerGuard::<'static, '_, T> { + profiler: &HEAP_PROFILER, + alloc: self, + }) + }, + Err(err) => Err(err), + }, + } + } + + pub(crate) fn start(&self) { + self.profiling.store(true, Ordering::SeqCst) + } + + pub(crate) fn stop(&self) { + self.profiling.store(false, Ordering::SeqCst) + } +} + +pub struct HeapReportBuilder<'a, 'b, 'c, T: GlobalAlloc> { + report_builder: ReportBuilder<'a>, + guard: &'a HeapProfilerGuard<'b, 'c, T>, +} + +impl Drop for HeapReportBuilder<'_, '_, '_, T> { + fn drop(&mut self) { + self.guard.alloc.start() + } +} + +impl<'a, T: GlobalAlloc> Deref for HeapReportBuilder<'a, '_, '_, T> { + type Target = ReportBuilder<'a>; + + fn deref(&self) -> &Self::Target { + &self.report_builder + } +} + +pub struct HeapProfilerGuard<'a, 'b, T: GlobalAlloc> { + profiler: &'a RwLock>, + alloc: &'b AllocRecorder +} + +impl HeapProfilerGuard<'_, '_, T> { + /// Generate a report + pub fn report(&self) -> HeapReportBuilder<'_, '_, '_, T> { + self.alloc.stop(); + + HeapReportBuilder { + report_builder: ReportBuilder::new(&self.profiler), + guard: &self + } + } +} + +impl Drop for HeapProfilerGuard<'_, '_, T> { + fn drop(&mut self) { + self.alloc.stop(); + + match self.profiler.write().as_mut() { + Err(_) => {} + Ok(profiler) => match profiler.init() { + Ok(()) => {} + Err(err) => log::error!("error while reinitializing profiler {}", err), + }, + } + } +} + +unsafe impl GlobalAlloc for AllocRecorder { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if self.profiling.load(Ordering::SeqCst) { + let mut guard = HEAP_PROFILER.write(); + if let Ok(profiler) = guard.as_mut() { + let mut bt: [Frame; MAX_DEPTH] = + std::mem::MaybeUninit::uninit().assume_init(); + let mut index = 0; + + backtrace::trace_unsynchronized(|frame| { + if index < MAX_DEPTH { + bt[index] = frame.clone(); + index += 1; + true + } else { + false + } + }); + + let size = (layout.size() + layout.align()) as isize; + profiler.sample(&bt[0..index], &[], 0, size); + } + } + + let ptr = self.inner.alloc(layout); + + ptr + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if self.profiling.load(Ordering::SeqCst) { + let mut guard = HEAP_PROFILER.write(); + if let Ok(profiler) = guard.as_mut() { + let mut bt: [Frame; MAX_DEPTH] = + std::mem::MaybeUninit::uninit().assume_init(); + let mut index = 0; + + backtrace::trace_unsynchronized(|frame| { + if index < MAX_DEPTH { + bt[index] = frame.clone(); + index += 1; + true + } else { + false + } + }); + + let size = (layout.size() + layout.align()) as isize; + profiler.sample(&bt[0..index], &[], 0, -size); + } + } + + self.inner.dealloc(ptr, layout); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index c0b0f22b..c8afe0f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,8 @@ //!}; //! ``` +#![feature(const_fn)] + /// Define the MAX supported stack depth. TODO: make this variable mutable. pub const MAX_DEPTH: usize = 32; @@ -33,12 +35,14 @@ mod frames; mod profiler; mod report; mod timer; +mod heap_profiler; 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::report::{Report, ReportBuilder}; +pub use self::heap_profiler::{AllocRecorder, HeapProfilerGuard}; #[cfg(feature = "protobuf")] pub mod protos { diff --git a/src/profiler.rs b/src/profiler.rs index 2a93d82b..05cabbf1 100644 --- a/src/profiler.rs +++ b/src/profiler.rs @@ -5,7 +5,7 @@ use std::os::raw::c_int; use backtrace::Frame; use nix::sys::signal; -use parking_lot::RwLock; +use spin::RwLock; use crate::collector::Collector; use crate::error::{Error, Result}; @@ -143,13 +143,13 @@ extern "C" fn perf_signal_handler(_signal: c_int) { write_thread_name(current_thread, &mut name); let name = unsafe { std::ffi::CStr::from_ptr(name_ptr) }; - profiler.sample(&bt[0..index], name.to_bytes(), current_thread as u64); + profiler.sample(&bt[0..index], name.to_bytes(), current_thread as u64, 1); } } } impl Profiler { - fn new() -> Result { + pub fn new() -> Result { Ok(Profiler { data: Collector::new()?, sample_counter: 0, @@ -171,7 +171,7 @@ impl Profiler { } } - fn init(&mut self) -> Result<()> { + pub(crate) fn init(&mut self) -> Result<()> { self.sample_counter = 0; self.data = Collector::new()?; self.running = false; @@ -206,11 +206,11 @@ impl Profiler { } // This function has to be AS-safe - pub fn sample(&mut self, backtrace: &[Frame], thread_name: &[u8], thread_id: u64) { + pub fn sample(&mut self, backtrace: &[Frame], thread_name: &[u8], thread_id: u64, count: isize) { let frames = UnresolvedFrames::new(backtrace, thread_name, thread_id); self.sample_counter += 1; - if let Ok(()) = self.data.add(frames, 1) {} + if let Ok(()) = self.data.add(frames, count) {} } } diff --git a/src/report.rs b/src/report.rs index 91082f4f..430a94ed 100644 --- a/src/report.rs +++ b/src/report.rs @@ -3,11 +3,10 @@ use std::collections::HashMap; use std::fmt::{Debug, Formatter}; -use parking_lot::RwLock; +use spin::RwLock; use crate::frames::{Frames, UnresolvedFrames}; use crate::profiler::Profiler; - use crate::{Error, Result}; /// The final presentation of a report which is actually an `HashMap` from `Frames` to isize (count). From 63dc9f2039f925ee8686945a5418f1114d863422 Mon Sep 17 00:00:00 2001 From: Yang Keao Date: Tue, 15 Dec 2020 17:37:31 +0800 Subject: [PATCH 2/5] remove example profile.pb Signed-off-by: Yang Keao --- profile.pb | Bin 9455 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 profile.pb diff --git a/profile.pb b/profile.pb deleted file mode 100644 index 97e7cf22bc942778ba3c1690c1b6ef235f83ac53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9455 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 WVfC42c^Z6bGT80X=^*LGo&Nw3R*$Fv From 6e662edeaf759ab98fb9be1a2ced651ecc2c090b Mon Sep 17 00:00:00 2001 From: Yang Keao Date: Tue, 15 Dec 2020 17:51:06 +0800 Subject: [PATCH 3/5] fix fmt and clippy Signed-off-by: Yang Keao --- examples/heap_profiler.rs | 4 ++-- src/heap_profiler.rs | 32 ++++++++++++++------------------ src/lib.rs | 4 ++-- src/profiler.rs | 8 +++++++- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/examples/heap_profiler.rs b/examples/heap_profiler.rs index e82c1825..35ae2cb1 100644 --- a/examples/heap_profiler.rs +++ b/examples/heap_profiler.rs @@ -1,7 +1,7 @@ // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. -use pprof::AllocRecorder; use pprof::protos::Message; +use pprof::AllocRecorder; use std::alloc::System; use std::fs::File; use std::io::Write; @@ -40,4 +40,4 @@ fn memory_leak(size: usize) { memory_leak(size / 2); memory_leak(size / 2); } -} \ No newline at end of file +} diff --git a/src/heap_profiler.rs b/src/heap_profiler.rs index 9e873902..3d0ffcbb 100644 --- a/src/heap_profiler.rs +++ b/src/heap_profiler.rs @@ -1,17 +1,17 @@ // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. use std::alloc::{GlobalAlloc, Layout}; -use std::sync::atomic::{AtomicBool, Ordering}; use std::ops::Deref; +use std::sync::atomic::{AtomicBool, Ordering}; use backtrace::Frame; use spin::RwLock; -use crate::MAX_DEPTH; -use crate::Result; use crate::profiler::Profiler; use crate::Error; use crate::ReportBuilder; +use crate::Result; +use crate::MAX_DEPTH; lazy_static::lazy_static! { pub(crate) static ref HEAP_PROFILER: RwLock> = RwLock::new(Profiler::new()); @@ -34,17 +34,17 @@ impl AllocRecorder { match HEAP_PROFILER.write().as_mut() { Err(err) => { log::error!("Error in creating profiler: {}", err); - return Err(Error::CreatingError) + Err(Error::CreatingError) } Ok(profiler) => match profiler.start() { Ok(()) => { self.start(); - + Ok(HeapProfilerGuard::<'static, '_, T> { profiler: &HEAP_PROFILER, alloc: self, }) - }, + } Err(err) => Err(err), }, } @@ -80,7 +80,7 @@ impl<'a, T: GlobalAlloc> Deref for HeapReportBuilder<'a, '_, '_, T> { pub struct HeapProfilerGuard<'a, 'b, T: GlobalAlloc> { profiler: &'a RwLock>, - alloc: &'b AllocRecorder + alloc: &'b AllocRecorder, } impl HeapProfilerGuard<'_, '_, T> { @@ -90,7 +90,7 @@ impl HeapProfilerGuard<'_, '_, T> { HeapReportBuilder { report_builder: ReportBuilder::new(&self.profiler), - guard: &self + guard: &self, } } } @@ -114,10 +114,9 @@ unsafe impl GlobalAlloc for AllocRecorder { if self.profiling.load(Ordering::SeqCst) { let mut guard = HEAP_PROFILER.write(); if let Ok(profiler) = guard.as_mut() { - let mut bt: [Frame; MAX_DEPTH] = - std::mem::MaybeUninit::uninit().assume_init(); + let mut bt: [Frame; MAX_DEPTH] = std::mem::MaybeUninit::uninit().assume_init(); let mut index = 0; - + backtrace::trace_unsynchronized(|frame| { if index < MAX_DEPTH { bt[index] = frame.clone(); @@ -133,19 +132,16 @@ unsafe impl GlobalAlloc for AllocRecorder { } } - let ptr = self.inner.alloc(layout); - - ptr + self.inner.alloc(layout) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { if self.profiling.load(Ordering::SeqCst) { let mut guard = HEAP_PROFILER.write(); if let Ok(profiler) = guard.as_mut() { - let mut bt: [Frame; MAX_DEPTH] = - std::mem::MaybeUninit::uninit().assume_init(); + let mut bt: [Frame; MAX_DEPTH] = std::mem::MaybeUninit::uninit().assume_init(); let mut index = 0; - + backtrace::trace_unsynchronized(|frame| { if index < MAX_DEPTH { bt[index] = frame.clone(); @@ -163,4 +159,4 @@ unsafe impl GlobalAlloc for AllocRecorder { self.inner.dealloc(ptr, layout); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index c8afe0f0..f1317065 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,17 +32,17 @@ pub const MAX_THREAD_NAME: usize = 16; mod collector; mod error; mod frames; +mod heap_profiler; mod profiler; mod report; mod timer; -mod heap_profiler; pub use self::collector::{Collector, StackHashCounter}; pub use self::error::{Error, Result}; pub use self::frames::{Frames, Symbol}; +pub use self::heap_profiler::{AllocRecorder, HeapProfilerGuard}; pub use self::profiler::ProfilerGuard; pub use self::report::{Report, ReportBuilder}; -pub use self::heap_profiler::{AllocRecorder, HeapProfilerGuard}; #[cfg(feature = "protobuf")] pub mod protos { diff --git a/src/profiler.rs b/src/profiler.rs index 05cabbf1..da8c00e4 100644 --- a/src/profiler.rs +++ b/src/profiler.rs @@ -206,7 +206,13 @@ impl Profiler { } // This function has to be AS-safe - pub fn sample(&mut self, backtrace: &[Frame], thread_name: &[u8], thread_id: u64, count: isize) { + pub fn sample( + &mut self, + backtrace: &[Frame], + thread_name: &[u8], + thread_id: u64, + count: isize, + ) { let frames = UnresolvedFrames::new(backtrace, thread_name, thread_id); self.sample_counter += 1; From 29852fbb3de95bf60eff4be316df09c55d07313f Mon Sep 17 00:00:00 2001 From: Yang Keao Date: Tue, 15 Dec 2020 17:59:52 +0800 Subject: [PATCH 4/5] support stable rust Signed-off-by: Yang Keao --- Cargo.toml | 3 ++- src/lib.rs | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 65be5ce7..d4c521d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ default = ["cpp"] flamegraph = ["inferno"] protobuf = ["prost", "prost-derive", "prost-build"] cpp = ["symbolic-demangle/cpp"] +heap = [] [dependencies] backtrace = "0.3" @@ -55,7 +56,7 @@ required-features = ["flamegraph"] [[example]] name = "heap_profiler" -required-features = ["protobuf", "flamegraph"] +required-features = ["protobuf", "flamegraph", "heap"] [[bench]] name = "collector" diff --git a/src/lib.rs b/src/lib.rs index f1317065..115b0ffe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ //!}; //! ``` -#![feature(const_fn)] +#![cfg_attr(feature = "heap", feature(const_fn))] /// Define the MAX supported stack depth. TODO: make this variable mutable. pub const MAX_DEPTH: usize = 32; @@ -32,7 +32,9 @@ pub const MAX_THREAD_NAME: usize = 16; mod collector; mod error; mod frames; +#[cfg(feature = "heap")] mod heap_profiler; + mod profiler; mod report; mod timer; @@ -40,7 +42,10 @@ mod timer; pub use self::collector::{Collector, StackHashCounter}; pub use self::error::{Error, Result}; pub use self::frames::{Frames, Symbol}; + +#[cfg(feature = "heap")] pub use self::heap_profiler::{AllocRecorder, HeapProfilerGuard}; + pub use self::profiler::ProfilerGuard; pub use self::report::{Report, ReportBuilder}; From 73924e20a0ea5ee5b00e9f0307d453cde4bfac8a Mon Sep 17 00:00:00 2001 From: Yang Keao Date: Tue, 15 Dec 2020 18:04:19 +0800 Subject: [PATCH 5/5] fix action Signed-off-by: Yang Keao --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ff117ca8..9ab3fe6b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,7 +32,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-features -- -D warnings + args: --features=protobuf,flamegraph -- -D warnings test: name: Test @@ -56,4 +56,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --all-features + args: --features=protobuf,flamegraph