From e751e4d8a366de45b4afe311eedfadcc0a47435c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 17 Aug 2019 15:29:57 +0300 Subject: Remove cpuprofile dependencies --- crates/ra_cli/Cargo.toml | 2 +- crates/ra_prof/Cargo.toml | 3 +-- crates/ra_prof/src/google_cpu_profiler.rs | 39 +++++++++++++++++++++++++++++++ crates/ra_prof/src/lib.rs | 32 +++++++++++++++++-------- 4 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 crates/ra_prof/src/google_cpu_profiler.rs (limited to 'crates') diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index 970cb1f82..9c2ebdad2 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml @@ -18,5 +18,5 @@ ra_db = { path = "../ra_db" } [dependencies.ra_prof] path = "../ra_prof" -# features = [ "cpuprofiler" ] +# features = [ "cpu_profiler" ] # features = [ "jemalloc" ] diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index 84dcc9813..d35adeeeb 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml @@ -9,10 +9,9 @@ publish = false once_cell = "0.2.0" itertools = "0.8.0" backtrace = "0.3.28" -cpuprofiler = { version = "0.0.3", optional = true } jemallocator = { version = "0.3.2", optional = true } jemalloc-ctl = { version = "0.3.2", optional = true } - [features] jemalloc = [ "jemallocator", "jemalloc-ctl" ] +cpu_profiler = [] diff --git a/crates/ra_prof/src/google_cpu_profiler.rs b/crates/ra_prof/src/google_cpu_profiler.rs new file mode 100644 index 000000000..db865c65b --- /dev/null +++ b/crates/ra_prof/src/google_cpu_profiler.rs @@ -0,0 +1,39 @@ +//! https://github.com/gperftools/gperftools + +use std::{ + ffi::CString, + os::raw::c_char, + path::Path, + sync::atomic::{AtomicUsize, Ordering}, +}; + +#[link(name = "profiler")] +#[allow(non_snake_case)] +extern "C" { + fn ProfilerStart(fname: *const c_char) -> i32; + fn ProfilerStop(); +} + +static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF); +const OFF: usize = 0; +const ON: usize = 1; +const PENDING: usize = 2; + +pub fn start(path: &Path) { + if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF { + panic!("profiler already started"); + } + let path = CString::new(path.display().to_string()).unwrap(); + if unsafe { ProfilerStart(path.as_ptr()) } == 0 { + panic!("profiler failed to start") + } + assert!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING); +} + +pub fn stop() { + if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON { + panic!("profiler is not started") + } + unsafe { ProfilerStop() }; + assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING); +} diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index 6d44fef33..d32a289be 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs @@ -1,4 +1,6 @@ mod memory_usage; +#[cfg(feature = "cpu_profiler")] +mod google_cpu_profiler; use std::{ cell::RefCell, @@ -268,25 +270,35 @@ impl Drop for Scope { } } -/// A wrapper around https://github.com/AtheMathmo/cpuprofiler +/// A wrapper around google_cpu_profiler. /// -/// It can be used to capture sampling profiles of sections of code. -/// It is not exactly out-of-the-box, as it relies on gperftools. -/// See the docs for the crate for more! +/// Usage: +/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro. +/// 2. Build with `cpu_profiler` feature. +/// 3. Tun the code, the *raw* output would be in the `./out.profile` file. +/// 4. Install pprof for visualization (https://github.com/google/pprof). +/// 5. Use something like `pprof -svg target/release/ra_cli ./out.profile` to see the results. +/// +/// For example, here's how I run profiling on NixOS: +/// +/// ```bash +/// $ nix-shell -p gperftools --run \ +/// 'cargo run --release -p ra_cli -- parse < ~/projects/rustbench/parser.rs > /dev/null' +/// ``` #[derive(Debug)] pub struct CpuProfiler { _private: (), } pub fn cpu_profiler() -> CpuProfiler { - #[cfg(feature = "cpuprofiler")] + #[cfg(feature = "cpu_profiler")] { - cpuprofiler::PROFILER.lock().unwrap().start("./out.profile").unwrap(); + google_cpu_profiler::start("./out.profile".as_ref()) } - #[cfg(not(feature = "cpuprofiler"))] + #[cfg(not(feature = "cpu_profiler"))] { - eprintln!("cpuprofiler feature is disabled") + eprintln!("cpu_profiler feature is disabled") } CpuProfiler { _private: () } @@ -294,9 +306,9 @@ pub fn cpu_profiler() -> CpuProfiler { impl Drop for CpuProfiler { fn drop(&mut self) { - #[cfg(feature = "cpuprofiler")] + #[cfg(feature = "cpu_profiler")] { - cpuprofiler::PROFILER.lock().unwrap().stop().unwrap(); + google_cpu_profiler::stop() } } } -- cgit v1.2.3