metrale_bench/benchmarks/scheduler_equivalence/
report.rs1use std::collections::BTreeMap;
11use std::time::Duration;
12
13use super::compare::{Cell, Leg, Score, metrics, score, verdict};
14use super::unmeasured;
15use crate::result::{
16 BenchmarkResult, Cell as TCell, CellStyle, Column, LogLine, ResultTable, Stat,
17};
18
19pub(super) fn terminal(
22 legs: &[Leg],
23 diagnostics: &BTreeMap<String, f64>,
24 elapsed: Duration,
25) -> BenchmarkResult {
26 let s = score(legs);
27 BenchmarkResult::completed("done", elapsed)
28 .with_summary(summary(&s))
29 .with_table(table(&s))
30 .with_metrics(metrics(&s, diagnostics))
31 .with_log(log(&s))
32 .with_verdict(verdict(&s))
33}
34
35pub(super) fn summary(s: &Score) -> Vec<Stat> {
36 let sum = |f: &dyn Fn(&Cell) -> usize| s.cells.iter().map(f).sum::<usize>();
37 vec![
38 Stat::new("cells", s.cells.len().to_string(), ""),
39 Stat::new(
40 "samples",
41 s.cells.first().map(|c| c.samples).unwrap_or(0).to_string(),
42 "",
43 ),
44 Stat::new(
45 "DIVERGED",
46 sum(&|c| c.async_vs_sync.diverged).to_string(),
47 "",
48 ),
49 Stat::new(
50 "control diverged",
51 sum(&|c| c.control_vs_sync.as_ref().map(|k| k.diverged).unwrap_or(0)).to_string(),
52 "",
53 ),
54 Stat::new(
55 "unmeasured causes",
56 unmeasured::breakdown(&all_unmeasured(s)),
57 "",
58 ),
59 ]
60}
61
62fn all_unmeasured(s: &Score) -> Vec<unmeasured::Unmeasured> {
63 s.cells.iter().flat_map(|c| c.unmeasured.clone()).collect()
64}
65
66pub(super) fn log(s: &Score) -> Vec<LogLine> {
68 all_unmeasured(s)
69 .iter()
70 .map(|u| LogLine::warn(u.to_string()))
71 .collect()
72}
73
74pub(super) fn table(s: &Score) -> ResultTable {
77 let mut t = ResultTable::new(
78 "SYNC VS ASYNC, PER LANE AND CONCURRENCY",
79 vec![
80 Column::left("Lane", 10),
81 Column::left("C", 4),
82 Column::left("Samples", 8),
83 Column::left("Async diverged", 15),
84 Column::left("Control diverged", 17),
85 Column::left("Unmeasured", 11),
86 Column::left("Causes", 24),
87 Column::left("Detail", 30),
88 ],
89 );
90 for c in &s.cells {
91 let bad = c.async_vs_sync.diverged > 0
92 || c.async_vs_sync.unmeasured > 0
93 || c.control_vs_sync
94 .as_ref()
95 .is_some_and(|k| k.diverged > 0 || k.unmeasured > 0);
96 let style = if bad { CellStyle::Bad } else { CellStyle::Good };
97 let detail = if c.async_vs_sync.diverged_ids.is_empty() {
98 "identical".to_string()
99 } else {
100 c.async_vs_sync.diverged_ids.join(", ")
101 };
102 t.push(vec![
103 TCell::new(c.lane.label().to_string()),
104 TCell::new(c.concurrency.to_string()),
105 TCell::new(c.samples.to_string()),
106 TCell::styled(c.async_vs_sync.diverged.to_string(), style),
107 TCell::new(
108 c.control_vs_sync
109 .as_ref()
110 .map(|k| k.diverged.to_string())
111 .unwrap_or_else(|| "-".to_string()),
112 ),
113 TCell::new(
114 (c.async_vs_sync.unmeasured
115 + c.control_vs_sync
116 .as_ref()
117 .map(|k| k.unmeasured)
118 .unwrap_or(0))
119 .to_string(),
120 ),
121 TCell::new(unmeasured::breakdown(&c.unmeasured)),
122 TCell::new(detail),
123 ]);
124 }
125 t
126}