#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum WorkloadPhase {
Warmup,
SteadyState,
Burst,
Cooldown,
Custom(&'static str),
}
pub struct RegimeClassifier {
current_phase: WorkloadPhase,
warmup_samples_remaining: u32,
throughput_ema: f64,
throughput_ema_alpha: f64,
burst_threshold_multiplier: f64,
}
impl RegimeClassifier {
pub fn new(warmup_samples: u32, burst_threshold: f64) -> Self {
Self {
current_phase: WorkloadPhase::Warmup,
warmup_samples_remaining: warmup_samples,
throughput_ema: 0.0,
throughput_ema_alpha: 0.1,
burst_threshold_multiplier: burst_threshold.max(1.1),
}
}
pub fn observe_throughput(&mut self, throughput: f64) -> WorkloadPhase {
if self.warmup_samples_remaining > 0 {
self.warmup_samples_remaining -= 1;
self.throughput_ema = throughput; if self.warmup_samples_remaining == 0 {
self.current_phase = WorkloadPhase::SteadyState;
}
return self.current_phase;
}
self.throughput_ema = self.throughput_ema_alpha * throughput
+ (1.0 - self.throughput_ema_alpha) * self.throughput_ema;
if throughput > self.throughput_ema * self.burst_threshold_multiplier {
self.current_phase = WorkloadPhase::Burst;
} else if throughput < self.throughput_ema * 0.1 {
self.current_phase = WorkloadPhase::Cooldown;
} else {
self.current_phase = WorkloadPhase::SteadyState;
}
self.current_phase
}
pub fn set_phase(&mut self, phase: WorkloadPhase) {
self.current_phase = phase;
}
pub fn phase(&self) -> WorkloadPhase {
self.current_phase
}
pub fn reset(&mut self, warmup_samples: u32) {
self.current_phase = WorkloadPhase::Warmup;
self.warmup_samples_remaining = warmup_samples;
self.throughput_ema = 0.0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_starts_in_warmup() {
let classifier = RegimeClassifier::new(10, 2.0);
assert_eq!(classifier.phase(), WorkloadPhase::Warmup);
}
#[test]
fn test_transitions_to_steady_state() {
let mut classifier = RegimeClassifier::new(3, 2.0);
classifier.observe_throughput(100.0);
classifier.observe_throughput(100.0);
assert_eq!(classifier.phase(), WorkloadPhase::Warmup);
classifier.observe_throughput(100.0);
assert_eq!(classifier.phase(), WorkloadPhase::SteadyState);
}
}