1use std::fmt::Write as _;
11
12use super::families::{EvidenceSource, ParamKind};
13use super::report::{Row, VennReport};
14use super::{Class, Compared, Finding};
15use crate::ir::LayerKind;
16
17fn short(recipe: &str) -> &str {
18 recipe.rsplit('/').next().unwrap_or(recipe)
19}
20
21fn base(path: &str) -> &str {
22 path.rsplit('/').next().unwrap_or(path)
23}
24
25fn compared(f: &Finding) -> String {
26 match &f.compared {
27 Compared::Model {
28 recipe,
29 node,
30 kernels,
31 } => format!("{}: `{kernels}` ({} `{node}`)", f.family, short(recipe)),
32 Compared::Point { how, files } => {
33 let more = if files.len() > 1 {
34 format!(" +{}", files.len() - 1)
35 } else {
36 String::new()
37 };
38 format!(
39 "{}: {} in `{}`{more}; no compared model runs this op on it here",
40 f.family,
41 how.name(),
42 base(&files[0])
43 )
44 }
45 }
46}
47
48fn diffs(f: &Finding) -> (String, String) {
49 if f.diffs.is_empty() {
50 return ("none".into(), "-".into());
51 }
52 let what: Vec<String> = f
53 .diffs
54 .iter()
55 .map(|d| format!("{} {} vs {}", d.param, d.target, d.other))
56 .collect();
57 let kinds: Vec<&str> = f.diffs.iter().map(|d| d.kind.name()).collect();
58 (what.join("; "), kinds.join("; "))
59}
60
61fn evidence(f: &Finding, r: &VennReport) -> String {
62 if f.evidence.is_empty() {
63 return "none".into();
64 }
65 f.evidence
66 .iter()
67 .map(|e| match e {
68 EvidenceSource::Measurement(k) => match r.cited.get(k) {
69 Some(p) => format!("`{k}` ({p:.1}% of floor)"),
70 None => format!("`{k}`"),
71 },
72 EvidenceSource::Microbench(m) => format!("microbench: {m}"),
73 })
74 .collect::<Vec<_>>()
75 .join("; ")
76}
77
78fn pointed(f: &Finding, kind: ParamKind) -> Vec<&str> {
79 f.diffs
80 .iter()
81 .filter(|d| d.kind == kind)
82 .map(|d| d.param.as_str())
83 .collect()
84}
85
86fn decision(row: &Row) -> String {
87 let Some(f) = &row.primary else {
88 return "build: reference kernel, logits parity, then microbench against its roofline"
89 .into();
90 };
91 let mut out = match f.class {
92 Class::Shared => "reuse (optimized at this point)".to_string(),
93 Class::SharedUnmeasured => "reuse, then microbench at this point".to_string(),
94 Class::PolicyVariant => format!(
95 "policy template on {} (or split + bit_identical fusion rule)",
96 pointed(f, ParamKind::Policy).join(", ")
97 ),
98 Class::ParameterizationOpportunity => {
99 let mut s = format!("template on {}", pointed(f, ParamKind::Compile).join(", "));
100 let pol = pointed(f, ParamKind::Policy);
101 if !pol.is_empty() {
102 let _ = write!(s, " + policy {}", pol.join(", "));
103 }
104 s.push_str("; stability gate at existing points");
105 s
106 }
107 Class::Novel => String::new(),
108 };
109 if f.instantiated == Some(super::families::How::Copy) {
110 out.push_str("; the target point exists only as a file copy");
111 }
112 for a in &row.also {
113 let params: Vec<&str> = a
114 .diffs
115 .iter()
116 .filter(|d| d.kind != ParamKind::Runtime)
117 .map(|d| d.param.as_str())
118 .collect();
119 let _ = write!(
120 out,
121 "; also {}: {} ({})",
122 a.family,
123 a.class.name(),
124 params.join(", ")
125 );
126 }
127 out
128}
129
130fn kind_name(k: Option<LayerKind>) -> &'static str {
131 k.map_or("head / draft", LayerKind::name)
132}
133
134pub fn render(r: &VennReport) -> String {
136 let mut s = String::new();
137 let t = &r.target;
138 let against: Vec<&str> = r.against.iter().map(|a| a.checkpoint.as_str()).collect();
139 let _ = writeln!(
140 s,
141 "# Kernel Venn: {} vs {}\n",
142 t.checkpoint,
143 against.join(", ")
144 );
145 let _ = writeln!(
146 s,
147 "Generated by `{}`. Do not edit: regenerate with that command, and `--check` verifies it is current.\n",
148 r.command
149 );
150 s.push_str("## Target\n\n| | |\n|---|---|\n");
151 let _ = writeln!(s, "| Recipe | `{}` |", t.recipe);
152 let _ = writeln!(s, "| Checkpoint | `{}` |", t.checkpoint);
153 let _ = writeln!(s, "| Circuit | `kernels/circuits/{}.toml` |", r.arch);
154 let _ = writeln!(s, "| Kernel target | `{}` |", t.target);
155 let mut kinds: Vec<(LayerKind, usize)> = Vec::new();
156 for k in &r.layer_kinds {
157 match kinds.iter_mut().find(|(x, _)| x == k) {
158 Some((_, n)) => *n += 1,
159 None => kinds.push((*k, 1)),
160 }
161 }
162 let kinds: Vec<String> = kinds
163 .iter()
164 .map(|(k, n)| format!("{n} {}", k.name()))
165 .collect();
166 let _ = writeln!(
167 s,
168 "| Layers | {}: {} |",
169 r.layer_kinds.len(),
170 kinds.join(", ")
171 );
172 let dims: Vec<String> = t
173 .shape
174 .dims
175 .iter()
176 .map(|(k, v)| format!("{k} {v}"))
177 .collect();
178 let _ = writeln!(s, "| Dims | {} |", dims.join(", "));
179 let set: Vec<String> = t
180 .policy
181 .settings
182 .iter()
183 .map(|(k, v)| format!("{k}={v}"))
184 .collect();
185 let _ = writeln!(s, "| Settings | {} |\n", set.join(" "));
186 s.push_str("### Declared precision (weight / input activation per site)\n\n| Site | Weight | Activation |\n|---|---|---|\n");
187 for (site, (w, a)) in &r.precision {
188 let _ = writeln!(s, "| `{site}` | {w} | {a} |");
189 }
190 s.push_str(
191 "\n## Compared with\n\n| Recipe | Checkpoint | Circuit | Settings |\n|---|---|---|---|\n",
192 );
193 for a in &r.against {
194 let set: Vec<String> = a
195 .policy
196 .settings
197 .iter()
198 .map(|(k, v)| format!("{k}={v}"))
199 .collect();
200 let _ = writeln!(
201 s,
202 "| `{}` | `{}` | `{}` | {} |",
203 a.recipe,
204 a.checkpoint,
205 a.arch,
206 set.join(" ")
207 );
208 }
209 let rf = &r.roofline;
210 let _ = writeln!(
211 s,
212 "\n## Estimate\n\nStep share is a roofline estimate from edge shapes and formats, per node: \
213 max(bytes / {:.1} GB/s, FLOPs / peak), with peaks BF16 {:.1}, FP8 {:.1} and NVFP4 {:.1} TFLOPS \
214 (the MMA class of the node's input activation). State traffic: the paged KV cache over {} \
215 tokens per sequence, and FP32 recurrent states read and written once per sequence. Routed \
216 experts read E(1 - (1 - k/E)^T) distinct experts for T tokens. Launch overhead and conv \
217 windows are not counted. Replace with measured profiles once a serve runs.\n",
218 rf.dram_gbps, rf.bf16_tflops, rf.fp8_tflops, rf.nvfp4_tflops, rf.context_tokens
219 );
220 s.push_str("## Flags: layers that cannot batch rows\n\n");
221 if r.flags.is_empty() {
222 s.push_str("None.\n");
223 } else {
224 s.push_str("| # | Layer kind | Mode | Rows | Est. added time | vs. multi-row step | Source | Note |\n|---|---|---|---|---|---|---|---|\n");
225 for (i, f) in r.flags.iter().enumerate() {
226 let _ = writeln!(
227 s,
228 "| {} | {} | {} | {} | {:.1} µs | +{:.1}% | {} | {} |",
229 i + 1,
230 kind_name(f.layer_kind),
231 f.run.mode.name(),
232 f.run.rows,
233 f.added_us,
234 100.0 * f.share,
235 f.source,
236 f.note
237 );
238 }
239 }
240 for tb in &r.tables {
241 let _ = writeln!(
242 s,
243 "\n## {}, {} row{} (estimated step {:.1} µs)\n",
244 tb.run.mode.name(),
245 tb.run.rows,
246 if tb.run.rows == 1 { "" } else { "s" },
247 tb.total_us
248 );
249 s.push_str("| # | Phase | Target op | Comparison kernel | Class | Parameter(s) differing | Runtime / compile-time / policy | Est. step share | Evidence at target point | Decision |\n|---|---|---|---|---|---|---|---|---|---|\n");
250 for (i, row) in tb.rows.iter().enumerate() {
251 let fmt = match (&row.weight, &row.activation) {
252 (Some(w), Some(a)) => format!(", W {w}, A {a}"),
253 (None, Some(a)) => format!(", in {a}"),
254 _ => String::new(),
255 };
256 let (cmp, class, (what, kinds), ev) = match &row.primary {
257 Some(f) => (compared(f), f.class.name(), diffs(f), evidence(f, r)),
258 None => (
259 "no family implements it".to_string(),
260 Class::Novel.name(),
261 ("-".to_string(), "-".to_string()),
262 "none".to_string(),
263 ),
264 };
265 let _ = writeln!(
266 s,
267 "| {} | {} | `{}` ×{} (`{}`{fmt}) | {cmp} | {class} | {what} | {kinds} | {:.1}% ({:.1} µs) | {ev} | {} |",
268 i + 1,
269 tb.run.mode.name(),
270 row.site,
271 row.count,
272 row.op,
273 100.0 * row.share,
274 row.time_us,
275 decision(row)
276 );
277 }
278 }
279 super::render_summary::summary(r, &mut s);
280 s
281}