metrale_model_layers/layer/transformer_layer/split_prefill.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-26: `LayerSplitPrefill`, the phased and batched prefill entry points: the SSM phase 1
4//! pieces, the GDN recurrence per stream, batched and varlen, phase 3, and the batched
5//! attention prefill.
6//!
7//! Owner: model-layers.
8//! Invariants: none beyond the types.
9
10use anyhow::Result;
11use metrale_cache::kv_cache::PagedKvCache;
12use metrale_gpu_runtime::gpu::DevicePtr;
13
14use crate::layer::{BatchedAttnMetadata, ForwardContext, GdnPrefillBuffers, LayerState};
15
16/// 2026-09-26: A supertrait of `TransformerLayer`; see the module header.
17pub trait LayerSplitPrefill {
18 /// 2026-09-25: Phase 1 projections (norm, QKVZ, gates) over all stacked tokens of a
19 /// batched prefill at once. The caller then runs `prefill_phase1_conv1d_one` per
20 /// request and `prefill_phase1_l2_batched`. The default returns an error.
21 fn prefill_phase1_proj_batched(
22 &self,
23 hidden_stacked: DevicePtr,
24 residual_stacked: DevicePtr,
25 total_tokens: usize,
26 gdn_bufs: &GdnPrefillBuffers,
27 ctx: &ForwardContext,
28 stream: u64,
29 ) -> Result<()> {
30 let _ = (
31 hidden_stacked,
32 residual_stacked,
33 total_tokens,
34 gdn_bufs,
35 ctx,
36 stream,
37 );
38 anyhow::bail!("prefill_phase1_proj_batched: only implemented for SSM layers")
39 }
40
41 /// 2026-09-25: Conv1d over one request's tokens of a batched prefill, advancing its
42 /// conv state and writing its slice of `gdn_bufs.qkv`. The default returns an error.
43 fn prefill_phase1_conv1d_one(
44 &self,
45 state: &mut dyn LayerState,
46 token_offset: usize,
47 len: usize,
48 gdn_bufs: &GdnPrefillBuffers,
49 ctx: &ForwardContext,
50 stream: u64,
51 ) -> Result<()> {
52 let _ = (state, token_offset, len, gdn_bufs, ctx, stream);
53 anyhow::bail!("prefill_phase1_conv1d_one: only implemented for SSM layers")
54 }
55
56 /// 2026-09-25: L2 norm over the whole stacked `gdn_bufs.qkv`, after every request's
57 /// conv1d. The default returns an error.
58 fn prefill_phase1_l2_batched(
59 &self,
60 total_tokens: usize,
61 gdn_bufs: &GdnPrefillBuffers,
62 ctx: &ForwardContext,
63 stream: u64,
64 ) -> Result<()> {
65 let _ = (total_tokens, gdn_bufs, ctx, stream);
66 anyhow::bail!("prefill_phase1_l2_batched: only implemented for SSM layers")
67 }
68
69 /// 2026-09-25: Split SSM prefill, phase 2: the GDN recurrence over all
70 /// `gdn_bufs.total_len` tokens, reading packed QKV and gate/beta and writing `output`.
71 /// Default: nothing.
72 fn prefill_gdn_full(
73 &self,
74 _state: &mut dyn LayerState,
75 _gdn_bufs: &GdnPrefillBuffers,
76 _ctx: &ForwardContext,
77 _stream: u64,
78 ) -> Result<()> {
79 Ok(())
80 }
81
82 /// 2026-09-25: Prefill of one attention layer over the stacked tokens of several
83 /// streams, with per-stream metadata from `batched_meta`. The default returns an
84 /// error; the Qwen3 attention layer overrides it.
85 fn prefill_inner_batched_q12(
86 &self,
87 _hidden_stacked: DevicePtr,
88 _residual_stacked: DevicePtr,
89 _num_tokens: usize,
90 _kv_cache: &mut PagedKvCache,
91 _seq_len_start: usize,
92 _batched_meta: &BatchedAttnMetadata,
93 _ctx: &ForwardContext,
94 _stream: u64,
95 ) -> Result<()> {
96 anyhow::bail!("prefill_inner_batched_q12: not implemented for this layer type")
97 }
98
99 /// 2026-09-25: GDN recurrence for `batch_size` streams of equal length `chunk_len` in
100 /// one call. `h_state_ptrs` is a device array of one h-state pointer per stream
101 /// (`TransformerModel::stage_h_state_ptrs`), and the streams' tokens lie back to back
102 /// in `gdn_bufs`. `prefill_ssm_batched_layer` calls it only when every stream has
103 /// the same length. The default returns an error.
104 fn prefill_gdn_full_batched(
105 &self,
106 _h_state_ptrs: DevicePtr,
107 _gdn_bufs: &GdnPrefillBuffers,
108 _batch_size: u32,
109 _chunk_len: u32,
110 _ctx: &ForwardContext,
111 _stream: u64,
112 ) -> Result<()> {
113 anyhow::bail!(
114 "prefill_gdn_full_batched: layer does not implement batched GDN \
115 — caller should fall back to per-stream prefill_gdn_full"
116 )
117 }
118
119 /// 2026-09-25: GDN recurrence for streams of different lengths in one FLA call,
120 /// driven by `cu_seqlens`. `Ok(true)` if it ran; `Ok(false)` if not eligible, and the
121 /// caller then runs `prefill_gdn_full` per stream. Default `Ok(false)`.
122 #[allow(clippy::too_many_arguments)]
123 fn prefill_gdn_full_batched_fla_varlen(
124 &self,
125 _h_state_ptrs: DevicePtr,
126 _gdn_bufs: &GdnPrefillBuffers,
127 _batch_size: u32,
128 _cu_seqlens: DevicePtr,
129 _max_num_chunks: u32,
130 _total_nt: usize,
131 _max_seqlen: u32,
132 _ctx: &ForwardContext,
133 _stream: u64,
134 ) -> Result<bool> {
135 Ok(false)
136 }
137
138 /// 2026-09-25: Split SSM prefill, phase 3: for `num_tokens` tokens at `token_offset`,
139 /// gated RMSNorm of the GDN output with Z, the output projection, the residual add and
140 /// the FFN. Default: nothing.
141 #[allow(clippy::too_many_arguments)]
142 fn prefill_phase3(
143 &self,
144 _hidden: DevicePtr,
145 _residual: DevicePtr,
146 _num_tokens: usize,
147 _gdn_bufs: &GdnPrefillBuffers,
148 _token_offset: usize,
149 _ctx: &ForwardContext,
150 _stream: u64,
151 ) -> Result<()> {
152 Ok(())
153 }
154}