use core::time::Duration;
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq)]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct ResourceBound {
pub amount: usize,
pub peak_per_s: f64,
}
impl ResourceBound {
pub fn time_at_peak(&self) -> Option<Duration> {
if self.peak_per_s > 0.0 && self.peak_per_s.is_normal() {
Some(Duration::from_secs_f64(
self.amount as f64 / self.peak_per_s,
))
} else {
None
}
}
}
pub fn binding_resource(bounds: &[ResourceBound]) -> Option<&ResourceBound> {
bounds
.iter()
.filter(|bound| bound.time_at_peak().is_some())
.max_by_key(|bound| bound.time_at_peak())
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct AchievedThroughput {
pub achieved_per_s: f64,
pub fraction_of_peak: f64,
}
pub fn score_resources(duration: Duration, bounds: &[ResourceBound]) -> Vec<AchievedThroughput> {
bounds
.iter()
.map(|bound| {
let achieved_per_s = if duration.is_zero() {
f64::NAN
} else {
bound.amount as f64 / duration.as_secs_f64()
};
AchievedThroughput {
achieved_per_s,
fraction_of_peak: achieved_per_s / bound.peak_per_s,
}
})
.collect()
}
pub fn binding_achieved(scores: &[AchievedThroughput]) -> Option<&AchievedThroughput> {
scores
.iter()
.filter(|score| score.fraction_of_peak.is_finite())
.max_by(|a, b| a.fraction_of_peak.total_cmp(&b.fraction_of_peak))
}