use crate::monitor::{MonitorReport, MonitorSummary, ScxEventDeltas};
use super::SampleSeries;
#[derive(Debug, Clone, Copy)]
#[must_use = "MonitorView is a borrowed view; call .summary() or .scx_events() to project"]
#[non_exhaustive]
pub struct MonitorView<'a> {
report: &'a MonitorReport,
}
impl<'a> MonitorView<'a> {
pub fn summary(&self) -> &'a MonitorSummary {
&self.report.summary
}
pub fn scx_events(&self) -> Option<ScxEventsView<'a>> {
self.report
.summary
.event_deltas
.as_ref()
.map(|deltas| ScxEventsView { deltas })
}
pub fn samples(&self) -> &'a [crate::monitor::MonitorSample] {
&self.report.samples
}
}
pub const ERROR_CLASS_NAMES: &[&str] = &[
"enq_skip_exiting",
"enq_skip_migration_disabled",
"reenq_immed",
"reenq_local_repeat",
"insert_not_owned",
];
#[derive(Debug, Clone, Copy)]
#[must_use = "ScxEventsView is a borrowed view; call .total_pairs() or .rates_pairs() to project"]
#[non_exhaustive]
pub struct ScxEventsView<'a> {
deltas: &'a ScxEventDeltas,
}
impl<'a> ScxEventsView<'a> {
pub fn total_pairs(&self) -> Vec<(&'static str, i64)> {
vec![
("select_cpu_fallback", self.deltas.total_fallback),
(
"select_cpu_fallback_max_burst",
self.deltas.max_fallback_burst,
),
(
"dispatch_local_dsq_offline",
self.deltas.total_dispatch_offline,
),
("dispatch_keep_last", self.deltas.total_dispatch_keep_last),
("enq_skip_exiting", self.deltas.total_enq_skip_exiting),
(
"enq_skip_migration_disabled",
self.deltas.total_enq_skip_migration_disabled,
),
("reenq_immed", self.deltas.total_reenq_immed),
("reenq_local_repeat", self.deltas.total_reenq_local_repeat),
("refill_slice_dfl", self.deltas.total_refill_slice_dfl),
("bypass_duration_ns", self.deltas.total_bypass_duration),
("bypass_dispatch", self.deltas.total_bypass_dispatch),
("bypass_activate", self.deltas.total_bypass_activate),
("insert_not_owned", self.deltas.total_insert_not_owned),
("sub_bypass_dispatch", self.deltas.total_sub_bypass_dispatch),
]
}
pub fn rates_pairs(&self) -> Vec<(&'static str, f64)> {
vec![
("select_cpu_fallback_rate", self.deltas.fallback_rate),
("dispatch_keep_last_rate", self.deltas.keep_last_rate),
]
}
}
impl SampleSeries {
pub fn monitor(&self) -> Option<MonitorView<'_>> {
self.monitor.as_ref().map(|m| MonitorView { report: m })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn series_monitor_none_when_unset() {
let series = SampleSeries::from_drained(vec![], None);
assert!(series.monitor().is_none());
}
#[test]
fn series_monitor_view_threads_through_supplied_report() {
let mut report = MonitorReport::default();
report.summary.total_samples = 42;
report.summary.max_imbalance_ratio = 2.5;
let series = SampleSeries::from_drained(vec![], Some(report));
let view = series.monitor().expect("monitor must be Some");
let summary = view.summary();
assert_eq!(summary.total_samples, 42);
assert_eq!(summary.max_imbalance_ratio, 2.5);
}
#[test]
fn series_monitor_scx_events_none_when_event_deltas_absent() {
let report = MonitorReport::default(); let series = SampleSeries::from_drained(vec![], Some(report));
let view = series.monitor().expect("monitor must be Some");
assert!(
view.scx_events().is_none(),
"scx_events must return None when event_deltas is absent — \
returning Some with zero-default pairs would silently mask the missing-data condition"
);
}
#[test]
fn series_monitor_scx_events_pairs_map_to_named_counters() {
let mut report = MonitorReport::default();
report.summary.event_deltas = Some(ScxEventDeltas {
total_fallback: 1,
fallback_rate: 0.5,
max_fallback_burst: 2,
total_dispatch_offline: 3,
total_dispatch_keep_last: 4,
keep_last_rate: 0.75,
total_enq_skip_exiting: 5,
total_enq_skip_migration_disabled: 6,
total_reenq_immed: 7,
total_reenq_local_repeat: 8,
total_refill_slice_dfl: 9,
total_bypass_duration: 10,
total_bypass_dispatch: 11,
total_bypass_activate: 12,
total_insert_not_owned: 13,
total_sub_bypass_dispatch: 14,
});
let series = SampleSeries::from_drained(vec![], Some(report));
let view = series.monitor().expect("monitor must be Some");
let events = view.scx_events().expect("event_deltas were set");
let totals = events.total_pairs();
assert_eq!(totals.len(), 14, "exactly 14 i64 counter pairs");
assert_eq!(
totals,
vec![
("select_cpu_fallback", 1),
("select_cpu_fallback_max_burst", 2),
("dispatch_local_dsq_offline", 3),
("dispatch_keep_last", 4),
("enq_skip_exiting", 5),
("enq_skip_migration_disabled", 6),
("reenq_immed", 7),
("reenq_local_repeat", 8),
("refill_slice_dfl", 9),
("bypass_duration_ns", 10),
("bypass_dispatch", 11),
("bypass_activate", 12),
("insert_not_owned", 13),
("sub_bypass_dispatch", 14),
]
);
let rates = events.rates_pairs();
assert_eq!(rates.len(), 2, "exactly 2 f64 rate pairs");
assert_eq!(
rates,
vec![
("select_cpu_fallback_rate", 0.5),
("dispatch_keep_last_rate", 0.75),
]
);
}
#[test]
fn series_monitor_scx_events_strict_zero_misuse_pinning() {
use crate::assert::assert_scx_events_clean;
let mut report = MonitorReport::default();
report.summary.event_deltas = Some(ScxEventDeltas {
total_bypass_dispatch: 100,
total_bypass_activate: 50,
total_dispatch_keep_last: 7,
..Default::default()
});
let series = SampleSeries::from_drained(vec![], Some(report));
let view = series.monitor().expect("monitor was set");
let events = view.scx_events().expect("event_deltas were set");
let pairs = events.total_pairs();
let r_full = assert_scx_events_clean(&pairs, None);
assert!(
!r_full.is_pass(),
"strict-zero against full 14-entry slice MUST fail when non-error-class counters legitimately fire — pins the STRICTNESS WARNING design contract"
);
let error_only: Vec<(&str, i64)> = pairs
.into_iter()
.filter(|(name, _)| ERROR_CLASS_NAMES.contains(name))
.collect();
let r_curated = assert_scx_events_clean(&error_only, None);
assert!(
r_curated.is_pass(),
"curated error-class subset MUST pass when every error counter is zero — pins the curate-then-assert documented workaround"
);
}
}