1 //! Like `std::time::Instant`, but also measures memory & CPU cycles.
4 time::{Duration, Instant},
7 use crate::MemoryUsage;
11 #[cfg(target_os = "linux")]
12 counter: Option<perf_event::Counter>,
13 memory: Option<MemoryUsage>,
16 pub struct StopWatchSpan {
18 pub instructions: Option<u64>,
19 pub memory: Option<MemoryUsage>,
23 pub fn start() -> StopWatch {
24 #[cfg(target_os = "linux")]
26 // When debugging rust-analyzer using rr, the perf-related syscalls cause it to abort.
27 // We allow disabling perf by setting the env var `RA_DISABLE_PERF`.
29 use once_cell::sync::Lazy;
30 static PERF_ENABLED: Lazy<bool> =
31 Lazy::new(|| std::env::var_os("RA_DISABLE_PERF").is_none());
34 let mut counter = perf_event::Builder::new()
36 .map_err(|err| eprintln!("Failed to create perf counter: {}", err))
38 if let Some(counter) = &mut counter {
39 if let Err(err) = counter.enable() {
40 eprintln!("Failed to start perf counter: {}", err)
48 let time = Instant::now();
51 #[cfg(target_os = "linux")]
56 pub fn memory(mut self, yes: bool) -> StopWatch {
58 self.memory = Some(MemoryUsage::now());
62 pub fn elapsed(&mut self) -> StopWatchSpan {
63 let time = self.time.elapsed();
65 #[cfg(target_os = "linux")]
66 let instructions = self.counter.as_mut().and_then(|it| {
67 it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).ok()
69 #[cfg(not(target_os = "linux"))]
70 let instructions = None;
72 let memory = self.memory.map(|it| MemoryUsage::now() - it);
73 StopWatchSpan { time, instructions, memory }
77 impl fmt::Display for StopWatchSpan {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "{:.2?}", self.time)?;
80 if let Some(mut instructions) = self.instructions {
82 if instructions > 10000 {
86 if instructions > 10000 {
90 if instructions > 10000 {
94 write!(f, ", {}{}instr", instructions, prefix)?;
96 if let Some(memory) = self.memory {
97 write!(f, ", {}", memory)?;