aboutsummaryrefslogtreecommitdiff
path: root/crates/profile/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/profile/src/lib.rs')
-rw-r--r--crates/profile/src/lib.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs
new file mode 100644
index 000000000..ab19271c7
--- /dev/null
+++ b/crates/profile/src/lib.rs
@@ -0,0 +1,109 @@
1//! A collection of tools for profiling rust-analyzer.
2
3mod stop_watch;
4mod memory_usage;
5#[cfg(feature = "cpu_profiler")]
6mod google_cpu_profiler;
7mod hprof;
8mod tree;
9
10use std::cell::RefCell;
11
12pub use crate::{
13 hprof::{init, init_from, span},
14 memory_usage::{Bytes, MemoryUsage},
15 stop_watch::{StopWatch, StopWatchSpan},
16};
17
18/// Prints backtrace to stderr, useful for debugging.
19#[cfg(feature = "backtrace")]
20pub fn print_backtrace() {
21 let bt = backtrace::Backtrace::new();
22 eprintln!("{:?}", bt);
23}
24#[cfg(not(feature = "backtrace"))]
25pub fn print_backtrace() {
26 eprintln!(
27 r#"enable the backtrace feature:
28 profile = {{ path = "../profile", features = [ "backtrace"] }}
29"#
30 );
31}
32
33thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false));
34
35/// Allows to check if the current code is withing some dynamic scope, can be
36/// useful during debugging to figure out why a function is called.
37pub struct Scope {
38 prev: bool,
39}
40
41impl Scope {
42 #[must_use]
43 pub fn enter() -> Scope {
44 let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true));
45 Scope { prev }
46 }
47 pub fn is_active() -> bool {
48 IN_SCOPE.with(|slot| *slot.borrow())
49 }
50}
51
52impl Drop for Scope {
53 fn drop(&mut self) {
54 IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev);
55 }
56}
57
58/// A wrapper around google_cpu_profiler.
59///
60/// Usage:
61/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro.
62/// 2. Build with `cpu_profiler` feature.
63/// 3. Tun the code, the *raw* output would be in the `./out.profile` file.
64/// 4. Install pprof for visualization (https://github.com/google/pprof).
65/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000`
66/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results.
67///
68/// For example, here's how I run profiling on NixOS:
69///
70/// ```bash
71/// $ nix-shell -p gperftools --run \
72/// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null'
73/// ```
74///
75/// See this diff for how to profile completions:
76///
77/// https://github.com/rust-analyzer/rust-analyzer/pull/5306
78#[derive(Debug)]
79pub struct CpuSpan {
80 _private: (),
81}
82
83#[must_use]
84pub fn cpu_span() -> CpuSpan {
85 #[cfg(feature = "cpu_profiler")]
86 {
87 google_cpu_profiler::start("./out.profile".as_ref())
88 }
89
90 #[cfg(not(feature = "cpu_profiler"))]
91 {
92 eprintln!("cpu_profiler feature is disabled")
93 }
94
95 CpuSpan { _private: () }
96}
97
98impl Drop for CpuSpan {
99 fn drop(&mut self) {
100 #[cfg(feature = "cpu_profiler")]
101 {
102 google_cpu_profiler::stop()
103 }
104 }
105}
106
107pub fn memory_usage() -> MemoryUsage {
108 MemoryUsage::current()
109}