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/lib.rs2
-rw-r--r--crates/ra_prof/src/memory_usage.rs37
-rw-r--r--crates/ra_prof/src/stop_watch.rs86
4 files changed, 113 insertions, 15 deletions
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml
index 6c214501e..c82b9f76d 100644
--- a/crates/ra_prof/Cargo.toml
+++ b/crates/ra_prof/Cargo.toml
@@ -16,6 +16,9 @@ backtrace = { version = "0.3.44", optional = true }
16cfg-if = "0.1.10" 16cfg-if = "0.1.10"
17libc = "0.2.73" 17libc = "0.2.73"
18 18
19[target.'cfg(target_os = "linux")'.dependencies]
20perf-event = "0.4"
21
19[features] 22[features]
20cpu_profiler = [] 23cpu_profiler = []
21 24
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index ba5609703..eb50965ae 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -1,5 +1,6 @@
1//! A collection of tools for profiling rust-analyzer. 1//! A collection of tools for profiling rust-analyzer.
2 2
3mod stop_watch;
3mod memory_usage; 4mod memory_usage;
4#[cfg(feature = "cpu_profiler")] 5#[cfg(feature = "cpu_profiler")]
5mod google_cpu_profiler; 6mod google_cpu_profiler;
@@ -11,6 +12,7 @@ use std::cell::RefCell;
11pub use crate::{ 12pub use crate::{
12 hprof::{init, init_from, profile}, 13 hprof::{init, init_from, profile},
13 memory_usage::{Bytes, MemoryUsage}, 14 memory_usage::{Bytes, MemoryUsage},
15 stop_watch::{StopWatch, StopWatchSpan},
14}; 16};
15 17
16/// Prints backtrace to stderr, useful for debugging. 18/// Prints backtrace to stderr, useful for debugging.
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs
index 745345fac..c2ecbd33c 100644
--- a/crates/ra_prof/src/memory_usage.rs
+++ b/crates/ra_prof/src/memory_usage.rs
@@ -3,9 +3,22 @@ use std::fmt;
3 3
4use cfg_if::cfg_if; 4use cfg_if::cfg_if;
5 5
6#[derive(Copy, Clone)]
6pub struct MemoryUsage { 7pub struct MemoryUsage {
7 pub allocated: Bytes, 8 pub allocated: Bytes,
8 pub resident: Bytes, 9}
10
11impl fmt::Display for MemoryUsage {
12 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
13 write!(fmt, "{}", self.allocated)
14 }
15}
16
17impl std::ops::Sub for MemoryUsage {
18 type Output = MemoryUsage;
19 fn sub(self, rhs: MemoryUsage) -> MemoryUsage {
20 MemoryUsage { allocated: self.allocated - rhs.allocated }
21 }
9} 22}
10 23
11impl MemoryUsage { 24impl MemoryUsage {
@@ -13,26 +26,20 @@ impl MemoryUsage {
13 cfg_if! { 26 cfg_if! {
14 if #[cfg(target_os = "linux")] { 27 if #[cfg(target_os = "linux")] {
15 // Note: This is incredibly slow. 28 // Note: This is incredibly slow.
16 let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as usize; 29 let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
17 MemoryUsage { allocated: Bytes(alloc), resident: Bytes(0) } 30 MemoryUsage { allocated: Bytes(alloc) }
18 } else { 31 } else {
19 MemoryUsage { allocated: Bytes(0), resident: Bytes(0) } 32 MemoryUsage { allocated: Bytes(0) }
20 } 33 }
21 } 34 }
22 } 35 }
23} 36}
24 37
25impl fmt::Display for MemoryUsage {
26 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
27 write!(fmt, "{} allocated {} resident", self.allocated, self.resident,)
28 }
29}
30
31#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] 38#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
32pub struct Bytes(usize); 39pub struct Bytes(isize);
33 40
34impl Bytes { 41impl Bytes {
35 pub fn megabytes(self) -> usize { 42 pub fn megabytes(self) -> isize {
36 self.0 / 1024 / 1024 43 self.0 / 1024 / 1024
37 } 44 }
38} 45}
@@ -42,10 +49,10 @@ impl fmt::Display for Bytes {
42 let bytes = self.0; 49 let bytes = self.0;
43 let mut value = bytes; 50 let mut value = bytes;
44 let mut suffix = "b"; 51 let mut suffix = "b";
45 if value > 4096 { 52 if value.abs() > 4096 {
46 value /= 1024; 53 value /= 1024;
47 suffix = "kb"; 54 suffix = "kb";
48 if value > 4096 { 55 if value.abs() > 4096 {
49 value /= 1024; 56 value /= 1024;
50 suffix = "mb"; 57 suffix = "mb";
51 } 58 }
@@ -56,7 +63,7 @@ impl fmt::Display for Bytes {
56 63
57impl std::ops::AddAssign<usize> for Bytes { 64impl std::ops::AddAssign<usize> for Bytes {
58 fn add_assign(&mut self, x: usize) { 65 fn add_assign(&mut self, x: usize) {
59 self.0 += x; 66 self.0 += x as isize;
60 } 67 }
61} 68}
62 69
diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs
new file mode 100644
index 000000000..5e276190e
--- /dev/null
+++ b/crates/ra_prof/src/stop_watch.rs
@@ -0,0 +1,86 @@
1//! Like `std::time::Instant`, but also measures memory & CPU cycles.
2use std::{
3 fmt,
4 time::{Duration, Instant},
5};
6
7use crate::MemoryUsage;
8
9pub struct StopWatch {
10 time: Instant,
11 #[cfg(target_os = "linux")]
12 counter: Option<perf_event::Counter>,
13 memory: Option<MemoryUsage>,
14}
15
16pub struct StopWatchSpan {
17 pub time: Duration,
18 pub instructions: Option<u64>,
19 pub memory: Option<MemoryUsage>,
20}
21
22impl StopWatch {
23 pub fn start() -> StopWatch {
24 #[cfg(target_os = "linux")]
25 let counter = {
26 let mut counter = perf_event::Builder::new()
27 .build()
28 .map_err(|err| eprintln!("Failed to create perf counter: {}", err))
29 .ok();
30 if let Some(counter) = &mut counter {
31 if let Err(err) = counter.enable() {
32 eprintln!("Failed to start perf counter: {}", err)
33 }
34 }
35 counter
36 };
37 let time = Instant::now();
38 StopWatch {
39 time,
40 #[cfg(target_os = "linux")]
41 counter,
42 memory: None,
43 }
44 }
45 pub fn memory(mut self, yes: bool) -> StopWatch {
46 if yes {
47 self.memory = Some(MemoryUsage::current());
48 }
49 self
50 }
51 pub fn elapsed(&mut self) -> StopWatchSpan {
52 let time = self.time.elapsed();
53
54 #[cfg(target_os = "linux")]
55 let instructions = self.counter.as_mut().and_then(|it| {
56 it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok()
57 });
58 #[cfg(not(target_os = "linux"))]
59 let instructions = None;
60
61 let memory = self.memory.map(|it| MemoryUsage::current() - it);
62 StopWatchSpan { time, instructions, memory }
63 }
64}
65
66impl fmt::Display for StopWatchSpan {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "{:.2?}", self.time)?;
69 if let Some(mut instructions) = self.instructions {
70 let mut prefix = "";
71 if instructions > 10000 {
72 instructions /= 1000;
73 prefix = "k"
74 }
75 if instructions > 10000 {
76 instructions /= 1000;
77 prefix = "m"
78 }
79 write!(f, ", {}{}i", instructions, prefix)?;
80 }
81 if let Some(memory) = self.memory {
82 write!(f, ", {}", memory)?;
83 }
84 Ok(())
85 }
86}