metrale_circuit/venn/mod.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-29: The kernel Venn diagram of a target model against the models we already support
4//! (`met circuit venn`): every target node, in every mode and row count asked for, classified
5//! against the kernel families the compared models run, ranked by estimated share of step time.
6//!
7//! Classes, decided per node from the family manifest ([`families`]):
8//! - **Shared**: a family the compared models run, at the same compile-time and policy point,
9//! with a microbench record at that point and row count.
10//! - **Shared, unmeasured**: the same, without the record. Also a point the family already
11//! realises by an instantiation or a runtime branch while the compared models run another
12//! (the differing parameters are still listed).
13//! - **Parameterization opportunity**: the same family where declared parameters differ and
14//! one of them is compile-time; the target point is missing or exists only as a file copy.
15//! - **Policy variant**: the same, where every differing parameter is a policy.
16//! - **Novel**: no family implements the op with the node's formats at that row count.
17//!
18//! Owner: metrale-circuit (venn).
19//! Invariants:
20//! - Pure: no I/O. The caller passes the circuits, plans, manifest and measurements.
21//! - Deterministic: ties break by family order in the manifest, then by circuit order.
22//! - A compared node whose plan kernel belongs to no family, and a parameter a node cannot
23//! supply, are typed errors: the report is never built from a guess.
24
25pub mod checkpoint;
26pub mod classify;
27mod cli_args;
28pub mod compute;
29pub mod discover;
30pub mod families;
31pub mod measurements;
32mod render;
33mod render_summary;
34pub mod repo;
35pub mod report;
36pub mod roofline;
37
38use std::collections::BTreeMap;
39
40use crate::fuser::FusionPlan;
41use crate::ir::Circuit;
42use crate::rules::Mode;
43
44pub use cli_args::VennArgs;
45pub use families::{Families, FamilyError, ParamKind, parse_families};
46pub use measurements::{Measurements, parse_measurements};
47pub use render::render;
48pub use repo::{Repo, checkpoint_id_of, report_text, resolve};
49pub use report::{VennInputs, VennReport, build};
50
51/// 2026-09-29: One model on either side of the diagram, at one mode and row count.
52#[derive(Debug, Clone, Copy)]
53pub struct Subject<'a> {
54 /// 2026-09-29: Recipe id.
55 pub recipe: &'a str,
56 /// 2026-09-29: The instantiated circuit.
57 pub circuit: &'a Circuit,
58 /// 2026-09-29: The instance's policy settings (`kv_cache_dtype`, ...).
59 pub settings: &'a BTreeMap<String, String>,
60 /// 2026-09-29: Its fused plan at this mode and row count; `None` for a target no rule set
61 /// covers yet, whose nodes are matched to families by op.
62 pub plan: Option<&'a FusionPlan>,
63}
64
65/// 2026-09-29: A node's class.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
67pub enum Class {
68 /// 2026-09-29: Reuse; optimized at this point.
69 Shared,
70 /// 2026-09-29: Reuse, then microbench.
71 SharedUnmeasured,
72 /// 2026-09-29: A policy template (or a split).
73 PolicyVariant,
74 /// 2026-09-29: A template parameter (or a split), with the stability gate.
75 ParameterizationOpportunity,
76 /// 2026-09-29: Build it.
77 Novel,
78}
79
80impl Class {
81 /// 2026-09-29: The report spelling.
82 pub fn name(self) -> &'static str {
83 match self {
84 Class::Shared => "Shared",
85 Class::SharedUnmeasured => "Shared, unmeasured",
86 Class::PolicyVariant => "Policy variant",
87 Class::ParameterizationOpportunity => "Param. opportunity",
88 Class::Novel => "Novel",
89 }
90 }
91}
92
93/// 2026-09-29: A parameter whose value differs from the compared point.
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct Diff {
96 /// 2026-09-29: Parameter.
97 pub param: String,
98 /// 2026-09-29: Its kind.
99 pub kind: ParamKind,
100 /// 2026-09-29: The target's value.
101 pub target: String,
102 /// 2026-09-29: The compared value.
103 pub other: String,
104}
105
106/// 2026-09-29: What a target node was compared with.
107#[derive(Debug, Clone, PartialEq, Eq)]
108pub enum Compared {
109 /// 2026-09-29: A node a compared model runs, and the kernels its plan group launches.
110 Model {
111 /// 2026-09-29: Recipe.
112 recipe: String,
113 /// 2026-09-29: Node id.
114 node: String,
115 /// 2026-09-29: `module::function` list, or the emitter of a kernel-less group.
116 kernels: String,
117 },
118 /// 2026-09-29: An instantiated point no compared model runs.
119 Point {
120 /// 2026-09-29: How it is realised.
121 how: families::How,
122 /// 2026-09-29: Its sources.
123 files: Vec<String>,
124 },
125}
126
127/// 2026-09-29: A node's classification against one family.
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct Finding {
130 /// 2026-09-29: Family id.
131 pub family: String,
132 /// 2026-09-29: Class.
133 pub class: Class,
134 /// 2026-09-29: The target's point in the family.
135 pub point: families::Values,
136 /// 2026-09-29: The comparison.
137 pub compared: Compared,
138 /// 2026-09-29: Parameters that differ from the comparison, runtime ones included.
139 pub diffs: Vec<Diff>,
140 /// 2026-09-29: How the target point is realised when the family already has it.
141 pub instantiated: Option<families::How>,
142 /// 2026-09-29: Evidence records at the target point and row count.
143 pub evidence: Vec<families::EvidenceSource>,
144}
145
146/// 2026-09-29: Why a Venn table could not be built.
147#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
148pub enum VennError {
149 /// 2026-09-29: A compared node whose plan group's kernels no family lists.
150 #[error("{recipe}: node `{node}` ({op}) runs {kernels}, which no family in the manifest lists")]
151 UnmappedKernel {
152 /// 2026-09-29: Recipe.
153 recipe: String,
154 /// 2026-09-29: Node id.
155 node: String,
156 /// 2026-09-29: Op name.
157 op: String,
158 /// 2026-09-29: Kernels.
159 kernels: String,
160 },
161 /// 2026-09-29: A parameter a node cannot supply, and no stated `absent` value.
162 #[error("family `{family}` parameter `{param}`: node `{node}` gives no value")]
163 MissingValue {
164 /// 2026-09-29: Family id.
165 family: String,
166 /// 2026-09-29: Parameter.
167 param: String,
168 /// 2026-09-29: Node id.
169 node: String,
170 },
171 /// 2026-09-29: An evidence record naming a measurements.toml row that does not exist.
172 #[error("family `{family}` cites measurement `{key}`, which measurements.toml does not have")]
173 UnknownMeasurement {
174 /// 2026-09-29: Family id.
175 family: String,
176 /// 2026-09-29: The key.
177 key: String,
178 },
179 /// 2026-09-29: A node the roofline cannot estimate.
180 #[error(transparent)]
181 Cost(#[from] roofline::CostError),
182 /// 2026-09-29: A mode the target circuit has no section for, or a row count it cannot run.
183 #[error("{0}")]
184 Run(String),
185 /// 2026-09-29: Loading or fusing a subject.
186 #[error("{0}")]
187 Load(String),
188 /// 2026-09-29: The family manifest disagrees with the kernel sources.
189 #[error("KERNEL_FAMILIES.toml has drifted from the sources:\n {}", .0.join("\n "))]
190 Drift(Vec<String>),
191 /// 2026-09-29: The target instance disagrees with the checkpoint directory it was named by.
192 #[error("{0}")]
193 Checkpoint(String),
194}
195
196/// 2026-09-29: One mode and row count.
197#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
198pub struct Run {
199 /// 2026-09-29: Mode.
200 pub mode: Mode,
201 /// 2026-09-29: Padded rows.
202 pub rows: u64,
203}
204
205#[cfg(test)]
206mod venn_tests;