2020-07-30 03:43:47 -05:00
|
|
|
//! Like `std::time::Instant`, but also measures memory & CPU cycles.
|
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 = {
|
2020-07-30 07:27:19 -05:00
|
|
|
let mut counter = perf_event::Builder::new()
|
|
|
|
.build()
|
|
|
|
.map_err(|err| eprintln!("Failed to create perf counter: {}", err))
|
|
|
|
.ok();
|
2020-07-30 03:40:55 -05:00
|
|
|
if let Some(counter) = &mut counter {
|
2020-07-30 07:27:19 -05:00
|
|
|
if let Err(err) = counter.enable() {
|
|
|
|
eprintln!("Failed to start perf counter: {}", err)
|
|
|
|
}
|
2020-07-30 03:40:55 -05:00
|
|
|
}
|
|
|
|
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 07:27:19 -05:00
|
|
|
let instructions = self.counter.as_mut().and_then(|it| {
|
|
|
|
it.read().map_err(|err| eprintln!("Failed to read perf counter: {}", err)).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(())
|
|
|
|
}
|
|
|
|
}
|