use alloc::vec::Vec;
use core::time::Duration;
use ruda_core::benchmark::{BenchmarkComputations, BenchmarkDurations};
use ruda_core::profile::TimingMethod;
#[derive(Debug, Default)]
pub(crate) struct SampleSet {
durations: Vec<Duration>,
stalled: u8,
}
impl SampleSet {
pub(crate) fn push(&mut self, duration: Duration) {
let before = self.best();
self.durations.push(duration);
if self.durations.len() == DISCARD_THRESHOLD {
self.stalled = 0;
return;
}
let improved = match (before, self.best()) {
(Some(before), Some(after)) => TimeChange::of(after, before) == TimeChange::Improvement,
_ => true,
};
self.stalled = if improved {
0
} else {
self.stalled.saturating_add(1)
};
}
pub(crate) fn len(&self) -> usize {
self.durations.len()
}
pub(crate) fn is_empty(&self) -> bool {
self.durations.is_empty()
}
fn reliable(&self) -> &[Duration] {
if self.durations.len() >= DISCARD_THRESHOLD {
&self.durations[1..]
} else {
&self.durations
}
}
pub(crate) fn best(&self) -> Option<Duration> {
self.reliable().iter().min().copied()
}
pub(crate) fn converged(&self) -> bool {
self.stalled >= CONVERGENCE_ROUNDS
}
pub(crate) fn confirmed_under(&self, limit: Duration, required: usize) -> bool {
self.durations.iter().filter(|d| **d <= limit).count() >= required
}
pub(crate) fn any_under(&self, limit: Duration) -> bool {
self.durations.iter().any(|d| *d <= limit)
}
pub(crate) fn computation(&self, method: TimingMethod) -> BenchmarkComputations {
BenchmarkComputations::new(&BenchmarkDurations::from_durations(
method,
self.reliable().to_vec(),
))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum TimeChange {
Improvement,
Neutral,
Regression,
}
impl TimeChange {
pub(crate) fn of(time: Duration, baseline: Duration) -> Self {
if time < baseline.mul_f64(1.0 - IMPROVEMENT_THRESHOLD) {
Self::Improvement
} else if time > baseline.mul_f64(1.0 + IMPROVEMENT_THRESHOLD) {
Self::Regression
} else {
Self::Neutral
}
}
}
const DISCARD_THRESHOLD: usize = 3;
const IMPROVEMENT_THRESHOLD: f64 = 0.02;
const CONVERGENCE_ROUNDS: u8 = 2;