From dae99b66611759ba48fd164646f077d3e8515dad Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 09:45:20 +0200 Subject: Drop resident from memory usage --- crates/ra_prof/src/memory_usage.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs index 745345fac..857b51321 100644 --- a/crates/ra_prof/src/memory_usage.rs +++ b/crates/ra_prof/src/memory_usage.rs @@ -5,7 +5,6 @@ use cfg_if::cfg_if; pub struct MemoryUsage { pub allocated: Bytes, - pub resident: Bytes, } impl MemoryUsage { @@ -14,9 +13,9 @@ impl MemoryUsage { if #[cfg(target_os = "linux")] { // Note: This is incredibly slow. let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as usize; - MemoryUsage { allocated: Bytes(alloc), resident: Bytes(0) } + MemoryUsage { allocated: Bytes(alloc) } } else { - MemoryUsage { allocated: Bytes(0), resident: Bytes(0) } + MemoryUsage { allocated: Bytes(0) } } } } @@ -24,7 +23,7 @@ impl MemoryUsage { impl fmt::Display for MemoryUsage { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{} allocated {} resident", self.allocated, self.resident,) + write!(fmt, "{}", self.allocated) } } -- cgit v1.2.3 From afab67e69c39027fb99878751309d4050324beef Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 09:47:16 +0200 Subject: Allow negative bytes Gotta be optimistic about those memory usage optimizations --- crates/ra_prof/src/memory_usage.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs index 857b51321..22b61e4a2 100644 --- a/crates/ra_prof/src/memory_usage.rs +++ b/crates/ra_prof/src/memory_usage.rs @@ -3,16 +3,30 @@ use std::fmt; use cfg_if::cfg_if; +#[derive(Copy, Clone)] pub struct MemoryUsage { pub allocated: Bytes, } +impl fmt::Display for MemoryUsage { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self.allocated) + } +} + +impl std::ops::Sub for MemoryUsage { + type Output = MemoryUsage; + fn sub(self, rhs: MemoryUsage) -> MemoryUsage { + MemoryUsage { allocated: self.allocated - rhs.allocated } + } +} + impl MemoryUsage { pub fn current() -> MemoryUsage { cfg_if! { if #[cfg(target_os = "linux")] { // Note: This is incredibly slow. - let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as usize; + let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as isize; MemoryUsage { allocated: Bytes(alloc) } } else { MemoryUsage { allocated: Bytes(0) } @@ -21,17 +35,11 @@ impl MemoryUsage { } } -impl fmt::Display for MemoryUsage { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{}", self.allocated) - } -} - #[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] -pub struct Bytes(usize); +pub struct Bytes(isize); impl Bytes { - pub fn megabytes(self) -> usize { + pub fn megabytes(self) -> isize { self.0 / 1024 / 1024 } } @@ -41,10 +49,10 @@ impl fmt::Display for Bytes { let bytes = self.0; let mut value = bytes; let mut suffix = "b"; - if value > 4096 { + if value.abs() > 4096 { value /= 1024; suffix = "kb"; - if value > 4096 { + if value.abs() > 4096 { value /= 1024; suffix = "mb"; } @@ -55,7 +63,7 @@ impl fmt::Display for Bytes { impl std::ops::AddAssign for Bytes { fn add_assign(&mut self, x: usize) { - self.0 += x; + self.0 += x as isize; } } -- cgit v1.2.3 From 4bab553029da31f3e90e99d8b83d160a34fdf4b2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 10:14:35 +0200 Subject: fix cast --- crates/ra_prof/src/memory_usage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs index 22b61e4a2..c2ecbd33c 100644 --- a/crates/ra_prof/src/memory_usage.rs +++ b/crates/ra_prof/src/memory_usage.rs @@ -26,7 +26,7 @@ impl MemoryUsage { cfg_if! { if #[cfg(target_os = "linux")] { // Note: This is incredibly slow. - let alloc = unsafe { libc::mallinfo() }.uordblks as u32 as isize; + let alloc = unsafe { libc::mallinfo() }.uordblks as isize; MemoryUsage { allocated: Bytes(alloc) } } else { MemoryUsage { allocated: Bytes(0) } -- cgit v1.2.3 From 7204374719f4021ce06c25e7dd72b09a56923954 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 09:44:21 +0200 Subject: Report instructions in addition to time They hopefully will be more stable on CI --- crates/ra_prof/Cargo.toml | 1 + crates/ra_prof/src/lib.rs | 2 ++ crates/ra_prof/src/stop_watch.rs | 72 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 crates/ra_prof/src/stop_watch.rs (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index 6c214501e..e41cb5f52 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml @@ -15,6 +15,7 @@ once_cell = "1.3.1" backtrace = { version = "0.3.44", optional = true } cfg-if = "0.1.10" libc = "0.2.73" +perf-event = "0.4" [features] cpu_profiler = [] 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 @@ //! A collection of tools for profiling rust-analyzer. +mod stop_watch; mod memory_usage; #[cfg(feature = "cpu_profiler")] mod google_cpu_profiler; @@ -11,6 +12,7 @@ use std::cell::RefCell; pub use crate::{ hprof::{init, init_from, profile}, memory_usage::{Bytes, MemoryUsage}, + stop_watch::{StopWatch, StopWatchSpan}, }; /// Prints backtrace to stderr, useful for debugging. diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs new file mode 100644 index 000000000..54bfb0559 --- /dev/null +++ b/crates/ra_prof/src/stop_watch.rs @@ -0,0 +1,72 @@ +use crate::MemoryUsage; +use std::{ + fmt, + time::{Duration, Instant}, +}; + +pub struct StopWatch { + time: Instant, + counter: Option, + memory: Option, +} + +pub struct StopWatchSpan { + pub time: Duration, + pub instructions: Option, + pub memory: Option, +} + +impl StopWatch { + pub fn start() -> StopWatch { + let mut counter = perf_event::Builder::new().build().ok(); + if let Some(counter) = &mut counter { + let _ = counter.enable(); + } + let time = Instant::now(); + StopWatch { time, counter, memory: None } + } + pub fn memory(mut self, yes: bool) -> StopWatch { + if yes { + self.memory = Some(MemoryUsage::current()); + } + self + } + pub fn elapsed(&mut self) -> StopWatchSpan { + let time = self.time.elapsed(); + let instructions = self.counter.as_mut().and_then(|it| it.read().ok()); + let memory = self.memory.map(|it| MemoryUsage::current() - it); + StopWatchSpan { time, instructions, memory } + } +} + +impl fmt::Display for StopWatchSpan { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:.2?}", self.time)?; + if let Some(mut instructions) = self.instructions { + let mut prefix = ""; + if instructions > 10000 { + instructions /= 1000; + prefix = "k" + } + if instructions > 10000 { + instructions /= 1000; + prefix = "m" + } + write!(f, ", {}{}i", instructions, prefix)?; + } + if let Some(memory) = self.memory { + write!(f, ", {}", memory)?; + } + Ok(()) + } +} + +// Unclear if we need this: +// https://github.com/jimblandy/perf-event/issues/8 +impl Drop for StopWatch { + fn drop(&mut self) { + if let Some(mut counter) = self.counter.take() { + let _ = counter.disable(); + } + } +} -- cgit v1.2.3 From 5e498546e8275c86e0b3f711b069b2787c6385f2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 10:40:55 +0200 Subject: Fix non-linux compilation --- crates/ra_prof/Cargo.toml | 2 ++ crates/ra_prof/src/stop_watch.rs | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index e41cb5f52..c82b9f76d 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml @@ -15,6 +15,8 @@ once_cell = "1.3.1" backtrace = { version = "0.3.44", optional = true } cfg-if = "0.1.10" libc = "0.2.73" + +[target.'cfg(target_os = "linux")'.dependencies] perf-event = "0.4" [features] diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs index 54bfb0559..c52c92ce5 100644 --- a/crates/ra_prof/src/stop_watch.rs +++ b/crates/ra_prof/src/stop_watch.rs @@ -1,11 +1,13 @@ -use crate::MemoryUsage; use std::{ fmt, time::{Duration, Instant}, }; +use crate::MemoryUsage; + pub struct StopWatch { time: Instant, + #[cfg(target_os = "linux")] counter: Option, memory: Option, } @@ -18,12 +20,21 @@ pub struct StopWatchSpan { impl StopWatch { pub fn start() -> StopWatch { - let mut counter = perf_event::Builder::new().build().ok(); - if let Some(counter) = &mut counter { - let _ = counter.enable(); - } + #[cfg(target_os = "linux")] + let counter = { + let mut counter = perf_event::Builder::new().build().ok(); + if let Some(counter) = &mut counter { + let _ = counter.enable(); + } + counter + }; let time = Instant::now(); - StopWatch { time, counter, memory: None } + StopWatch { + time, + #[cfg(target_os = "linux")] + counter, + memory: None, + } } pub fn memory(mut self, yes: bool) -> StopWatch { if yes { @@ -33,7 +44,12 @@ impl StopWatch { } pub fn elapsed(&mut self) -> StopWatchSpan { let time = self.time.elapsed(); + + #[cfg(target_os = "linux")] let instructions = self.counter.as_mut().and_then(|it| it.read().ok()); + #[cfg(not(target_os = "linux"))] + let instructions = None; + let memory = self.memory.map(|it| MemoryUsage::current() - it); StopWatchSpan { time, instructions, memory } } @@ -65,6 +81,7 @@ impl fmt::Display for StopWatchSpan { // https://github.com/jimblandy/perf-event/issues/8 impl Drop for StopWatch { fn drop(&mut self) { + #[cfg(target_os = "linux")] if let Some(mut counter) = self.counter.take() { let _ = counter.disable(); } -- cgit v1.2.3 From f22af66c3763c4b2a9d16621473cb6979fb2f36d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 10:43:47 +0200 Subject: Fixes --- crates/ra_prof/src/stop_watch.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs index c52c92ce5..8b8ec25a5 100644 --- a/crates/ra_prof/src/stop_watch.rs +++ b/crates/ra_prof/src/stop_watch.rs @@ -1,3 +1,4 @@ +//! Like `std::time::Instant`, but also measures memory & CPU cycles. use std::{ fmt, time::{Duration, Instant}, @@ -76,14 +77,3 @@ impl fmt::Display for StopWatchSpan { Ok(()) } } - -// Unclear if we need this: -// https://github.com/jimblandy/perf-event/issues/8 -impl Drop for StopWatch { - fn drop(&mut self) { - #[cfg(target_os = "linux")] - if let Some(mut counter) = self.counter.take() { - let _ = counter.disable(); - } - } -} -- cgit v1.2.3 From 3e1e6227ca525f8631e0bff2215fa3de1b4f4cc1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Jul 2020 14:27:19 +0200 Subject: Print errors when failing to create a perf counter --- crates/ra_prof/src/stop_watch.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'crates/ra_prof') diff --git a/crates/ra_prof/src/stop_watch.rs b/crates/ra_prof/src/stop_watch.rs index 8b8ec25a5..5e276190e 100644 --- a/crates/ra_prof/src/stop_watch.rs +++ b/crates/ra_prof/src/stop_watch.rs @@ -23,9 +23,14 @@ impl StopWatch { pub fn start() -> StopWatch { #[cfg(target_os = "linux")] let counter = { - let mut counter = perf_event::Builder::new().build().ok(); + let mut counter = perf_event::Builder::new() + .build() + .map_err(|err| eprintln!("Failed to create perf counter: {}", err)) + .ok(); if let Some(counter) = &mut counter { - let _ = counter.enable(); + if let Err(err) = counter.enable() { + eprintln!("Failed to start perf counter: {}", err) + } } counter }; @@ -47,7 +52,9 @@ impl StopWatch { let time = self.time.elapsed(); #[cfg(target_os = "linux")] - let instructions = self.counter.as_mut().and_then(|it| it.read().ok()); + let instructions = self.counter.as_mut().and_then(|it| { + it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok() + }); #[cfg(not(target_os = "linux"))] let instructions = None; -- cgit v1.2.3