use std::collections::HashMap;
use std::time;
pub struct DevTime {}
pub fn run_benchmark(iters: usize, function: impl Fn(usize)) -> RunThroughReport {
let mut timer = DevTime::new_simple();
let mut res = Vec::with_capacity(iters);
for i in 0..iters {
println!("Running iter {} ...", i + 1);
timer.start();
(function)(i);
timer.stop();
res.push(timer.time_in_nanos().unwrap());
}
res.sort();
let realindex = res.len() - 1;
let fastest = res[0];
let slowest = res[realindex];
let sum: u128 = res.into_iter().sum();
let avg: u128 = sum / (iters as u128);
RunThroughReport {
fastest,
slowest,
avg,
}
}
impl DevTime {
pub fn new_simple() -> SimpleTimer {
SimpleTimer::new()
}
pub fn new_complex() -> ComplexTimer {
ComplexTimer::new()
}
}
pub struct ComplexTimer {
timers: HashMap<&'static str, SimpleTimer>,
}
impl ComplexTimer {
pub fn new() -> Self {
ComplexTimer {
timers: HashMap::new(),
}
}
pub fn create_timer(&mut self, timer_name: &'static str) -> Result<(), &'static str> {
if self.timers.contains_key(timer_name) {
Err("This timer already exists")
} else {
let _ = self.timers.insert(
timer_name,
SimpleTimer {
start: None,
stop: None,
},
);
Ok(())
}
}
pub fn start_timer(&mut self, timer_name: &'static str) -> Result<(), &'static str> {
match self.timers.get_mut(timer_name) {
None => return Err("This timer does not exist"),
Some(x) => {
x.start = Some(time::Instant::now());
Ok(())
}
}
}
pub fn stop_timer(&mut self, timer_name: &'static str) -> Result<(), &'static str> {
match self.timers.get_mut(timer_name) {
None => return Err("This timer does not exist"),
Some(x) => {
x.stop = Some(time::Instant::now());
Ok(())
}
}
}
pub fn time_in_secs(&self, timer_name: &'static str) -> Option<u64> {
match self.timers.get(timer_name) {
Some(t) => match t.find_diff() {
Some(diff) => Some(diff.as_secs()),
None => None,
},
None => return None,
}
}
pub fn time_in_millis(&self, timer_name: &'static str) -> Option<u128> {
match self.timers.get(timer_name) {
Some(t) => match t.find_diff() {
Some(diff) => Some(diff.as_millis()),
None => None,
},
None => return None,
}
}
pub fn time_in_micros(&self, timer_name: &'static str) -> Option<u128> {
match self.timers.get(timer_name) {
Some(t) => match t.find_diff() {
Some(diff) => Some(diff.as_micros()),
None => None,
},
None => return None,
}
}
pub fn time_in_nanos(&self, timer_name: &'static str) -> Option<u128> {
match self.timers.get(timer_name) {
Some(t) => match t.find_diff() {
Some(diff) => Some(diff.as_nanos()),
None => None,
},
None => return None,
}
}
pub fn delete_timer(&mut self, timer_name: &'static str) -> Result<(), &'static str> {
match self.timers.remove_entry(timer_name) {
Some(_) => return Ok(()),
None => return Err("This timer does not exist"),
}
}
pub fn clear_timers(&mut self) {
self.timers.clear();
}
pub fn print_results(&self) {
println!("");
for (k, v) in self.timers.iter() {
println!("{} - {} ns", k, v.time_in_nanos().unwrap());
}
}
pub fn iter(&self) -> std::collections::hash_map::Iter<&'static str, SimpleTimer> {
self.timers.iter()
}
}
pub struct SimpleTimer {
start: Option<time::Instant>,
stop: Option<time::Instant>,
}
impl SimpleTimer {
pub fn new() -> Self {
SimpleTimer {
start: None,
stop: None,
}
}
pub fn start(&mut self) {
self.start = Some(time::Instant::now());
}
pub fn stop(&mut self) {
self.stop = Some(time::Instant::now());
}
pub fn start_after(&mut self, dur: &std::time::Duration) {
std::thread::sleep(*dur);
self.start = Some(time::Instant::now());
}
fn find_diff(&self) -> Option<time::Duration> {
match self.start {
Some(start) => match self.stop {
Some(stop) => {
return Some(stop.duration_since(start));
}
_ => None,
},
_ => None,
}
}
pub fn time_in_nanos(&self) -> Option<u128> {
match self.find_diff() {
Some(duration) => return Some(duration.as_nanos()),
_ => None,
}
}
pub fn time_in_micros(&self) -> Option<u128> {
match self.find_diff() {
Some(duration) => return Some(duration.as_micros()),
_ => None,
}
}
pub fn time_in_millis(&self) -> Option<u128> {
match self.find_diff() {
Some(duration) => return Some(duration.as_millis()),
_ => None,
}
}
pub fn time_in_secs(&self) -> Option<u64> {
match self.find_diff() {
Some(duration) => return Some(duration.as_secs()),
_ => None,
}
}
}
pub struct RunThroughReport {
fastest: u128,
slowest: u128,
avg: u128,
}
impl RunThroughReport {
pub fn print_stats(&self) {
println!("\nSlowest: {} ns", self.slowest);
println!("Fastest: {} ns", self.fastest);
println!("Average: {} ns/iter", self.avg);
}
pub fn get_fastest(&self) -> u128 {
self.fastest
}
pub fn get_slowest(&self) -> u128 {
self.slowest
}
pub fn get_average(&self) -> u128 {
self.avg
}
}
#[test]
fn check_complex_timer_impl() {
let mut dt = DevTime::new_complex();
dt.create_timer("pk12").unwrap();
dt.start_timer("pk12").unwrap();
std::thread::sleep(std::time::Duration::from_micros(12));
dt.stop_timer("pk12").unwrap();
println!(
"The operation took: {} us",
dt.time_in_micros("pk12").unwrap()
);
dt.create_timer("arg2").unwrap();
dt.start_timer("arg2").unwrap();
std::thread::sleep(std::time::Duration::from_micros(45));
dt.stop_timer("arg2").unwrap();
println!(
"The operation took: {} us",
dt.time_in_micros("arg2").unwrap()
);
for (timer, result) in dt.iter() {
println!("Timer: {} - {}", timer, result.time_in_nanos().unwrap());
}
dt.print_results();
dt.clear_timers();
}
#[test]
fn test_benchmark_impl() {
use run_benchmark;
let bench1 = run_benchmark(10, |_| {
std::thread::sleep(time::Duration::from_secs(1));
});
bench1.print_stats();
}
#[test]
fn test_simple_timer_impl() {
let mut dt = DevTime::new_simple();
dt.start();
std::thread::sleep(time::Duration::from_secs(10));
dt.stop();
println!("Operation took: {}", dt.time_in_micros().unwrap());
}