use std::time::Duration;
#[cfg(feature = "bench")]
use criterion::{Criterion, Throughput};
pub struct SimpleTimer {
start: std::time::Instant,
}
impl SimpleTimer {
pub fn start() -> Self {
Self { start: std::time::Instant::now() }
}
pub fn elapsed(&self) -> Duration {
self.start.elapsed()
}
pub fn reset(&mut self) {
self.start = std::time::Instant::now();
}
pub fn elapsed_ms(&self) -> u128 {
self.start.elapsed().as_millis()
}
pub fn elapsed_us(&self) -> u128 {
self.start.elapsed().as_micros()
}
pub fn elapsed_ns(&self) -> u128 {
self.start.elapsed().as_nanos()
}
}
pub struct PerformanceStats {
samples: Vec<Duration>,
}
impl PerformanceStats {
pub fn new() -> Self {
Self { samples: Vec::new() }
}
pub fn add_sample(&mut self, duration: Duration) {
self.samples.push(duration);
}
pub fn measure<F, R>(&mut self, f: F) -> R
where
F: FnOnce() -> R,
{
let start = std::time::Instant::now();
let result = f();
self.samples.push(start.elapsed());
result
}
pub fn sample_count(&self) -> usize {
self.samples.len()
}
pub fn mean(&self) -> Option<Duration> {
if self.samples.is_empty() {
return None;
}
let total: u128 = self.samples.iter().map(|d| d.as_nanos()).sum();
Some(Duration::from_nanos((total / self.samples.len() as u128) as u64))
}
pub fn min(&self) -> Option<Duration> {
self.samples.iter().min().copied()
}
pub fn max(&self) -> Option<Duration> {
self.samples.iter().max().copied()
}
pub fn median(&self) -> Option<Duration> {
if self.samples.is_empty() {
return None;
}
let mut sorted = self.samples.clone();
sorted.sort();
let mid = sorted.len() / 2;
Some(sorted[mid])
}
pub fn percentile(&self, p: f64) -> Option<Duration> {
if self.samples.is_empty() || p < 0.0 || p > 1.0 {
return None;
}
let mut sorted = self.samples.clone();
sorted.sort();
let idx = (sorted.len() as f64 * p) as usize;
let idx = idx.min(sorted.len() - 1);
Some(sorted[idx])
}
pub fn std_dev(&self) -> Option<Duration> {
if self.samples.len() < 2 {
return None;
}
let mean = self.mean()?.as_nanos() as f64;
let variance: f64 =
self.samples.iter().map(|d| (d.as_nanos() as f64 - mean).powi(2)).sum::<f64>() / (self.samples.len() - 1) as f64;
Some(Duration::from_nanos(variance.sqrt() as u64))
}
pub fn clear(&mut self) {
self.samples.clear();
}
}
impl Default for PerformanceStats {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "bench")]
pub struct BenchmarkConfig {
pub sample_size: usize,
pub measurement_time: Duration,
pub warm_up_time: Duration,
pub noise_threshold: f64,
pub significance_level: f64,
}
#[cfg(feature = "bench")]
impl Default for BenchmarkConfig {
fn default() -> Self {
Self {
sample_size: 100,
measurement_time: Duration::from_secs(5),
warm_up_time: Duration::from_secs(3),
noise_threshold: 0.05,
significance_level: 0.05,
}
}
}
#[cfg(feature = "bench")]
impl BenchmarkConfig {
pub fn new() -> Self {
Self::default()
}
pub fn sample_size(mut self, size: usize) -> Self {
self.sample_size = size;
self
}
pub fn measurement_time(mut self, time: Duration) -> Self {
self.measurement_time = time;
self
}
pub fn warm_up_time(mut self, time: Duration) -> Self {
self.warm_up_time = time;
self
}
pub fn noise_threshold(mut self, threshold: f64) -> Self {
self.noise_threshold = threshold;
self
}
pub fn significance_level(mut self, level: f64) -> Self {
self.significance_level = level;
self
}
}