metrale_model_layers/layers/ops/
ssm_gdn_tc_route.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-25: The GDN prefill state spines' entry names, and the route lines
4//! built from them.
5//!
6//! # Why the name is a constant
7//!
8//! The tensor-core module holds two entries, `…_tcfuse` (one bf16 limb of
9//! `S_c`) and `…_tcfuse_x2` (two limbs), and the lever ships `_x2`. A route
10//! line that names only the family, such as
11//!
12//! ```text
13//! GDN state spine: gated_delta_rule_chunk_delta_h_tcfuse (METRALE_GDN_PREFILL_TC; …)
14//! ```
15//!
16//! reads as the 1-limb entry. So the name exists once, here:
17//! `qwen3_ssm::init_kernels` binds the handle with it and
18//! [`gdn_tc_spine_route_line`] prints it.
19//!
20//! Owner: model-layers ops (GDN).
21//! Invariants: none beyond the types.
22
23/// 2026-09-25: The spine entry the `gdn_prefill_tc` lever launches: two bf16
24/// limbs of `S_c`. Both entries take the same arguments, grid, block and
25/// shared memory, so nothing downstream depends on which one is bound.
26pub const GDN_TC_SPINE_ENTRY: &str = "gated_delta_rule_chunk_delta_h_tcfuse_x2";
27
28/// 2026-09-25: The module the entry lives in:
29/// `kernels/hopper/common/gated_delta_rule_chunk_tc.cu`.
30pub const GDN_TC_SPINE_MODULE: &str = "gated_delta_rule_chunk_tc";
31
32/// 2026-09-25: The scalar spine entries `init_kernels::fused_spine_kernel`
33/// binds, as [`gdn_scalar_spine`] picks them. The init route line and the
34/// handle are built from the same strings.
35/// 2026-09-28: The default: `_vfused`'s arithmetic with W, K and U double-buffered
36/// through cp.async (bit-identical to `_vfused`, 1.4x faster on GB10 at 1.6k-8k
37/// tokens per chunk).
38pub const GDN_SCALAR_SPINE_PIPE: &str = "gated_delta_rule_chunk_delta_h_pipe";
39/// 2026-09-25: SPLIT=4, 512 threads. Not the default; `fused_spine_kernel`'s
40/// doc says why.
41pub const GDN_SCALAR_SPINE_VTILE: &str = "gated_delta_rule_chunk_delta_h_vtile";
42/// 2026-09-25: SPLIT=2, 256 threads, single-buffered; `METRALE_GDN_PIPE=0`.
43pub const GDN_SCALAR_SPINE_VFUSED: &str = "gated_delta_rule_chunk_delta_h_vfused";
44
45/// 2026-09-28: The scalar spine a process binds (`init_kernels::fused_spine_kernel`) and
46/// launches (`ops::gdn_prefill_fla`, whose block size and shared memory depend on it). Both
47/// read it through [`gdn_scalar_spine`], so they cannot disagree.
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub enum GdnScalarSpine {
50    Pipe,
51    Vtile,
52    Vfused,
53}
54
55impl GdnScalarSpine {
56    pub fn entry(self) -> &'static str {
57        match self {
58            Self::Pipe => GDN_SCALAR_SPINE_PIPE,
59            Self::Vtile => GDN_SCALAR_SPINE_VTILE,
60            Self::Vfused => GDN_SCALAR_SPINE_VFUSED,
61        }
62    }
63}
64
65/// 2026-09-28: From the values of `METRALE_GDN_PIPE` and `METRALE_GDN_VTILE`: `PIPE=1`
66/// picks the pipe spine (as before), else `VTILE=1` the vtile spine, else `PIPE=0` the
67/// vfused spine, else the pipe spine.
68pub fn gdn_scalar_spine_from(pipe: Option<&str>, vtile: Option<&str>) -> GdnScalarSpine {
69    match (pipe, vtile) {
70        (Some("1"), _) => GdnScalarSpine::Pipe,
71        (_, Some("1")) => GdnScalarSpine::Vtile,
72        (Some("0"), _) => GdnScalarSpine::Vfused,
73        _ => GdnScalarSpine::Pipe,
74    }
75}
76
77/// 2026-09-28: [`gdn_scalar_spine_from`] of this process's environment, read once.
78pub fn gdn_scalar_spine() -> GdnScalarSpine {
79    static SPINE: std::sync::OnceLock<GdnScalarSpine> = std::sync::OnceLock::new();
80    *SPINE.get_or_init(|| {
81        gdn_scalar_spine_from(
82            std::env::var("METRALE_GDN_PIPE").ok().as_deref(),
83            std::env::var("METRALE_GDN_VTILE").ok().as_deref(),
84        )
85    })
86}
87
88/// 2026-09-25: `GDN state spine: …`, the line `qwen3_ssm::init` prints for
89/// each layer as it binds the handles, before any prefill has run.
90///
91/// # Why it is not simply the scalar entry's name
92///
93/// With the tensor-core handle bound, the prefill launches
94/// [`GDN_TC_SPINE_ENTRY`], and the scalar entry stays bound only as the
95/// fallback the prefill's shape guards drop to. An init line that named the
96/// scalar entry would contradict the prefill's line:
97///
98/// ```text
99///    48  qwen3_ssm::init: GDN state spine: gated_delta_rule_chunk_delta_h_vfused
100/// 14400  GDN state spine: gated_delta_rule_chunk_delta_h_tcfuse_x2 (…)
101/// ```
102///
103/// So the line follows the handle the probe resolved: bound, it names
104/// [`GDN_TC_SPINE_ENTRY`]; unbound, `scalar_entry`.
105pub fn gdn_init_spine_line(tc_spine_bound: bool, scalar_entry: &str) -> String {
106    if tc_spine_bound {
107        format!(
108            "GDN state spine: {GDN_TC_SPINE_ENTRY} ([defaults] gdn_prefill_tc; the \
109             scalar spine stays bound as the fallback the prefill's shape guards \
110             drop to, and the prefill logs the entry it launches)"
111        )
112    } else {
113        format!("GDN state spine: {scalar_entry}")
114    }
115}
116
117/// 2026-09-25: `GDN state spine: …`, the line the prefill logs when the
118/// tensor-core spine runs, built from [`GDN_TC_SPINE_ENTRY`]. Pure and
119/// returning a `String`, so the tests below can check it.
120pub fn gdn_tc_spine_route_line(num_v_heads: u32, batch_size: u32, smem_bytes: u32) -> String {
121    format!(
122        "GDN state spine: {GDN_TC_SPINE_ENTRY} (METRALE_GDN_PREFILL_TC; bf16 mma.sync \
123         operands, f32 accumulator = the recurrent state, h stays f32) \
124         grid=[{num_v_heads},{batch_size}] block=256 smem={smem_bytes}B"
125    )
126}
127
128#[cfg(test)]
129mod tests {
130    use super::{
131        GDN_SCALAR_SPINE_PIPE, GDN_SCALAR_SPINE_VFUSED, GDN_SCALAR_SPINE_VTILE, GDN_TC_SPINE_ENTRY,
132        GdnScalarSpine, gdn_init_spine_line, gdn_scalar_spine_from, gdn_tc_spine_route_line,
133    };
134
135    /// 2026-09-28: The pipe spine by default and under `PIPE=1` (which also wins over
136    /// `VTILE=1`, as before), vtile under `VTILE=1`, vfused only under `PIPE=0`; any other
137    /// value is the default.
138    #[test]
139    fn scalar_spine_choice() {
140        use GdnScalarSpine::*;
141        for (pipe, vtile, want) in [
142            (None, None, Pipe),
143            (Some("1"), None, Pipe),
144            (Some("1"), Some("1"), Pipe),
145            (None, Some("1"), Vtile),
146            (Some("0"), Some("1"), Vtile),
147            (Some("0"), None, Vfused),
148            (Some("0"), Some("0"), Vfused),
149            (Some("yes"), None, Pipe),
150            (None, Some("0"), Pipe),
151        ] {
152            assert_eq!(
153                gdn_scalar_spine_from(pipe, vtile),
154                want,
155                "{pipe:?} {vtile:?}"
156            );
157        }
158        assert_eq!(Pipe.entry(), GDN_SCALAR_SPINE_PIPE);
159        assert_eq!(Vtile.entry(), GDN_SCALAR_SPINE_VTILE);
160        assert_eq!(Vfused.entry(), GDN_SCALAR_SPINE_VFUSED);
161    }
162
163    /// 2026-09-25: The line names the `_x2` entry, never the bare family name
164    /// (`…_tcfuse` followed by a space).
165    #[test]
166    fn the_route_line_names_the_entry_that_is_launched() {
167        let line = gdn_tc_spine_route_line(48, 1, 88_324);
168        assert!(line.contains(GDN_TC_SPINE_ENTRY), "{line}");
169        assert!(
170            !line.contains("gated_delta_rule_chunk_delta_h_tcfuse "),
171            "the line must not name the FAMILY where the binary launches the \
172             `_x2` member — round 12 stage 4b:\n{line}"
173        );
174    }
175
176    /// 2026-09-25: The line carries the launch geometry.
177    #[test]
178    fn the_route_line_carries_the_geometry() {
179        let line = gdn_tc_spine_route_line(48, 2, 88_324);
180        for field in [
181            "grid=[48,2]",
182            "block=256",
183            "smem=88324B",
184            "METRALE_GDN_PREFILL_TC",
185        ] {
186            assert!(line.contains(field), "missing `{field}` in:\n{line}");
187        }
188    }
189
190    /// 2026-09-25: With the tensor-core handle bound, the init line names that
191    /// entry, not the scalar spine bound behind it.
192    #[test]
193    fn the_init_line_names_the_tc_entry_when_its_handle_is_bound() {
194        let line = gdn_init_spine_line(true, GDN_SCALAR_SPINE_VFUSED);
195        assert!(line.contains(GDN_TC_SPINE_ENTRY), "{line}");
196        assert!(
197            !line.contains(GDN_SCALAR_SPINE_VFUSED),
198            "the init line must not NAME the scalar spine where the probe bound \
199             the tensor-core one:\n{line}"
200        );
201    }
202
203    /// 2026-09-25: The init line and the prefill's line name the same entry.
204    #[test]
205    fn the_two_route_lines_agree_on_the_entry() {
206        let init = gdn_init_spine_line(true, GDN_SCALAR_SPINE_VFUSED);
207        let dispatch = gdn_tc_spine_route_line(48, 1, 88_324);
208        for line in [&init, &dispatch] {
209            assert!(line.contains(GDN_TC_SPINE_ENTRY), "{line}");
210        }
211    }
212
213    /// 2026-09-25: With the probe off (by default, every target but
214    /// `kernels/hopper`), the line names the scalar entry, for each of the
215    /// three.
216    #[test]
217    fn the_init_line_names_the_scalar_entry_when_the_probe_is_off() {
218        for entry in [
219            GDN_SCALAR_SPINE_PIPE,
220            GDN_SCALAR_SPINE_VTILE,
221            GDN_SCALAR_SPINE_VFUSED,
222        ] {
223            assert_eq!(
224                gdn_init_spine_line(false, entry),
225                format!("GDN state spine: {entry}"),
226            );
227        }
228    }
229}