aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_prof/src/stop_watch.rs
blob: 54bfb05594a60dd168a1f7443f33d16259e06004 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::MemoryUsage;
use std::{
    fmt,
    time::{Duration, Instant},
};

pub struct StopWatch {
    time: Instant,
    counter: Option<perf_event::Counter>,
    memory: Option<MemoryUsage>,
}

pub struct StopWatchSpan {
    pub time: Duration,
    pub instructions: Option<u64>,
    pub memory: Option<MemoryUsage>,
}

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();
        }
    }
}