2020-07-30 02:44:21 -05:00
|
|
|
use std::{
|
|
|
|
fmt,
|
|
|
|
time::{Duration, Instant},
|
|
|
|
};
|
|
|
|
|
2020-07-30 03:40:55 -05:00
|
|
|
use crate::MemoryUsage;
|
|
|
|
|
2020-07-30 02:44:21 -05:00
|
|
|
pub struct StopWatch {
|
|
|
|
time: Instant,
|
2020-07-30 03:40:55 -05:00
|
|
|
#[cfg(target_os = "linux")]
|
2020-07-30 02:44:21 -05:00
|
|
|
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 {
|
2020-07-30 03:40:55 -05:00
|
|
|
#[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
|
|
|
|
};
|
2020-07-30 02:44:21 -05:00
|
|
|
let time = Instant::now();
|
2020-07-30 03:40:55 -05:00
|
|
|
StopWatch {
|
|
|
|
time,
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
counter,
|
|
|
|
memory: None,
|
|
|
|
}
|
2020-07-30 02:44:21 -05:00
|
|
|
}
|
|
|
|
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();
|
2020-07-30 03:40:55 -05:00
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2020-07-30 02:44:21 -05:00
|
|
|
let instructions = self.counter.as_mut().and_then(|it| it.read().ok());
|
2020-07-30 03:40:55 -05:00
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
|
|
let instructions = None;
|
|
|
|
|
2020-07-30 02:44:21 -05:00
|
|
|
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) {
|
2020-07-30 03:40:55 -05:00
|
|
|
#[cfg(target_os = "linux")]
|
2020-07-30 02:44:21 -05:00
|
|
|
if let Some(mut counter) = self.counter.take() {
|
|
|
|
let _ = counter.disable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|