//! Quality markers for collected recipes: bench-coverage stars and the //! per-category medal ranks. use super::render::latest_score; use super::{ReportEntry, ReportRow}; /// Reports exist but none finished the full scenario pool. pub(crate) fn incomplete(reports: &[ReportEntry]) -> bool { !reports.is_empty() && !reports.iter().any(|e| e.done) } /// Gold/silver/bronze per (parent model, node count) category, ranked by /// latest score. Lanes of different node counts don't compete against each /// other (4x has more GPUs than 2x); recipes without any score don't take /// a medal. Ties break by recipe name (deterministic). pub(crate) fn award_medals(rows: &mut [ReportRow]) { use std::cmp::Ordering; let mut groups: std::collections::HashMap<(String, u32), Vec> = std::collections::HashMap::new(); for (i, r) in rows.iter().enumerate() { groups .entry((r.parent.clone(), r.nodes.unwrap_or(1))) .or_default() .push(i); } for (_, mut idxs) in groups { idxs.sort_by(|&a, &b| { let pct = |i: usize| latest_score(&rows[i]).and_then(|e| e.pct); pct(b) .partial_cmp(&pct(a)) .unwrap_or(Ordering::Equal) .then_with(|| rows[a].name.cmp(&rows[b].name)) }); for (rank, &i) in idxs.iter().enumerate().take(3) { if latest_score(&rows[i]).is_some() { rows[i].medal = Some(rank as u8 + 1); } } } }