aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_prof
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_prof')
-rw-r--r--crates/ra_prof/Cargo.toml3
-rw-r--r--crates/ra_prof/src/google_cpu_profiler.rs39
-rw-r--r--crates/ra_prof/src/lib.rs32
3 files changed, 62 insertions, 12 deletions
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
9once_cell = "0.2.0" 9once_cell = "0.2.0"
10itertools = "0.8.0" 10itertools = "0.8.0"
11backtrace = "0.3.28" 11backtrace = "0.3.28"
12cpuprofiler = { version = "0.0.3", optional = true }
13jemallocator = { version = "0.3.2", optional = true } 12jemallocator = { version = "0.3.2", optional = true }
14jemalloc-ctl = { version = "0.3.2", optional = true } 13jemalloc-ctl = { version = "0.3.2", optional = true }
15 14
16
17[features] 15[features]
18jemalloc = [ "jemallocator", "jemalloc-ctl" ] 16jemalloc = [ "jemallocator", "jemalloc-ctl" ]
17cpu_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 @@
1//! https://github.com/gperftools/gperftools
2
3use std::{
4 ffi::CString,
5 os::raw::c_char,
6 path::Path,
7 sync::atomic::{AtomicUsize, Ordering},
8};
9
10#[link(name = "profiler")]
11#[allow(non_snake_case)]
12extern "C" {
13 fn ProfilerStart(fname: *const c_char) -> i32;
14 fn ProfilerStop();
15}
16
17static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF);
18const OFF: usize = 0;
19const ON: usize = 1;
20const PENDING: usize = 2;
21
22pub fn start(path: &Path) {
23 if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF {
24 panic!("profiler already started");
25 }
26 let path = CString::new(path.display().to_string()).unwrap();
27 if unsafe { ProfilerStart(path.as_ptr()) } == 0 {
28 panic!("profiler failed to start")
29 }
30 assert!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING);
31}
32
33pub fn stop() {
34 if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON {
35 panic!("profiler is not started")
36 }
37 unsafe { ProfilerStop() };
38 assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING);
39}
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 @@
1mod memory_usage; 1mod memory_usage;
2#[cfg(feature = "cpu_profiler")]
3mod google_cpu_profiler;
2 4
3use std::{ 5use std::{
4 cell::RefCell, 6 cell::RefCell,
@@ -268,25 +270,35 @@ impl Drop for Scope {
268 } 270 }
269} 271}
270 272
271/// A wrapper around https://github.com/AtheMathmo/cpuprofiler 273/// A wrapper around google_cpu_profiler.
272/// 274///
273/// It can be used to capture sampling profiles of sections of code. 275/// Usage:
274/// It is not exactly out-of-the-box, as it relies on gperftools. 276/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro.
275/// See the docs for the crate for more! 277/// 2. Build with `cpu_profiler` feature.
278/// 3. Tun the code, the *raw* output would be in the `./out.profile` file.
279/// 4. Install pprof for visualization (https://github.com/google/pprof).
280/// 5. Use something like `pprof -svg target/release/ra_cli ./out.profile` to see the results.
281///
282/// For example, here's how I run profiling on NixOS:
283///
284/// ```bash
285/// $ nix-shell -p gperftools --run \
286/// 'cargo run --release -p ra_cli -- parse < ~/projects/rustbench/parser.rs > /dev/null'
287/// ```
276#[derive(Debug)] 288#[derive(Debug)]
277pub struct CpuProfiler { 289pub struct CpuProfiler {
278 _private: (), 290 _private: (),
279} 291}
280 292
281pub fn cpu_profiler() -> CpuProfiler { 293pub fn cpu_profiler() -> CpuProfiler {
282 #[cfg(feature = "cpuprofiler")] 294 #[cfg(feature = "cpu_profiler")]
283 { 295 {
284 cpuprofiler::PROFILER.lock().unwrap().start("./out.profile").unwrap(); 296 google_cpu_profiler::start("./out.profile".as_ref())
285 } 297 }
286 298
287 #[cfg(not(feature = "cpuprofiler"))] 299 #[cfg(not(feature = "cpu_profiler"))]
288 { 300 {
289 eprintln!("cpuprofiler feature is disabled") 301 eprintln!("cpu_profiler feature is disabled")
290 } 302 }
291 303
292 CpuProfiler { _private: () } 304 CpuProfiler { _private: () }
@@ -294,9 +306,9 @@ pub fn cpu_profiler() -> CpuProfiler {
294 306
295impl Drop for CpuProfiler { 307impl Drop for CpuProfiler {
296 fn drop(&mut self) { 308 fn drop(&mut self) {
297 #[cfg(feature = "cpuprofiler")] 309 #[cfg(feature = "cpu_profiler")]
298 { 310 {
299 cpuprofiler::PROFILER.lock().unwrap().stop().unwrap(); 311 google_cpu_profiler::stop()
300 } 312 }
301 } 313 }
302} 314}