1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
//! Env-gated router-selection histogram (`TURBOSPARK_ROUTER_HIST=/path.json`).
//!
//! Counts, per layer, how often each expert appears in the router's top-k
//! across every forward pass (prefill and decode alike, matching the
//! `TURBOSPARK_PHASES` divisor convention), and writes one JSON file when the
//! runner drops. Diagnostic only, never on by default: it exists to answer
//! whether routing is domain-concentrated enough for a pruned or pre-warmed
//! expert set to be worth building. Per-layer counts must sum to
//! `top_k * moe_forward_passes`, which is the sanity check on any capture.
//!
//! `TURBOSPARK_ROUTER_TRACE=1` additionally records the top-k ids IN PASS
//! ORDER, which the counts throw away. That ordering is what ROADMAP's
//! speculative-decoding question needs: a batched verify of M consecutive
//! tokens must read the UNION of their routes, so the expert-byte cost of a
//! block is the distinct-expert count over a window of M consecutive
//! passes, and no histogram can answer that. The counts stay in the same
//! file and are recomputable from the trace, which is the capture's own
//! cross-check.
//!
//! `TURBOSPARK_ROUTER_LOGITS_LAYER` plus `TURBOSPARK_ROUTER_LOGITS_PASS`
//! capture one full f32 router-logit row into that JSON. Pass is the 0-based
//! routed-forward count for that layer, so it lines up with token position in
//! a one-token-at-a-time prefill probe.
pub(crate) struct RouterHistogram {
path: std::path::PathBuf,
/// `counts[layer][expert]`; non-MoE layers never record and stay
/// all-zero rows, so layer indices line up with the model's.
counts: Vec<Vec<u64>>,
/// Number of routed forwards recorded for each layer.
passes: Vec<u64>,
/// `trace[layer]` is the flat concatenation of that layer's top-k ids,
/// one group of `top_k` per forward pass, in pass order. `Some` only
/// under `TURBOSPARK_ROUTER_TRACE`.
///
/// ponytail: unbounded, ~1.3 KB per pass at Qwen's 40 layers x top-8,
/// so a 4,000-pass session costs ~5 MB. Cap it if a capture ever runs
/// long enough to matter.
trace: Option<Vec<Vec<u32>>>,
/// `pred[layer]` is the ONE-LAYER-AHEAD prediction of that layer's
/// top-k: what layer `layer`'s own router says when it is run early, on
/// the previous layer's post-attention residual instead of its own
/// input. `Some` only under `TURBOSPARK_PILOT_PROBE`.
///
/// Aligned with `trace` by construction: layer L records a prediction
/// FOR L+1 during pass p, and layer L+1 records its actual selection
/// later in that same pass, so entry p of `pred[L+1]` and entry p of
/// `trace[L+1]` describe the same forward pass. Row 0 stays empty (no
/// layer precedes it), which the analysis skips rather than misreads.
pred: Option<Vec<Vec<u32>>>,
/// `TURBOSPARK_PILOT_PROBE=self`: aim the probe at the layer it is already
/// running in, instead of one ahead.
///
/// The prediction then reproduces the production router exactly, so
/// recall MUST read 100%. That is the check which separates "the
/// predictor is weak here" from "the probe is mis-wired", and it exists
/// because the first wiring of it read 7.7% against a 6.25% random
/// baseline -- indistinguishable from a real negative result, and
/// actually an off-by-one in which layer the prediction was filed
/// against (AGENTS.md Gotcha 57: near-random means UNRELATED, so suspect
/// the instrument before believing the finding).
pilot_self_test: bool,
/// One optional raw router-logit row requested by layer and pass.
router_logits: Option<RouterLogitsCapture>,
/// Learned from the first `record`, since `from_env` is not told it.
top_k: usize,
}
struct RouterLogitsCapture {
layer: usize,
pass: usize,
values: Option<Vec<f32>>,
}
impl RouterHistogram {
/// `Some` only when `TURBOSPARK_ROUTER_HIST` names an output path and the
/// install actually routes (dense installs have nothing to count).
pub(crate) fn from_env(num_layers: usize, num_experts: usize, top_k: usize) -> Option<Self> {
let path = std::env::var_os("TURBOSPARK_ROUTER_HIST")?;
if num_experts == 0 {
return None;
}
let trace =
std::env::var_os("TURBOSPARK_ROUTER_TRACE").map(|_| vec![Vec::new(); num_layers]);
let probe = std::env::var_os("TURBOSPARK_PILOT_PROBE");
let pilot_self_test = probe.as_deref().is_some_and(|v| v == "self");
let pred = probe.map(|_| vec![Vec::new(); num_layers]);
let router_logits = match (
std::env::var("TURBOSPARK_ROUTER_LOGITS_LAYER")
.ok()
.and_then(|value| value.parse::<usize>().ok()),
std::env::var("TURBOSPARK_ROUTER_LOGITS_PASS")
.ok()
.and_then(|value| value.parse::<usize>().ok()),
) {
(Some(layer), Some(pass)) if layer < num_layers => Some(RouterLogitsCapture {
layer,
pass,
values: None,
}),
_ => None,
};
Some(Self {
path: path.into(),
counts: vec![vec![0; num_experts]; num_layers],
passes: vec![0; num_layers],
trace,
pred,
pilot_self_test,
router_logits,
top_k,
})
}
/// See [`Self::pilot_self_test`]. The offset the probe aims at: 0 in
/// self-test (reproduce this layer's own router, expect 100% recall),
/// 1 in the real measurement (predict the next layer).
pub(crate) fn pilot_offset(&self) -> usize {
usize::from(!self.pilot_self_test)
}
/// Is the one-layer-ahead probe on? Read by the family encoders, which
/// must not pay for an extra router GEMV when it is off.
pub(crate) fn pilot_enabled(&self) -> bool {
self.pred.is_some()
}
/// Records the prediction FOR `layer`, made while the previous layer was
/// running. Never called for layer 0.
pub(crate) fn record_prediction(&mut self, layer: usize, predicted: &[usize]) {
if let Some(pred) = self.pred.as_mut() {
pred[layer].extend(predicted.iter().map(|&e| e as u32));
}
}
/// Capture only the requested row; no serialization or allocation is
/// paid for when the opt-in layer/pass pair is absent or does not match.
pub(crate) fn record_router_logits(&mut self, layer: usize, logits: &[f32]) {
let Some(capture) = self.router_logits.as_mut() else {
return;
};
if capture.layer == layer
&& capture.pass == self.passes[layer] as usize
&& capture.values.is_none()
{
capture.values = Some(logits.to_vec());
}
}
pub(crate) fn record(&mut self, layer: usize, selected: &[usize]) {
for &expert in selected {
self.counts[layer][expert] += 1;
}
if self.top_k == 0 {
self.top_k = selected.len();
}
if let Some(trace) = self.trace.as_mut() {
trace[layer].extend(selected.iter().map(|&e| e as u32));
}
self.passes[layer] += 1;
}
// Hand-rolled: nested integer arrays only, and this crate deliberately
// carries no serde.
fn to_json(&self) -> String {
let num_experts = self.counts.first().map_or(0, Vec::len);
let mut out = format!(
"{{\"num_layers\":{},\"num_experts\":{},\"top_k\":{},\"counts\":[",
self.counts.len(),
num_experts,
self.top_k
);
push_rows(&mut out, self.counts.iter().map(|row| row.iter()));
out.push(']');
if let Some(trace) = self.trace.as_ref() {
out.push_str(",\"trace\":[");
push_rows(&mut out, trace.iter().map(|row| row.iter()));
out.push(']');
}
if let Some(pred) = self.pred.as_ref() {
out.push_str(",\"pred\":[");
push_rows(&mut out, pred.iter().map(|row| row.iter()));
out.push(']');
}
if let Some(capture) = self.router_logits.as_ref() {
out.push_str(&format!(
",\"router_logits\":{{\"layer\":{},\"pass\":{},\"values\":",
capture.layer, capture.pass
));
if let Some(values) = capture.values.as_ref() {
out.push('[');
for (index, value) in values.iter().enumerate() {
if index > 0 {
out.push(',');
}
out.push_str(&value.to_string());
}
out.push(']');
} else {
out.push_str("null");
}
out.push('}');
}
out.push('}');
out
}
}
/// `[[a,b],[c]]` without the trailing bracket, which the caller closes.
fn push_rows<'a, R, I, T>(out: &mut String, rows: R)
where
R: Iterator<Item = I>,
I: Iterator<Item = &'a T>,
T: std::fmt::Display + 'a,
{
for (i, row) in rows.enumerate() {
if i > 0 {
out.push(',');
}
out.push('[');
for (j, value) in row.enumerate() {
if j > 0 {
out.push(',');
}
out.push_str(&value.to_string());
}
out.push(']');
}
}
impl Drop for RouterHistogram {
fn drop(&mut self) {
match std::fs::write(&self.path, self.to_json()) {
Ok(()) => eprintln!("[router-hist] wrote {}", self.path.display()),
Err(e) => eprintln!("[router-hist] FAILED writing {}: {e}", self.path.display()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn fixture(trace: bool) -> RouterHistogram {
fixture_with(trace, false)
}
fn fixture_with(trace: bool, pilot: bool) -> RouterHistogram {
RouterHistogram {
path: std::path::PathBuf::new(),
counts: vec![vec![0; 3]; 2],
passes: vec![0; 2],
trace: trace.then(|| vec![Vec::new(); 2]),
pred: pilot.then(|| vec![Vec::new(); 2]),
pilot_self_test: false,
router_logits: None,
top_k: 0,
}
}
#[test]
fn records_and_serializes_layer_expert_counts() {
let mut hist = fixture(false);
hist.record(0, &[2, 0]);
hist.record(0, &[2, 1]);
hist.record(1, &[1, 1]);
assert_eq!(
hist.to_json(),
"{\"num_layers\":2,\"num_experts\":3,\"top_k\":2,\"counts\":[[1,1,2],[0,2,0]]}"
);
// Drop would try to write the (empty) path; forget it so the unit
// test touches no filesystem.
std::mem::forget(hist);
}
#[test]
fn trace_keeps_pass_order_that_the_counts_discard() {
let mut hist = fixture(true);
hist.record(0, &[2, 0]);
hist.record(0, &[2, 1]);
hist.record(1, &[1, 1]);
// Same counts as above, plus the ordering: layer 0's two passes are
// (2,0) then (2,1), which is 3 distinct experts over a window of 2
// against the 4 a union-free cost model would charge.
assert_eq!(
hist.to_json(),
"{\"num_layers\":2,\"num_experts\":3,\"top_k\":2,\
\"counts\":[[1,1,2],[0,2,0]],\"trace\":[[2,0,2,1],[1,1]]}"
);
std::mem::forget(hist);
}
#[test]
fn a_prediction_is_recorded_against_the_layer_it_is_about() {
let mut hist = fixture_with(true, true);
// One pass: layer 0 runs, and while it runs it predicts layer 1.
// Layer 1 then routes to something the prediction got half right.
hist.record(0, &[2, 0]);
hist.record_prediction(1, &[1, 2]);
hist.record(1, &[1, 0]);
// `pred` row 0 stays EMPTY -- nothing precedes layer 0, so no
// prediction is ever made about it, and the analysis must not read
// row 0 as "predicted nothing correctly".
assert_eq!(
hist.to_json(),
"{\"num_layers\":2,\"num_experts\":3,\"top_k\":2,\
\"counts\":[[1,0,1],[1,1,0]],\"trace\":[[2,0],[1,0]],\
\"pred\":[[],[1,2]]}"
);
std::mem::forget(hist);
}
#[test]
fn predictions_are_dropped_when_the_probe_is_off() {
// The probe costs a router GEMV per layer, so the encoders ask
// `pilot_enabled` before paying for one. If that ever returned true
// with no storage behind it, `record_prediction` would silently
// discard and the capture would look like a 0%-recall predictor
// rather than like a disabled probe.
let mut hist = fixture_with(true, false);
assert!(!hist.pilot_enabled());
hist.record_prediction(1, &[1, 2]);
hist.record(0, &[2, 0]);
assert!(!hist.to_json().contains("pred"));
std::mem::forget(hist);
}
#[test]
fn the_probe_reports_enabled_only_when_storage_exists() {
let (on, off) = (fixture_with(true, true), fixture_with(true, false));
assert!(on.pilot_enabled());
assert!(!off.pilot_enabled());
// `Drop` writes to `path`, which is empty here; forget both so the
// unit test touches no filesystem, as its siblings above do.
std::mem::forget(on);
std::mem::forget(off);
}
#[test]
fn router_logits_capture_targets_one_layer_and_pass() {
let mut hist = fixture(false);
hist.router_logits = Some(RouterLogitsCapture {
layer: 1,
pass: 1,
values: None,
});
hist.record_router_logits(0, &[9.0, 8.0, 7.0]);
hist.record(0, &[0, 1]);
hist.record_router_logits(1, &[6.0, 5.0, 4.0]);
hist.record(1, &[0, 1]);
hist.record_router_logits(1, &[3.5, 2.5, 1.5]);
assert!(hist
.to_json()
.contains("\"router_logits\":{\"layer\":1,\"pass\":1,\"values\":[3.5,2.5,1.5]}"));
std::mem::forget(hist);
}
}