Skip to main content

qualia_core_db/gguf_bridge/
resident_decode.rs

1//! Native GPU-resident single-fence token decode.
2//!
3//! The legacy native decode path round-trips the hidden state through the CPU
4//! twice per layer (attention readback + FFN readback), paying ~2 blocking
5//! `submit → poll(wait)` fences and two CPU RMSNorm/residual-adds per layer —
6//! ~107 fences/token measured on SmolLM2-360M (A2000, Vulkan), ~24% of the
7//! token in pure fence latency plus the GPU idling through every CPU
8//! turnaround.
9//!
10//! This module keeps the hidden state resident in VRAM for the WHOLE token:
11//! per layer it encodes RMSNorm (elem op) → K/V/Q preprojection (coop GEMV) +
12//! KV-cache write → Q-SDPA (reads precomputed Q) → O-projection → residual add
13//! (elem) → RMSNorm (elem) → fused FFN expansion (`fused_ffn.wgsl` when gate/up
14//! share a supported quant; else gate/up GEMV + SiLU·mul) → down GEMV → residual
15//! add (elem), then the output RMSNorm and the chunked logits GEMV + top-1
16//! block reduction — all into ONE command encoder, ONE submit, ONE fence, with
17//! a ~400-byte candidate readback.
18//! It is the native mirror of the proven wasm MC8 fused-encoder design
19//! (`mc8_wasm/`), built from the same kernels the legacy path already runs:
20//! `coop_gemv`/`main` GEMV, `fused_ffn.wgsl`, `fused_attention.wgsl`,
21//! `wasm_elementwise.wgsl`, `topk_reduction.wgsl`. The GPU RMSNorm reduces in
22//! the same sequential order as the CPU `rms_norm_inplace`, so decode output is
23//! expected token-identical to the legacy path (asserted by the `a1d` differential test).
24//!
25//! All bind groups and static uniform slots are created ONCE per model (the
26//! weights are Phase-2 resident, so bindings are stable). Per token the driver
27//! writes: the embedded token (n_embd floats), the per-layer attention uniform
28//! block (token_idx / KV mask fields — one `write_buffer`), and the KV mask
29//! words. Everything else is pre-encoded state.
30//!
31//! Toggle: `QUALIA_LLM_RESIDENT_DECODE` / `set_resident_decode` (default ON).
32//! Any ineligibility (unsupported quant, missing resident logits, layer cap,
33//! sieve mask) falls back to the legacy per-layer path unchanged.
34
35#![cfg(not(target_arch = "wasm32"))]
36
37use super::*;
38
39/// 256-byte uniform slot stride (WebGPU min uniform offset alignment).
40const SLOT: wgpu::BufferAddress = 256;
41/// Resident logits buffer cap. Sized to cover Llama-3.2 128256 vocab in **one**
42/// GEMV+topk wave (E3). Was 32768 (= 4 chunks); full-vocab eliminates the multi-chunk tax.
43const RESIDENT_LOGITS_CHUNK: usize = 131_072;
44
45/// Static GEMM param slots per layer: K, V, Q, O, gate, up, down.
46const GEMM_SLOTS_PER_LAYER: u64 = 7;
47/// Dynamic attention param slots per layer: K-write, V-write, Q-SDPA.
48const ATTN_SLOTS_PER_LAYER: u64 = 3;
49
50/// Elem param slots (shared across layers): rms(n_embd), add(n_embd), silu(n_ffn).
51const ELEM_SLOT_RMS: wgpu::BufferAddress = 0;
52const ELEM_SLOT_ADD: wgpu::BufferAddress = SLOT;
53const ELEM_SLOT_SILU: wgpu::BufferAddress = SLOT * 2;
54const ELEM_SLOTS: u64 = 3;
55
56/// One transformer layer's pre-built bind groups (encode order).
57struct LayerBinds {
58    rms_attn: wgpu::BindGroup,
59    /// Triple Q+K+V GEMV (shared act, GQA) when SoA — preferred over dual+q.
60    triple_qkv: Option<wgpu::BindGroup>,
61    /// Dual K+V GEMV (shared act) when SoA and triple unavailable; else k_gemm/v_gemm.
62    dual_kv: Option<wgpu::BindGroup>,
63    k_gemm: wgpu::BindGroup,
64    k_write: wgpu::BindGroup,
65    v_gemm: wgpu::BindGroup,
66    v_write: wgpu::BindGroup,
67    /// Coop GEMV: normed → q_proj (decoupled from attention shader).
68    q_gemm: wgpu::BindGroup,
69    /// Q-SDPA over precomputed Q (`proj_row_stride = q_dim`).
70    q: wgpu::BindGroup,
71    /// O-proj + residual (coop_gemv_residual) → hidden_b.
72    o_resid: wgpu::BindGroup,
73    rms_ffn: wgpu::BindGroup,
74    /// T-A1: silu(gate·x)·(up·x) in one pass when set; else use gate/up/silu.
75    fused_ffn: Option<wgpu::BindGroup>,
76    gate: Option<wgpu::BindGroup>,
77    up: Option<wgpu::BindGroup>,
78    silu: Option<wgpu::BindGroup>,
79    /// Down-proj + residual (coop_gemv_residual) → hidden_a.
80    down_resid: wgpu::BindGroup,
81}
82
83/// ggml types supported by coop fused FFN (incl. Q4_K_SOA for 3B layouts). Not F16.
84fn fused_ffn_quant_supported(ggml_type: u32) -> bool {
85    use crate::ggml_quants::{
86        GGML_TYPE_Q4_0, GGML_TYPE_Q4_K, GGML_TYPE_Q4_K_SOA, GGML_TYPE_Q5_0, GGML_TYPE_Q6_K,
87        GGML_TYPE_Q8_0,
88    };
89    matches!(
90        ggml_type,
91        GGML_TYPE_Q4_0
92            | GGML_TYPE_Q5_0
93            | GGML_TYPE_Q8_0
94            | GGML_TYPE_Q4_K
95            | GGML_TYPE_Q4_K_SOA
96            | GGML_TYPE_Q6_K
97    )
98}
99
100/// One output-projection vocab chunk (GEMV + top-1 reduction).
101struct OutChunk {
102    gemm: wgpu::BindGroup,
103    topk: wgpu::BindGroup,
104    rows: u32,
105    cand_count: usize,
106}
107
108/// Per-layer prototype attention params; per token only the position/mask
109/// fields are patched before the single dynamic-arena upload.
110struct LayerProtos {
111    k_write: AttentionGpuParams,
112    v_write: AttentionGpuParams,
113    q: AttentionGpuParams,
114}
115
116pub(crate) struct ResidentDecodePlan {
117    /// (mmap base, tensor_data_start, n_layer) — invalidates on model swap.
118    key: (u64, u64, u32),
119    n_embd: usize,
120    n_ffn: usize,
121    kv_dim: usize,
122    q_dim: usize,
123    n_head: u32,
124    n_kv_head: u32,
125    layout: KvCacheLayout,
126    layer_protos: Vec<LayerProtos>,
127    layers: Vec<LayerBinds>,
128    rms_out: wgpu::BindGroup,
129    out_chunks: Vec<OutChunk>,
130    total_cands: usize,
131    /// Dynamic (per-token) attention uniform arena: `n_layer × 3` slots.
132    attn_dyn_arena: wgpu::Buffer,
133    /// Reused CPU staging for the dynamic arena (no per-token heap alloc).
134    dyn_scratch: Vec<u8>,
135    /// Embedded-token upload target; also the residual stream (layer in/out).
136    hidden_a: wgpu::Buffer,
137    /// Post-output-norm hidden (logits GEMV input); `COPY_SRC` for sample-path readback.
138    normed: wgpu::Buffer,
139    /// Candidate readback staging: `[vals(total_cands) | idxs(total_cands)]`.
140    staging: wgpu::Buffer,
141    /// Full-hidden MAP_READ staging for sampler-compatible resident (n_embd f32).
142    hidden_staging: wgpu::Buffer,
143    use_coop: bool,
144    /// Multi-row coop GEMV (8 rows/WG) — armed for Q4_K_SOA decode (3B bandwidth path).
145    use_multirow: bool,
146    /// Warp GEMV (32 thr/row) for Q4_K_SOA — more FMA/thread than 256-wide coop.
147    use_warp: bool,
148    /// Multi-row fused FFN (4 rows/WG) for Q4_K_SOA.
149    use_ffn_mr: bool,
150    /// Warp fused FFN (32 thr/row) for Q4_K_SOA.
151    use_ffn_warp: bool,
152    /// True when every layer has fused_ffn bind groups (T-A1).
153    /// Read by lab audit via `ffn_fusion_in_resident()`; kept on plan for diagnostics.
154    #[allow(dead_code)]
155    use_fused_ffn: bool,
156    /// Exact compute dispatches encoded for one token on this prepared plan.
157    dispatches_per_token: u32,
158    /// Candidate bytes copied into the MAP_READ staging buffer per token.
159    readback_bytes_per_token: u32,
160}
161
162pub(crate) enum ResidentDecodeState {
163    Unbuilt,
164    /// Build failed for this model — don't retry every token.
165    Ineligible(u64),
166    Ready(Box<ResidentDecodePlan>),
167}
168
169/// Greedy → argmax token; sample path → post-norm hidden was written to the caller buffer.
170enum ResidentTokenOutcome {
171    Argmax(StreamingArgmaxResult),
172    HiddenReady,
173}
174
175impl QTensorEngine {
176    /// Exact steady-state compute dispatch count for the prepared resident plan.
177    pub fn resident_dispatches_per_token(&self) -> Option<u32> {
178        match &self.resident_decode {
179            ResidentDecodeState::Ready(plan) => Some(plan.dispatches_per_token),
180            _ => None,
181        }
182    }
183
184    /// Exact candidate staging copy size for one resident greedy token.
185    pub fn resident_readback_bytes_per_token(&self) -> Option<u32> {
186        match &self.resident_decode {
187            ResidentDecodeState::Ready(plan) => Some(plan.readback_bytes_per_token),
188            _ => None,
189        }
190    }
191
192    fn plan_key(&self, index: &crate::gguf_sharder::GgufTensorIndex) -> (u64, u64, u32) {
193        let base = self
194            .gguf_mmap
195            .as_deref()
196            .map(|m| m.as_ptr() as u64)
197            .unwrap_or(0);
198        (base, index.tensor_data_start, index.hyperparams.n_layer)
199    }
200
201    /// Single-fence resident-token decode (greedy top-1). Returns the argmax token, or `None`
202    /// on any ineligibility (caller falls back to the legacy per-layer path).
203    pub fn dispatch_token_forward_resident(
204        &mut self,
205        index: &crate::gguf_sharder::GgufTensorIndex,
206        emb: &[f32],
207        token_idx: u32,
208    ) -> Option<StreamingArgmaxResult> {
209        match self.with_resident_plan(index, |this, plan| {
210            this.run_resident_token(plan, emb, token_idx, None)
211        })? {
212            Some(ResidentTokenOutcome::Argmax(a)) => Some(a),
213            _ => None,
214        }
215    }
216
217    /// Sampler-compatible resident forward: same single-fence layer stack + output
218    /// RMSNorm, then read back the normed hidden into `out_hidden` so the caller can
219    /// project full logits + sample on CPU without the legacy ~107-fence path.
220    ///
221    /// `emb` is the token embedding input; `out_hidden` receives post-output-norm state
222    /// (may be the same logical buffer only if the caller copies input first — they must
223    /// not alias while the upload of `emb` is live; pass distinct slices).
224    pub fn dispatch_token_forward_resident_hidden(
225        &mut self,
226        index: &crate::gguf_sharder::GgufTensorIndex,
227        emb: &[f32],
228        token_idx: u32,
229        out_hidden: &mut [f32],
230    ) -> bool {
231        matches!(
232            self.with_resident_plan(index, |this, plan| {
233                this.run_resident_token(plan, emb, token_idx, Some(out_hidden))
234            }),
235            Some(Some(ResidentTokenOutcome::HiddenReady))
236        )
237    }
238
239    fn with_resident_plan<R>(
240        &mut self,
241        index: &crate::gguf_sharder::GgufTensorIndex,
242        f: impl FnOnce(&Self, &mut ResidentDecodePlan) -> R,
243    ) -> Option<R> {
244        if !crate::llm_bench::resident_decode_enabled()
245            || !crate::llm_bench::resident_weights_enabled()
246            || crate::llm_bench::cpu_attention_enabled()
247            || crate::llm_bench::kv_dict_enabled()
248        {
249            return None;
250        }
251        // Note: do NOT skip resident for mode=cuda — the wgpu mega-pass is still faster
252        // end-to-end than legacy host-layered CUDA GEMVs. CUDA FFN block helps the
253        // non-resident / fused-resident FFN cold path only.
254        let key = self.plan_key(index);
255        let state = std::mem::replace(&mut self.resident_decode, ResidentDecodeState::Unbuilt);
256        let mut plan = match state {
257            ResidentDecodeState::Ready(p) if p.key == key => p,
258            ResidentDecodeState::Ineligible(k) if k == (key.0 ^ key.1) => {
259                self.resident_decode = ResidentDecodeState::Ineligible(k);
260                return None;
261            }
262            _ => match self.build_resident_plan(index, key) {
263                Some(p) => p,
264                None => {
265                    wlog("[resident-decode] plan build ineligible — legacy path");
266                    self.resident_decode = ResidentDecodeState::Ineligible(key.0 ^ key.1);
267                    return None;
268                }
269            },
270        };
271        let result = f(self, &mut plan);
272        self.resident_decode = ResidentDecodeState::Ready(plan);
273        Some(result)
274    }
275
276    fn run_resident_token(
277        &self,
278        plan: &mut ResidentDecodePlan,
279        emb: &[f32],
280        token_idx: u32,
281        out_hidden: Option<&mut [f32]>,
282    ) -> Option<ResidentTokenOutcome> {
283        let n_embd = plan.n_embd;
284        if emb.len() < n_embd || token_idx >= plan.layout.max_context {
285            return None;
286        }
287        let queue = self.gpu_queue();
288
289        // 1) Per-token uploads: embedding + dynamic attention params.
290        // Skip full KV-mask upload when route mask is inactive (common path).
291        queue.write_buffer(&plan.hidden_a, 0, bytemuck::cast_slice(&emb[..n_embd]));
292
293        let (mask_words, mask_active) =
294            crate::compute_universe::attention_kv_mask_u32(token_idx, plan.layout.max_context);
295        if mask_active != 0 {
296            queue.write_buffer(
297                self.attention_mask_buf.as_ref()?,
298                0,
299                bytemuck::cast_slice(&mask_words),
300            );
301        }
302
303        let ap_size = std::mem::size_of::<AttentionGpuParams>();
304        for (l, protos) in plan.layer_protos.iter().enumerate() {
305            let base = l as u64 * ATTN_SLOTS_PER_LAYER * SLOT;
306            let mut k = protos.k_write;
307            k.token_idx = token_idx;
308            k.batch_start_token_idx = token_idx;
309            let mut v = protos.v_write;
310            v.token_idx = token_idx;
311            v.batch_start_token_idx = token_idx;
312            let mut q = protos.q;
313            q.token_idx = token_idx;
314            q.batch_start_token_idx = token_idx;
315            q.mask_active = mask_active;
316            q.mask_word_count = if mask_active != 0 {
317                KV_ATTENTION_MASK_WORDS as u32
318            } else {
319                0
320            };
321            for (slot, p) in [(0u64, &k), (1, &v), (2, &q)] {
322                let off = (base + slot * SLOT) as usize;
323                plan.dyn_scratch[off..off + ap_size].copy_from_slice(bytemuck::bytes_of(p));
324            }
325        }
326        queue.write_buffer(&plan.attn_dyn_arena, 0, &plan.dyn_scratch);
327
328        // 2) Encode the WHOLE token in ONE compute pass: all layers + output norm + logits.
329        // Previously: 15 passes/layer × 28–32 layers + norm + per-chunk logits ≈ 450+ passes.
330        // Then: 1 pass/layer. Now: **one pass for the entire forward**. Driver overhead collapses.
331        let mut encoder =
332            self.gpu_device()
333                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
334                    label: Some("ResidentTokenEncoder"),
335                });
336        let rms = self.elem_gpu_pipeline(ELEM_OP_RMS_NORM)?;
337        let silu = &self.elem_silu_mul_pipeline;
338        let attn = &self.attention_pipeline;
339        let sample_path = out_hidden.is_some();
340        let topk = if sample_path {
341            None
342        } else {
343            Some(self.output_topk_pipeline.as_ref()?)
344        };
345
346        // Projection GEMV (Q, K/V fallback): always 1-row/WG.
347        // Residual O/down + logits: multi-row when plan.use_multirow.
348        let gemv_proj_wg = |n_out: u32| {
349            if plan.use_coop {
350                n_out
351            } else {
352                n_out.div_ceil(64)
353            }
354        };
355        let gemv_large_wg = |n_out: u32| {
356            if plan.use_coop && plan.use_multirow {
357                crate::llm_bench::coop_gemv_workgroups(n_out)
358            } else if plan.use_coop {
359                n_out
360            } else {
361                n_out.div_ceil(64)
362            }
363        };
364        let elem_wg = |n: u32| n.div_ceil(64);
365        let (n_embd_u, n_ffn_u) = (n_embd as u32, plan.n_ffn as u32);
366        let kv_dim_u = plan.kv_dim as u32;
367        let q_dim_u = plan.q_dim as u32;
368
369        {
370            // Lab L1.1: optional TIMESTAMP_QUERY around the mega-pass (FusedBlock phase).
371            let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
372                label: Some("ResidentFullToken"),
373                timestamp_writes: crate::llm_gpu_profiler::pass_writes_both(),
374            });
375            // Fused FFN: multi-row (4 rows/WG) for Q4 SoA; else coop 256; else naive.
376            const FFN_MR_ROWS: u32 = 4;
377            let (fused_pipe, fused_wg) = if plan.use_coop && plan.use_ffn_mr {
378                (
379                    &self.ffn_fused_mr_pipeline,
380                    n_ffn_u.div_ceil(FFN_MR_ROWS).max(1),
381                )
382            } else if plan.use_coop && plan.use_ffn_warp {
383                (&self.ffn_fused_warp_pipeline, n_ffn_u)
384            } else if plan.use_coop {
385                (&self.ffn_fused_coop_pipeline, n_ffn_u)
386            } else {
387                (&self.ffn_fused_pipeline, n_ffn_u.div_ceil(64))
388            };
389            let gemv_proj = if plan.use_coop {
390                &self.coop_gemv_pipeline
391            } else {
392                &self.pipeline
393            };
394            let gemv_large = if plan.use_coop && plan.use_multirow {
395                &self.coop_gemv_mr_pipeline
396            } else if plan.use_coop && plan.use_warp {
397                &self.coop_gemv_warp_pipeline
398            } else if plan.use_coop {
399                &self.coop_gemv_pipeline
400            } else {
401                &self.pipeline
402            };
403            let gemv_resid = if plan.use_multirow {
404                &self.coop_gemv_residual_mr_pipeline
405            } else if plan.use_warp {
406                &self.coop_gemv_residual_warp_pipeline
407            } else {
408                &self.coop_gemv_residual_pipeline
409            };
410            for lb in &plan.layers {
411                // RMS attn
412                cpass.set_pipeline(rms);
413                cpass.set_bind_group(0, &lb.rms_attn, &[]);
414                cpass.dispatch_workgroups(1, 1, 1);
415                // Triple Q+K+V (shared act) or dual K+V + Q or split.
416                if let Some(ref tri) = lb.triple_qkv {
417                    cpass.set_pipeline(&self.triple_gemv_pipeline);
418                    cpass.set_bind_group(0, tri, &[]);
419                    cpass.dispatch_workgroups(q_dim_u.max(1), 1, 1);
420                    cpass.set_pipeline(attn);
421                    cpass.set_bind_group(0, &lb.k_write, &[]);
422                    cpass.dispatch_workgroups(plan.n_kv_head.max(1), 1, 1);
423                    cpass.set_pipeline(attn);
424                    cpass.set_bind_group(0, &lb.v_write, &[]);
425                    cpass.dispatch_workgroups(plan.n_kv_head.max(1), 1, 1);
426                } else if let Some(ref dual) = lb.dual_kv {
427                    // Dual multi-row (4 rows/WG): opt-in. A/B on A2000 3B lost vs 1-row dual
428                    // (~8.75 vs ~9.0). QUALIA_LLM_DUAL_MR=1 to force.
429                    let dual_mr = matches!(
430                        std::env::var("QUALIA_LLM_DUAL_MR").ok().as_deref(),
431                        Some("1") | Some("true")
432                    );
433                    const DUAL_ROWS: u32 = 4;
434                    if dual_mr {
435                        cpass.set_pipeline(&self.dual_gemv_mr_pipeline);
436                        cpass.set_bind_group(0, dual, &[]);
437                        cpass.dispatch_workgroups(kv_dim_u.div_ceil(DUAL_ROWS).max(1), 1, 1);
438                    } else {
439                        cpass.set_pipeline(&self.dual_gemv_pipeline);
440                        cpass.set_bind_group(0, dual, &[]);
441                        cpass.dispatch_workgroups(kv_dim_u.max(1), 1, 1);
442                    }
443                    cpass.set_pipeline(attn);
444                    cpass.set_bind_group(0, &lb.k_write, &[]);
445                    cpass.dispatch_workgroups(plan.n_kv_head.max(1), 1, 1);
446                    cpass.set_pipeline(attn);
447                    cpass.set_bind_group(0, &lb.v_write, &[]);
448                    cpass.dispatch_workgroups(plan.n_kv_head.max(1), 1, 1);
449                    cpass.set_pipeline(gemv_proj);
450                    cpass.set_bind_group(0, &lb.q_gemm, &[]);
451                    cpass.dispatch_workgroups(gemv_proj_wg(q_dim_u), 1, 1);
452                } else {
453                    cpass.set_pipeline(gemv_proj);
454                    cpass.set_bind_group(0, &lb.k_gemm, &[]);
455                    cpass.dispatch_workgroups(gemv_proj_wg(kv_dim_u), 1, 1);
456                    cpass.set_pipeline(attn);
457                    cpass.set_bind_group(0, &lb.k_write, &[]);
458                    cpass.dispatch_workgroups(plan.n_kv_head.max(1), 1, 1);
459                    cpass.set_pipeline(gemv_proj);
460                    cpass.set_bind_group(0, &lb.v_gemm, &[]);
461                    cpass.dispatch_workgroups(gemv_proj_wg(kv_dim_u), 1, 1);
462                    cpass.set_pipeline(attn);
463                    cpass.set_bind_group(0, &lb.v_write, &[]);
464                    cpass.dispatch_workgroups(plan.n_kv_head.max(1), 1, 1);
465                    cpass.set_pipeline(gemv_proj);
466                    cpass.set_bind_group(0, &lb.q_gemm, &[]);
467                    cpass.dispatch_workgroups(gemv_proj_wg(q_dim_u), 1, 1);
468                }
469                // SDPA + O resid + RMS ffn
470                cpass.set_pipeline(attn);
471                cpass.set_bind_group(0, &lb.q, &[]);
472                cpass.dispatch_workgroups(plan.n_head.max(1), 1, 1);
473                cpass.set_pipeline(gemv_resid);
474                cpass.set_bind_group(0, &lb.o_resid, &[]);
475                cpass.dispatch_workgroups(gemv_large_wg(n_embd_u), 1, 1);
476                cpass.set_pipeline(rms);
477                cpass.set_bind_group(0, &lb.rms_ffn, &[]);
478                cpass.dispatch_workgroups(1, 1, 1);
479                // T-A1 FFN expansion: fused_ffn OR gate+up+silu.
480                if let Some(ref fbg) = lb.fused_ffn {
481                    cpass.set_pipeline(fused_pipe);
482                    cpass.set_bind_group(0, fbg, &[]);
483                    cpass.dispatch_workgroups(fused_wg, 1, 1);
484                } else if let (Some(g), Some(u), Some(s)) =
485                    (lb.gate.as_ref(), lb.up.as_ref(), lb.silu.as_ref())
486                {
487                    for (pipe, bg, wg_x) in [
488                        (gemv_large, g, gemv_large_wg(n_ffn_u)),
489                        (gemv_large, u, gemv_large_wg(n_ffn_u)),
490                        (silu, s, elem_wg(n_ffn_u)),
491                    ] {
492                        cpass.set_pipeline(pipe);
493                        cpass.set_bind_group(0, bg, &[]);
494                        cpass.dispatch_workgroups(wg_x, 1, 1);
495                    }
496                }
497                // Down + residual fused. Multi-row opt-in only (A/B lost on A2000 3B).
498                cpass.set_pipeline(gemv_resid);
499                cpass.set_bind_group(0, &lb.down_resid, &[]);
500                cpass.dispatch_workgroups(gemv_large_wg(n_embd_u), 1, 1);
501            }
502            // Output RMSNorm → `plan.normed`.
503            cpass.set_pipeline(rms);
504            cpass.set_bind_group(0, &plan.rms_out, &[]);
505            cpass.dispatch_workgroups(1, 1, 1);
506
507            // Logits + topk (E3: one full-vocab chunk when cap ≥ vocab).
508            // Device maxComputeWorkgroupsPerDimension is typically 65535 — for
509            // vocab > 60k always use multi-row GEMV (8 rows/WG) even if residual
510            // multirow is off, so a single 128k dispatch stays legal.
511            if !sample_path {
512                let topk = topk?;
513                let logits_mr = plan.use_coop && plan.out_chunks.iter().any(|c| c.rows > 60_000);
514                let logits_pipe = if logits_mr {
515                    &self.coop_gemv_mr_pipeline
516                } else {
517                    gemv_large
518                };
519                let logits_wg = |rows: u32| {
520                    if logits_mr {
521                        crate::llm_bench::coop_gemv_workgroups(rows)
522                    } else {
523                        gemv_large_wg(rows)
524                    }
525                };
526                for chunk in &plan.out_chunks {
527                    cpass.set_pipeline(logits_pipe);
528                    cpass.set_bind_group(0, &chunk.gemm, &[]);
529                    cpass.dispatch_workgroups(logits_wg(chunk.rows), 1, 1);
530                    cpass.set_pipeline(topk);
531                    cpass.set_bind_group(0, &chunk.topk, &[]);
532                    cpass.dispatch_workgroups(chunk.cand_count as u32, 1, 1);
533                }
534            }
535            drop(cpass);
536            crate::llm_gpu_profiler::resolve(&mut encoder);
537
538            if sample_path {
539                let hb = (n_embd * 4) as wgpu::BufferAddress;
540                encoder.copy_buffer_to_buffer(&plan.normed, 0, &plan.hidden_staging, 0, hb);
541            } else {
542                let cand_val = self.topk_cand_val_buf.as_ref()?;
543                let cand_idx = self.topk_cand_idx_buf.as_ref()?;
544                // One copy of the full candidate pack (cand_base laid them out contiguously).
545                let cand_bytes = (plan.total_cands * 4) as wgpu::BufferAddress;
546                encoder.copy_buffer_to_buffer(cand_val, 0, &plan.staging, 0, cand_bytes);
547                encoder.copy_buffer_to_buffer(cand_idx, 0, &plan.staging, cand_bytes, cand_bytes);
548            }
549        }
550
551        // 3) ONE submit, ONE fence, tiny readback.
552        queue.submit(Some(encoder.finish()));
553        crate::llm_gpu_profiler::accumulate(crate::llm_gpu_profiler::Phase::FusedBlock);
554
555        if let Some(out) = out_hidden {
556            if out.len() < n_embd {
557                return None;
558            }
559            let map_bytes = (n_embd * 4) as wgpu::BufferAddress;
560            let slice = plan.hidden_staging.slice(..map_bytes);
561            let (tx, rx) = futures_channel::oneshot::channel();
562            slice.map_async(wgpu::MapMode::Read, move |r| {
563                let _ = tx.send(r);
564            });
565            self.poll_wait();
566            let mapped_ok = if let Ok(handle) = tokio::runtime::Handle::try_current() {
567                handle.block_on(rx).ok().map(|m| m.is_ok()).unwrap_or(false)
568            } else {
569                false
570            };
571            if !mapped_ok {
572                let _ = plan.hidden_staging.unmap();
573                return None;
574            }
575            {
576                let data = slice
577                    .get_mapped_range()
578                    .expect("wgpu buffer map_range failed");
579                let floats: &[f32] = bytemuck::cast_slice(&data[..n_embd * 4]);
580                out[..n_embd].copy_from_slice(floats);
581            }
582            plan.hidden_staging.unmap();
583            return Some(ResidentTokenOutcome::HiddenReady);
584        }
585
586        let map_bytes = (plan.total_cands * 8) as wgpu::BufferAddress;
587        let slice = plan.staging.slice(..map_bytes);
588        let (tx, rx) = futures_channel::oneshot::channel();
589        slice.map_async(wgpu::MapMode::Read, move |r| {
590            let _ = tx.send(r);
591        });
592        self.poll_wait();
593        let mapped_ok = if let Ok(handle) = tokio::runtime::Handle::try_current() {
594            handle.block_on(rx).ok().map(|m| m.is_ok()).unwrap_or(false)
595        } else {
596            false
597        };
598        if !mapped_ok {
599            let _ = plan.staging.unmap();
600            return None;
601        }
602
603        let mut best_token_id = 0u32;
604        let mut max_logit = f32::NEG_INFINITY;
605        {
606            let data = slice
607                .get_mapped_range()
608                .expect("wgpu buffer map_range failed");
609            let val_bytes = plan.total_cands * 4;
610            let vals: &[f32] = bytemuck::cast_slice(&data[..val_bytes]);
611            let idxs: &[u32] = bytemuck::cast_slice(&data[val_bytes..val_bytes * 2]);
612            let mut offset = 0usize;
613            let mut row_start = 0u32;
614            for chunk in &plan.out_chunks {
615                for i in 0..chunk.cand_count {
616                    let pos = offset + i;
617                    let v = vals[pos];
618                    let token_id = row_start + idxs[pos];
619                    if v > f32::NEG_INFINITY
620                        && (v > max_logit || (v == max_logit && token_id < best_token_id))
621                    {
622                        max_logit = v;
623                        best_token_id = token_id;
624                    }
625                }
626                offset += chunk.cand_count;
627                row_start += chunk.rows;
628            }
629        }
630        plan.staging.unmap();
631
632        if max_logit == f32::NEG_INFINITY {
633            None
634        } else {
635            Some(ResidentTokenOutcome::Argmax(StreamingArgmaxResult {
636                best_token_id,
637                max_logit,
638            }))
639        }
640    }
641
642    /// Build the per-model plan: force weight residency, create activation
643    /// buffers + static uniform slots + all bind groups. Any missing piece →
644    /// `None` (the caller records Ineligible and the legacy path runs).
645    fn build_resident_plan(
646        &mut self,
647        index: &crate::gguf_sharder::GgufTensorIndex,
648        key: (u64, u64, u32),
649    ) -> Option<Box<ResidentDecodePlan>> {
650        let mmap_arc = self.gguf_mmap.clone()?;
651        let mmap: &[u8] = &mmap_arc;
652        let h = index.hyperparams;
653        let layout = self.kv_layout?;
654        let n_embd = h.n_embd as usize;
655        let n_layer = h.n_layer;
656        let n_head = h.n_head as usize;
657        let n_kv = h.effective_n_kv_head() as usize;
658        let head_dim = h.head_dim() as usize;
659        let q_dim = n_head * head_dim;
660        let kv_dim = n_kv * head_dim;
661        if n_layer == 0
662            || n_embd == 0
663            || n_embd > MAX_HIDDEN_DIM
664            || q_dim == 0
665            || kv_dim == 0
666            || self.output_topk_pipeline.is_none()
667            || self.attention_mask_buf.is_none()
668        {
669            return None;
670        }
671
672        // Logits projection must be resident (per-chunk re-upload cannot share
673        // one encoder), and every weight must be GPU-eligible.
674        let logits_buf = self.mc8_logits_resident_buf.clone()?;
675        let logits_row_bytes = self.mc8_logits_row_bytes as u64;
676        let logits_info = *index.logits_projection_info()?;
677        let (logits_in, vocab) = Self::matmul_dims(&logits_info);
678        if logits_in != n_embd
679            || vocab == 0
680            || !ggml_gpu_gemm_supported(logits_info.ggml_type)
681            || logits_row_bytes == 0
682        {
683            return None;
684        }
685        let out_norm_info = *index.output_norm_info()?;
686
687        let use_coop = crate::llm_bench::coop_gemv_enabled();
688        let device = self.gpu_device().clone();
689        let mk_storage = |label: &str, floats: usize| {
690            device.create_buffer(&wgpu::BufferDescriptor {
691                label: Some(label),
692                size: ((floats * 4 + 255) & !255).max(4) as wgpu::BufferAddress,
693                usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
694                mapped_at_creation: false,
695            })
696        };
697        // Normed hidden is also COPY_SRC for the sampler-compatible readback path.
698        let mk_storage_copy_src = |label: &str, floats: usize| {
699            device.create_buffer(&wgpu::BufferDescriptor {
700                label: Some(label),
701                size: ((floats * 4 + 255) & !255).max(4) as wgpu::BufferAddress,
702                usage: wgpu::BufferUsages::STORAGE
703                    | wgpu::BufferUsages::COPY_DST
704                    | wgpu::BufferUsages::COPY_SRC,
705                mapped_at_creation: false,
706            })
707        };
708        let n_ffn = {
709            let t0 = index.get_layer_tensors(0);
710            let gate = t0.ffn_gate.as_ref()?;
711            Self::matmul_dims(gate).1
712        };
713        if n_ffn == 0 || n_ffn > MAX_STACK_GEMM_DIM {
714            return None;
715        }
716
717        let hidden_a = mk_storage("ResidentHiddenA", n_embd);
718        let hidden_b = mk_storage("ResidentHiddenB", n_embd);
719        let normed = mk_storage_copy_src("ResidentNormed", n_embd);
720        let attn_out = mk_storage("ResidentAttnOut", q_dim.max(n_embd));
721        // Residual add is fused into coop_gemv_residual (no separate delta buffer).
722        // Separate K/V proj slots so dual GEMV can write both in one dispatch.
723        let k_proj = mk_storage("ResidentKProj", kv_dim);
724        let v_proj = mk_storage("ResidentVProj", kv_dim);
725        // Q preprojection target (coop GEMV); attention reads with proj_row_stride = q_dim.
726        let q_proj = mk_storage("ResidentQProj", q_dim);
727        let gate_buf = mk_storage("ResidentGate", n_ffn);
728        let up_buf = mk_storage("ResidentUp", n_ffn);
729        let silu_buf = mk_storage("ResidentSilu", n_ffn);
730        let logits_chunk = mk_storage("ResidentLogitsChunk", RESIDENT_LOGITS_CHUNK);
731
732        // All layers' norm weights resident: slot 2L = attn_norm, 2L+1 = ffn_norm,
733        // slot 2·n_layer = output_norm. 256-aligned stride.
734        let norm_stride = ((n_embd * 4 + 255) & !255) as wgpu::BufferAddress;
735        let norm_res = device.create_buffer(&wgpu::BufferDescriptor {
736            label: Some("ResidentNormWeights"),
737            size: norm_stride * (2 * n_layer as u64 + 1),
738            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
739            mapped_at_creation: false,
740        });
741        let queue = self.gpu_queue().clone();
742        let upload_norm = |slot: u64, info: &GgufTensorInfo| -> bool {
743            let mut w = [0f32; MAX_HIDDEN_DIM];
744            if dequant_norm_row_into(mmap, index.tensor_data_start, info, &mut w) < n_embd {
745                return false;
746            }
747            queue.write_buffer(
748                &norm_res,
749                slot * norm_stride,
750                bytemuck::cast_slice(&w[..n_embd]),
751            );
752            true
753        };
754
755        // Static uniform arena: per-layer GEMM slots + output-chunk GEMM slots
756        // + shared elem slots + per-chunk topk slots.
757        let full_chunks = vocab.div_ceil(RESIDENT_LOGITS_CHUNK);
758        let gemm_slots = n_layer as u64 * GEMM_SLOTS_PER_LAYER + full_chunks as u64;
759        let static_arena = device.create_buffer(&wgpu::BufferDescriptor {
760            label: Some("ResidentStaticParams"),
761            size: (gemm_slots + ELEM_SLOTS + full_chunks as u64) * SLOT,
762            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
763            mapped_at_creation: false,
764        });
765        let elem_base = gemm_slots * SLOT;
766        let topk_base = (gemm_slots + ELEM_SLOTS) * SLOT;
767
768        let attn_dyn_arena = device.create_buffer(&wgpu::BufferDescriptor {
769            label: Some("ResidentAttnDynParams"),
770            size: n_layer as u64 * ATTN_SLOTS_PER_LAYER * SLOT,
771            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
772            mapped_at_creation: false,
773        });
774
775        // Candidate staging (own buffer — never contends with the legacy path's).
776        let block_size = crate::topk::TOPK_BLOCK_SIZE;
777        let total_cands = vocab.div_ceil(block_size);
778        let staging = device.create_buffer(&wgpu::BufferDescriptor {
779            label: Some("ResidentTopkStaging"),
780            size: ((total_cands * 8).max(8)) as wgpu::BufferAddress,
781            usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
782            mapped_at_creation: false,
783        });
784        let hidden_staging = device.create_buffer(&wgpu::BufferDescriptor {
785            label: Some("ResidentHiddenStaging"),
786            size: ((n_embd * 4).max(16)) as wgpu::BufferAddress,
787            usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
788            mapped_at_creation: false,
789        });
790
791        // Shared elem params (written once).
792        let elem_p = |n: usize, op: u32| ElemGpuParams {
793            n: n as u32,
794            batch: 1,
795            op,
796            eps: RMS_NORM_EPS,
797            a_row_stride: 0,
798            b_row_stride: 0,
799            out_row_stride: 0,
800            a_slot: 0,
801            b_slot: 0,
802            out_slot: 0,
803            _pad: 0,
804        };
805        queue.write_buffer(
806            &static_arena,
807            elem_base + ELEM_SLOT_RMS,
808            bytemuck::bytes_of(&elem_p(n_embd, ELEM_OP_RMS_NORM)),
809        );
810        queue.write_buffer(
811            &static_arena,
812            elem_base + ELEM_SLOT_ADD,
813            bytemuck::bytes_of(&elem_p(n_embd, ELEM_OP_ADD_RESIDUAL)),
814        );
815        queue.write_buffer(
816            &static_arena,
817            elem_base + ELEM_SLOT_SILU,
818            bytemuck::bytes_of(&elem_p(n_ffn, ELEM_OP_SILU_MUL)),
819        );
820
821        // Bind-group layouts + helpers.
822        let gemm_layout = self.native_gemm_bind_layout(use_coop).clone();
823        let attn_layout = self.attention_bind_layout.clone();
824        let rms_pipe = self.elem_gpu_pipeline(ELEM_OP_RMS_NORM)?.clone();
825        let rms_layout = rms_pipe.get_bind_group_layout(0);
826        let silu_layout = self.elem_silu_mul_bind_layout.clone();
827        let topk_layout = self.output_topk_bind_layout.clone()?;
828        let mask_buf = self.attention_mask_buf.as_ref()?.clone();
829        let kv_buf = self.kv_cache_gpu.as_ref()?.clone();
830        let cand_val = self.topk_cand_val_buf.as_ref()?.clone();
831        let cand_idx = self.topk_cand_idx_buf.as_ref()?.clone();
832
833        let gp_sz = std::num::NonZeroU64::new(std::mem::size_of::<GemmGpuParams>() as u64);
834        let ap_sz = std::num::NonZeroU64::new(std::mem::size_of::<AttentionGpuParams>() as u64);
835        let ep_sz = std::num::NonZeroU64::new(std::mem::size_of::<ElemGpuParams>() as u64);
836        let tp_sz = std::num::NonZeroU64::new(16);
837        fn ubind(
838            buf: &wgpu::Buffer,
839            off: wgpu::BufferAddress,
840            sz: Option<std::num::NonZeroU64>,
841        ) -> wgpu::BindingResource<'_> {
842            wgpu::BindingResource::Buffer(wgpu::BufferBinding {
843                buffer: buf,
844                offset: off,
845                size: sz,
846            })
847        }
848        let norm_bind = |slot: u64| {
849            wgpu::BindingResource::Buffer(wgpu::BufferBinding {
850                buffer: &norm_res,
851                offset: slot * norm_stride,
852                size: std::num::NonZeroU64::new((n_embd * 4) as u64),
853            })
854        };
855        let mk_elem_bg = |label: &str,
856                          layout: &wgpu::BindGroupLayout,
857                          a: wgpu::BindingResource,
858                          b: wgpu::BindingResource,
859                          out: &wgpu::Buffer,
860                          p_off: wgpu::BufferAddress| {
861            device.create_bind_group(&wgpu::BindGroupDescriptor {
862                label: Some(label),
863                layout,
864                entries: &[
865                    wgpu::BindGroupEntry {
866                        binding: 0,
867                        resource: a,
868                    },
869                    wgpu::BindGroupEntry {
870                        binding: 1,
871                        resource: b,
872                    },
873                    wgpu::BindGroupEntry {
874                        binding: 2,
875                        resource: out.as_entire_binding(),
876                    },
877                    wgpu::BindGroupEntry {
878                        binding: 3,
879                        resource: ubind(&static_arena, elem_base + p_off, ep_sz),
880                    },
881                ],
882            })
883        };
884        let mk_gemm_bg = |label: &str,
885                          input: &wgpu::Buffer,
886                          weight: wgpu::BindingResource,
887                          p_slot: u64,
888                          out: &wgpu::Buffer| {
889            // Binding 4 = dummy residual (shared CoopGemvBGL; input is a safe stand-in).
890            device.create_bind_group(&wgpu::BindGroupDescriptor {
891                label: Some(label),
892                layout: &gemm_layout,
893                entries: &[
894                    wgpu::BindGroupEntry {
895                        binding: 0,
896                        resource: input.as_entire_binding(),
897                    },
898                    wgpu::BindGroupEntry {
899                        binding: 1,
900                        resource: weight,
901                    },
902                    wgpu::BindGroupEntry {
903                        binding: 2,
904                        resource: ubind(&static_arena, p_slot * SLOT, gp_sz),
905                    },
906                    wgpu::BindGroupEntry {
907                        binding: 3,
908                        resource: out.as_entire_binding(),
909                    },
910                    wgpu::BindGroupEntry {
911                        binding: 4,
912                        resource: input.as_entire_binding(),
913                    },
914                ],
915            })
916        };
917        let resid_layout = &self.coop_gemv_residual_bind_layout;
918        let mk_resid_bg = |label: &str,
919                           input: &wgpu::Buffer,
920                           weight: wgpu::BindingResource,
921                           p_slot: u64,
922                           residual: &wgpu::Buffer,
923                           out: &wgpu::Buffer| {
924            device.create_bind_group(&wgpu::BindGroupDescriptor {
925                label: Some(label),
926                layout: resid_layout,
927                entries: &[
928                    wgpu::BindGroupEntry {
929                        binding: 0,
930                        resource: input.as_entire_binding(),
931                    },
932                    wgpu::BindGroupEntry {
933                        binding: 1,
934                        resource: weight,
935                    },
936                    wgpu::BindGroupEntry {
937                        binding: 2,
938                        resource: ubind(&static_arena, p_slot * SLOT, gp_sz),
939                    },
940                    wgpu::BindGroupEntry {
941                        binding: 3,
942                        resource: out.as_entire_binding(),
943                    },
944                    wgpu::BindGroupEntry {
945                        binding: 4,
946                        resource: residual.as_entire_binding(),
947                    },
948                ],
949            })
950        };
951        let layer_f32s = layout.layer_stride as u64;
952        let mk_attn_bg = |label: &str,
953                          input: &wgpu::Buffer,
954                          weight: &wgpu::Buffer,
955                          dyn_slot: u64,
956                          layer: u32,
957                          out: &wgpu::Buffer| {
958            let kv_binding = wgpu::BufferBinding {
959                buffer: &kv_buf,
960                offset: layer as u64 * layer_f32s * 4,
961                size: std::num::NonZeroU64::new((layer_f32s * 4).max(4)),
962            };
963            device.create_bind_group(&wgpu::BindGroupDescriptor {
964                label: Some(label),
965                layout: &attn_layout,
966                entries: &[
967                    wgpu::BindGroupEntry {
968                        binding: 0,
969                        resource: input.as_entire_binding(),
970                    },
971                    wgpu::BindGroupEntry {
972                        binding: 1,
973                        resource: weight.as_entire_binding(),
974                    },
975                    wgpu::BindGroupEntry {
976                        binding: 2,
977                        resource: ubind(&attn_dyn_arena, dyn_slot * SLOT, ap_sz),
978                    },
979                    wgpu::BindGroupEntry {
980                        binding: 3,
981                        resource: wgpu::BindingResource::Buffer(kv_binding),
982                    },
983                    wgpu::BindGroupEntry {
984                        binding: 4,
985                        resource: out.as_entire_binding(),
986                    },
987                    wgpu::BindGroupEntry {
988                        binding: 5,
989                        resource: mask_buf.as_entire_binding(),
990                    },
991                ],
992            })
993        };
994
995        let gemm_params =
996            |ggml_type: u32, n_in: usize, n_out: usize, row_elems: u32, raw_len: usize| {
997                GemmGpuParams {
998                    n_in: n_in as u32,
999                    n_out: n_out as u32,
1000                    weight_ggml_type: ggml_type,
1001                    weight_row_elems: row_elems,
1002                    weight_byte_len: raw_len as u32,
1003                    n_batch: 1,
1004                    in_row_stride: 0,
1005                    out_row_stride: 0,
1006                }
1007            };
1008
1009        let mut layers = Vec::with_capacity(n_layer as usize);
1010        let mut layer_protos = Vec::with_capacity(n_layer as usize);
1011        let mut layer_gate_ggml_type: u32 = 0;
1012        for l in 0..n_layer {
1013            let t = index.get_layer_tensors(l);
1014            let (q_info, k_info, v_info) = (t.attn_q?, t.attn_k?, t.attn_v?);
1015            let o_info = t.attn_output?;
1016            let (gate_info, up_info, down_info) = (t.ffn_gate?, t.ffn_up?, t.ffn_down?);
1017            if l == 0 {
1018                layer_gate_ggml_type = gate_info.ggml_type;
1019            }
1020            let attn_norm = t.attn_norm?;
1021            let ffn_norm = t.ffn_norm?;
1022            for i in [&q_info, &k_info, &v_info] {
1023                if !ggml_gpu_attention_shader_supported(i.ggml_type)
1024                    || !ggml_gpu_gemm_supported(i.ggml_type)
1025                {
1026                    return None;
1027                }
1028            }
1029            for i in [&o_info, &gate_info, &up_info, &down_info] {
1030                if !ggml_gpu_gemm_supported(i.ggml_type) {
1031                    return None;
1032                }
1033            }
1034            // Shape contract (mirrors the legacy per-layer checks).
1035            let (q_in, q_out) = Self::matmul_dims(&q_info);
1036            let (k_in, k_out) = Self::matmul_dims(&k_info);
1037            let (v_in, v_out) = Self::matmul_dims(&v_info);
1038            let (o_in, o_out) = Self::matmul_dims(&o_info);
1039            let (g_in, g_out) = Self::matmul_dims(&gate_info);
1040            let (u_in, u_out) = Self::matmul_dims(&up_info);
1041            let (d_in, d_out) = Self::matmul_dims(&down_info);
1042            if q_in != n_embd
1043                || q_out != q_dim
1044                || k_in != n_embd
1045                || v_in != n_embd
1046                || k_out != kv_dim
1047                || v_out != kv_dim
1048                || o_in != q_dim
1049                || o_out != n_embd
1050                || g_in != n_embd
1051                || u_in != n_embd
1052                || g_out != n_ffn
1053                || u_out != n_ffn
1054                || d_in != n_ffn
1055                || d_out != n_embd
1056            {
1057                return None;
1058            }
1059            let fetch = |i: &GgufTensorInfo| {
1060                crate::ggml_quants::fetch_tensor_bytes(mmap, index.tensor_data_start, i).ok()
1061            };
1062            let (q_raw, k_raw, v_raw) = (fetch(&q_info)?, fetch(&k_info)?, fetch(&v_info)?);
1063            let (o_raw, g_raw, u_raw, d_raw) = (
1064                fetch(&o_info)?,
1065                fetch(&gate_info)?,
1066                fetch(&up_info)?,
1067                fetch(&down_info)?,
1068            );
1069            // CUDA multi-weight preload only when CUDA_DECODE is on. Resident mega-pass
1070            // is the default winner (~6.7 tok/s); duplicating ~1.8 GiB SoA into the CUDA
1071            // slab while wgpu also holds weights steals VRAM and does not help resident.
1072            #[cfg(all(not(target_arch = "wasm32"), feature = "cuda"))]
1073            if crate::prefer_tensor_core_gemm()
1074                && matches!(
1075                    std::env::var("QUALIA_LLM_CUDA_DECODE").ok().as_deref(),
1076                    Some("1") | Some("true")
1077                )
1078            {
1079                use crate::ggml_quants::GGML_TYPE_Q4_K_SOA;
1080                if l == 0 {
1081                    if let Some(layout) = self.kv_layout.as_ref() {
1082                        if !layout.int8 && layout.dict_k == 0 {
1083                            let _ = crate::ensure_device_kv_cache(
1084                                layout.max_context,
1085                                layout.n_layer,
1086                                layout.n_kv_head,
1087                                layout.head_dim,
1088                                layout.slot_kv_elems,
1089                                layout.layer_stride,
1090                                layout.total_f32_elems,
1091                            );
1092                        }
1093                    }
1094                }
1095                let mut pack: Vec<(&[u8], usize, usize)> = Vec::with_capacity(7);
1096                if q_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1097                    pack.push((q_raw, q_in, q_out));
1098                }
1099                if k_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1100                    pack.push((k_raw, n_embd, kv_dim));
1101                }
1102                if v_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1103                    pack.push((v_raw, n_embd, kv_dim));
1104                }
1105                if o_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1106                    pack.push((o_raw, o_in, o_out));
1107                }
1108                if gate_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1109                    pack.push((g_raw, g_in, g_out));
1110                }
1111                if up_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1112                    pack.push((u_raw, u_in, u_out));
1113                }
1114                if down_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1115                    pack.push((d_raw, d_in, d_out));
1116                }
1117                if !pack.is_empty() {
1118                    let _ = crate::preload_q4k_soa_weights(&pack);
1119                }
1120                // Host dense TC cache prewarm (implements prewarm_cuda_weight).
1121                // Opt-in: QUALIA_LLM_CUDA_TC_PREWARM=1 — densify is cold and VRAM-adjacent;
1122                // SoA device preload above is the default CUDA_DECODE win path.
1123                let tc_prewarm = matches!(
1124                    std::env::var("QUALIA_LLM_CUDA_TC_PREWARM").ok().as_deref(),
1125                    Some("1") | Some("true")
1126                );
1127                if tc_prewarm {
1128                    let mut warmed = 0u32;
1129                    let mut try_warm = |info: &crate::gguf_sharder::GgufTensorInfo,
1130                                        raw: &[u8],
1131                                        n_in: usize,
1132                                        n_out: usize| {
1133                        if QTensorEngine::prewarm_cuda_weight(info, raw, n_in, n_out) {
1134                            warmed += 1;
1135                        }
1136                    };
1137                    if q_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1138                        try_warm(&q_info, q_raw, q_in, q_out);
1139                    }
1140                    if k_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1141                        try_warm(&k_info, k_raw, n_embd, kv_dim);
1142                    }
1143                    if v_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1144                        try_warm(&v_info, v_raw, n_embd, kv_dim);
1145                    }
1146                    if o_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1147                        try_warm(&o_info, o_raw, o_in, o_out);
1148                    }
1149                    if gate_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1150                        try_warm(&gate_info, g_raw, g_in, g_out);
1151                    }
1152                    if up_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1153                        try_warm(&up_info, u_raw, u_in, u_out);
1154                    }
1155                    if down_info.ggml_type == GGML_TYPE_Q4_K_SOA {
1156                        try_warm(&down_info, d_raw, d_in, d_out);
1157                    }
1158                    if l == 0 && warmed > 0 {
1159                        log::info!(
1160                            "LLM_LOAD|cuda_tc_prewarm|layer0|dense_entries={}|cache_len={}",
1161                            warmed,
1162                            crate::weight_cache_len()
1163                        );
1164                    }
1165                }
1166            }
1167            let res = |raw: &[u8]| self.resident_weight_buffer(raw.as_ptr() as u64, raw);
1168            let (q_w, k_w, v_w) = (res(q_raw)?, res(k_raw)?, res(v_raw)?);
1169            let o_w = res(o_raw)?;
1170            // FFN quant→f16 promotion: bind f16 for gate/up/down when eligible (fast coop path).
1171            let ffn_bind =
1172                |info: &GgufTensorInfo, raw: &[u8]| -> Option<(wgpu::Buffer, u32, u32, u32)> {
1173                    if let Some(p) = self.promote_matrix_to_f16_resident(info, raw) {
1174                        return Some(p);
1175                    }
1176                    let b = res(raw)?;
1177                    Some((b, info.ggml_type, raw.len() as u32, info.dims[0] as u32))
1178                };
1179            let (g_w, g_ty, g_blen, g_row) = ffn_bind(&gate_info, g_raw)?;
1180            let (u_w, u_ty, u_blen, u_row) = ffn_bind(&up_info, u_raw)?;
1181            let (d_w, d_ty, d_blen, d_row) = ffn_bind(&down_info, d_raw)?;
1182            if l == 0
1183                && (g_ty == crate::ggml_quants::GGML_TYPE_F16
1184                    || u_ty == crate::ggml_quants::GGML_TYPE_F16
1185                    || d_ty == crate::ggml_quants::GGML_TYPE_F16)
1186            {
1187                log::info!(
1188                    "LLM_LOAD|ffn-f16|promoted gate/up/down (types g={} u={} d={})",
1189                    g_ty,
1190                    u_ty,
1191                    d_ty
1192                );
1193            }
1194
1195            if !upload_norm(2 * l as u64, &attn_norm) || !upload_norm(2 * l as u64 + 1, &ffn_norm) {
1196                return None;
1197            }
1198
1199            // Static GEMM param slots for this layer: K, V, Q, O, gate, up, down.
1200            let gbase = l as u64 * GEMM_SLOTS_PER_LAYER;
1201            for (i, (ggml_type, n_in, n_out, row_elems, raw_len)) in [
1202                (
1203                    k_info.ggml_type,
1204                    n_embd,
1205                    kv_dim,
1206                    k_info.dims[0] as u32,
1207                    k_raw.len(),
1208                ),
1209                (
1210                    v_info.ggml_type,
1211                    n_embd,
1212                    kv_dim,
1213                    v_info.dims[0] as u32,
1214                    v_raw.len(),
1215                ),
1216                (
1217                    q_info.ggml_type,
1218                    n_embd,
1219                    q_dim,
1220                    q_info.dims[0] as u32,
1221                    q_raw.len(),
1222                ),
1223                (
1224                    o_info.ggml_type,
1225                    q_dim,
1226                    n_embd,
1227                    o_info.dims[0] as u32,
1228                    o_raw.len(),
1229                ),
1230                (g_ty, n_embd, n_ffn, g_row, g_blen as usize),
1231                (u_ty, n_embd, n_ffn, u_row, u_blen as usize),
1232                (d_ty, n_ffn, n_embd, d_row, d_blen as usize),
1233            ]
1234            .into_iter()
1235            .enumerate()
1236            {
1237                queue.write_buffer(
1238                    &static_arena,
1239                    (gbase + i as u64) * SLOT,
1240                    bytemuck::bytes_of(&gemm_params(ggml_type, n_in, n_out, row_elems, raw_len)),
1241                );
1242            }
1243
1244            // Prototype attention params (position/mask patched per token).
1245            let mut k_p = Self::attention_gpu_params(
1246                &h,
1247                &layout,
1248                l,
1249                0,
1250                &k_info,
1251                k_raw.len(),
1252                1,
1253                1,
1254                0,
1255                0,
1256                0,
1257                0,
1258            );
1259            k_p.proj_row_stride = kv_dim as u32;
1260            let mut v_p = Self::attention_gpu_params(
1261                &h,
1262                &layout,
1263                l,
1264                0,
1265                &v_info,
1266                v_raw.len(),
1267                2,
1268                1,
1269                0,
1270                0,
1271                0,
1272                0,
1273            );
1274            v_p.proj_row_stride = kv_dim as u32;
1275            // Q: coop GEMV preprojects into `q_proj`; SDPA pass only reads + RoPE.
1276            let mut q_p = Self::attention_gpu_params(
1277                &h,
1278                &layout,
1279                l,
1280                0,
1281                &q_info,
1282                q_raw.len(),
1283                0,
1284                1,
1285                0,
1286                0,
1287                0,
1288                0,
1289            );
1290            q_p.proj_row_stride = q_dim as u32;
1291            layer_protos.push(LayerProtos {
1292                k_write: k_p,
1293                v_write: v_p,
1294                q: q_p,
1295            });
1296
1297            let dyn_base = l as u64 * ATTN_SLOTS_PER_LAYER;
1298            // Triple Q+K+V: opt-in only. A/B on A2000 3B: dual+Q ~8.94 vs triple ~8.57
1299            // (triple fires q_dim WGs with 3× dequant; dual is lighter). QUALIA_LLM_TRIPLE_QKV=1.
1300            let want_triple = matches!(
1301                std::env::var("QUALIA_LLM_TRIPLE_QKV").ok().as_deref(),
1302                Some("1") | Some("true")
1303            );
1304            let triple_qkv = if want_triple
1305                && q_info.ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA
1306                && k_info.ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA
1307                && v_info.ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA
1308                && use_coop
1309            {
1310                // Dedicated params: n_out=q_dim, weight_byte_len packs n_kv (GQA).
1311                let tp = device.create_buffer(&wgpu::BufferDescriptor {
1312                    label: Some("ResTripleQkvParams"),
1313                    size: SLOT,
1314                    usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1315                    mapped_at_creation: false,
1316                });
1317                let mut p = gemm_params(
1318                    q_info.ggml_type,
1319                    n_embd,
1320                    q_dim,
1321                    q_info.dims[0] as u32,
1322                    q_raw.len(),
1323                );
1324                // triple_gemv.wgsl reads n_kv from weight_byte_len.
1325                p.weight_byte_len = kv_dim as u32;
1326                queue.write_buffer(&tp, 0, bytemuck::bytes_of(&p));
1327                Some(device.create_bind_group(&wgpu::BindGroupDescriptor {
1328                    label: Some("ResTripleQkv"),
1329                    layout: &self.triple_gemv_bind_layout,
1330                    entries: &[
1331                        wgpu::BindGroupEntry {
1332                            binding: 0,
1333                            resource: normed.as_entire_binding(),
1334                        },
1335                        wgpu::BindGroupEntry {
1336                            binding: 1,
1337                            resource: q_w.as_entire_binding(),
1338                        },
1339                        wgpu::BindGroupEntry {
1340                            binding: 2,
1341                            resource: tp.as_entire_binding(),
1342                        },
1343                        wgpu::BindGroupEntry {
1344                            binding: 3,
1345                            resource: q_proj.as_entire_binding(),
1346                        },
1347                        wgpu::BindGroupEntry {
1348                            binding: 4,
1349                            resource: k_w.as_entire_binding(),
1350                        },
1351                        wgpu::BindGroupEntry {
1352                            binding: 5,
1353                            resource: k_proj.as_entire_binding(),
1354                        },
1355                        wgpu::BindGroupEntry {
1356                            binding: 6,
1357                            resource: v_w.as_entire_binding(),
1358                        },
1359                        wgpu::BindGroupEntry {
1360                            binding: 7,
1361                            resource: v_proj.as_entire_binding(),
1362                        },
1363                    ],
1364                }))
1365            } else {
1366                None
1367            };
1368            let dual_kv = if triple_qkv.is_none()
1369                && k_info.ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA
1370                && v_info.ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA
1371                && use_coop
1372            {
1373                Some(device.create_bind_group(&wgpu::BindGroupDescriptor {
1374                    label: Some("ResDualKv"),
1375                    layout: &self.dual_gemv_bind_layout,
1376                    entries: &[
1377                        wgpu::BindGroupEntry {
1378                            binding: 0,
1379                            resource: normed.as_entire_binding(),
1380                        },
1381                        wgpu::BindGroupEntry {
1382                            binding: 1,
1383                            resource: k_w.as_entire_binding(),
1384                        },
1385                        wgpu::BindGroupEntry {
1386                            binding: 2,
1387                            resource: ubind(&static_arena, gbase * SLOT, gp_sz),
1388                        },
1389                        wgpu::BindGroupEntry {
1390                            binding: 3,
1391                            resource: k_proj.as_entire_binding(),
1392                        },
1393                        wgpu::BindGroupEntry {
1394                            binding: 4,
1395                            resource: v_w.as_entire_binding(),
1396                        },
1397                        wgpu::BindGroupEntry {
1398                            binding: 5,
1399                            resource: v_proj.as_entire_binding(),
1400                        },
1401                    ],
1402                }))
1403            } else {
1404                None
1405            };
1406            layers.push(LayerBinds {
1407                rms_attn: mk_elem_bg(
1408                    "ResRmsAttn",
1409                    &rms_layout,
1410                    hidden_a.as_entire_binding(),
1411                    norm_bind(2 * l as u64),
1412                    &normed,
1413                    ELEM_SLOT_RMS,
1414                ),
1415                triple_qkv,
1416                dual_kv,
1417                k_gemm: mk_gemm_bg("ResKGemm", &normed, k_w.as_entire_binding(), gbase, &k_proj),
1418                k_write: mk_attn_bg("ResKWrite", &k_proj, &k_w, dyn_base, l, &attn_out),
1419                v_gemm: mk_gemm_bg(
1420                    "ResVGemm",
1421                    &normed,
1422                    v_w.as_entire_binding(),
1423                    gbase + 1,
1424                    &v_proj,
1425                ),
1426                v_write: mk_attn_bg("ResVWrite", &v_proj, &v_w, dyn_base + 1, l, &attn_out),
1427                q_gemm: mk_gemm_bg(
1428                    "ResQGemm",
1429                    &normed,
1430                    q_w.as_entire_binding(),
1431                    gbase + 2,
1432                    &q_proj,
1433                ),
1434                // hidden binding = precomputed Q; weight unused when proj_row_stride != 0.
1435                q: mk_attn_bg("ResQSdpa", &q_proj, &q_w, dyn_base + 2, l, &attn_out),
1436                // O·attn + residual(hidden_a) → hidden_b (one dispatch).
1437                o_resid: mk_resid_bg(
1438                    "ResOResid",
1439                    &attn_out,
1440                    o_w.as_entire_binding(),
1441                    gbase + 3,
1442                    &hidden_a,
1443                    &hidden_b,
1444                ),
1445                rms_ffn: mk_elem_bg(
1446                    "ResRmsFfn",
1447                    &rms_layout,
1448                    hidden_b.as_entire_binding(),
1449                    norm_bind(2 * l as u64 + 1),
1450                    &normed,
1451                    ELEM_SLOT_RMS,
1452                ),
1453                // T-A1: fuse when flag on, gate/up same quant, and fused_ffn.wgsl supports it.
1454                // Q4_K_SOA / F16-promoted stay on coop GEMV + separate SiLU (faster for those).
1455                fused_ffn: {
1456                    let want = crate::llm_bench::ffn_fusion_enabled()
1457                        && g_ty == u_ty
1458                        && fused_ffn_quant_supported(g_ty);
1459                    if want {
1460                        Some(device.create_bind_group(&wgpu::BindGroupDescriptor {
1461                            label: Some("ResFusedFfn"),
1462                            layout: &self.ffn_fused_bind_layout,
1463                            entries: &[
1464                                wgpu::BindGroupEntry {
1465                                    binding: 0,
1466                                    resource: normed.as_entire_binding(),
1467                                },
1468                                wgpu::BindGroupEntry {
1469                                    binding: 1,
1470                                    resource: g_w.as_entire_binding(),
1471                                },
1472                                wgpu::BindGroupEntry {
1473                                    binding: 2,
1474                                    resource: u_w.as_entire_binding(),
1475                                },
1476                                wgpu::BindGroupEntry {
1477                                    binding: 3,
1478                                    // Gate params describe both streams (same type+dims).
1479                                    resource: ubind(&static_arena, (gbase + 4) * SLOT, gp_sz),
1480                                },
1481                                wgpu::BindGroupEntry {
1482                                    binding: 4,
1483                                    resource: silu_buf.as_entire_binding(),
1484                                },
1485                            ],
1486                        }))
1487                    } else {
1488                        None
1489                    }
1490                },
1491                gate: {
1492                    let want = !(crate::llm_bench::ffn_fusion_enabled()
1493                        && g_ty == u_ty
1494                        && fused_ffn_quant_supported(g_ty));
1495                    if want {
1496                        Some(mk_gemm_bg(
1497                            "ResGate",
1498                            &normed,
1499                            g_w.as_entire_binding(),
1500                            gbase + 4,
1501                            &gate_buf,
1502                        ))
1503                    } else {
1504                        None
1505                    }
1506                },
1507                up: {
1508                    let want = !(crate::llm_bench::ffn_fusion_enabled()
1509                        && g_ty == u_ty
1510                        && fused_ffn_quant_supported(g_ty));
1511                    if want {
1512                        Some(mk_gemm_bg(
1513                            "ResUp",
1514                            &normed,
1515                            u_w.as_entire_binding(),
1516                            gbase + 5,
1517                            &up_buf,
1518                        ))
1519                    } else {
1520                        None
1521                    }
1522                },
1523                silu: {
1524                    let want = !(crate::llm_bench::ffn_fusion_enabled()
1525                        && g_ty == u_ty
1526                        && fused_ffn_quant_supported(g_ty));
1527                    if want {
1528                        Some(mk_elem_bg(
1529                            "ResSilu",
1530                            &silu_layout,
1531                            gate_buf.as_entire_binding(),
1532                            up_buf.as_entire_binding(),
1533                            &silu_buf,
1534                            ELEM_SLOT_SILU,
1535                        ))
1536                    } else {
1537                        None
1538                    }
1539                },
1540                // Down·silu + residual(hidden_b) → hidden_a (one dispatch).
1541                down_resid: mk_resid_bg(
1542                    "ResDownResid",
1543                    &silu_buf,
1544                    d_w.as_entire_binding(),
1545                    gbase + 6,
1546                    &hidden_b,
1547                    &hidden_a,
1548                ),
1549            });
1550        }
1551
1552        // Output norm weights + bind group (reads the final hidden_a).
1553        if !upload_norm(2 * n_layer as u64, &out_norm_info) {
1554            return None;
1555        }
1556        let rms_out = mk_elem_bg(
1557            "ResRmsOut",
1558            &rms_layout,
1559            hidden_a.as_entire_binding(),
1560            norm_bind(2 * n_layer as u64),
1561            &normed,
1562            ELEM_SLOT_RMS,
1563        );
1564
1565        // Output chunks: logits GEMV (resident weight sub-range) + top-1 reduce.
1566        // cand_base packs multi-chunk candidates contiguously for one mega-pass.
1567        let mut out_chunks = Vec::with_capacity(full_chunks);
1568        let mut cand_base_acc = 0u32;
1569        for c in 0..full_chunks {
1570            let row_start = c * RESIDENT_LOGITS_CHUNK;
1571            let rows = RESIDENT_LOGITS_CHUNK.min(vocab - row_start);
1572            // Resident logits buffer is sized to RESIDENT_LOGITS_CHUNK (not stack gemm max).
1573            if rows > RESIDENT_LOGITS_CHUNK {
1574                return None;
1575            }
1576            let cand_count = rows.div_ceil(block_size);
1577            let byte_len = rows as u64 * logits_row_bytes;
1578            let gemm_slot = n_layer as u64 * GEMM_SLOTS_PER_LAYER + c as u64;
1579            queue.write_buffer(
1580                &static_arena,
1581                gemm_slot * SLOT,
1582                bytemuck::bytes_of(&gemm_params(
1583                    logits_info.ggml_type,
1584                    n_embd,
1585                    rows,
1586                    logits_info.dims[0] as u32,
1587                    byte_len as usize,
1588                )),
1589            );
1590            let tparams = crate::topk::topk_params_bytes_with_base(
1591                rows as u32,
1592                1,
1593                block_size as u32,
1594                cand_base_acc,
1595            );
1596            queue.write_buffer(&static_arena, topk_base + c as u64 * SLOT, &tparams);
1597            let weight = wgpu::BindingResource::Buffer(wgpu::BufferBinding {
1598                buffer: &logits_buf,
1599                offset: row_start as u64 * logits_row_bytes,
1600                size: std::num::NonZeroU64::new(byte_len),
1601            });
1602            let gemm = mk_gemm_bg("ResLogits", &normed, weight, gemm_slot, &logits_chunk);
1603            let topk = device.create_bind_group(&wgpu::BindGroupDescriptor {
1604                label: Some("ResTopk"),
1605                layout: &topk_layout,
1606                entries: &[
1607                    wgpu::BindGroupEntry {
1608                        binding: 0,
1609                        resource: logits_chunk.as_entire_binding(),
1610                    },
1611                    wgpu::BindGroupEntry {
1612                        binding: 1,
1613                        resource: ubind(&static_arena, topk_base + c as u64 * SLOT, tp_sz),
1614                    },
1615                    wgpu::BindGroupEntry {
1616                        binding: 2,
1617                        resource: cand_val.as_entire_binding(),
1618                    },
1619                    wgpu::BindGroupEntry {
1620                        binding: 3,
1621                        resource: cand_idx.as_entire_binding(),
1622                    },
1623                ],
1624            });
1625            out_chunks.push(OutChunk {
1626                gemm,
1627                topk,
1628                rows: rows as u32,
1629                cand_count,
1630            });
1631            cand_base_acc += cand_count as u32;
1632        }
1633
1634        let dyn_bytes = (n_layer as u64 * ATTN_SLOTS_PER_LAYER * SLOT) as usize;
1635        let use_fused_ffn = !layers.is_empty() && layers.iter().all(|lb| lb.fused_ffn.is_some());
1636        // Residual-fused O/down + triple QKV when SoA: ~9 dispatches/layer with fused FFN.
1637        let use_triple = layers.iter().any(|lb| lb.triple_qkv.is_some());
1638        let use_dual = layers.iter().any(|lb| lb.dual_kv.is_some());
1639        let passes_per_layer = if use_fused_ffn {
1640            if use_triple {
1641                9
1642            } else if use_dual {
1643                10
1644            } else {
1645                11
1646            }
1647        } else {
1648            13
1649        };
1650        let passes_token = n_layer as usize * passes_per_layer + 1 + out_chunks.len() * 2;
1651        crate::llm_bench::set_ffn_fusion_in_resident(use_fused_ffn);
1652        // Layer weights may be Q4_K_SOA while logits stay Q6_K (3B .soa.p64: 2520 B/row logits).
1653        let is_q4_soa = layer_gate_ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA
1654            || logits_info.ggml_type == crate::ggml_quants::GGML_TYPE_Q4_K_SOA;
1655        // Residual multirow: opt-in only (A/B lost vs 1-row on A2000 3B).
1656        // Logits always use multirow geometry when n_out > 60k (device max WG dim).
1657        let use_multirow = use_coop
1658            && is_q4_soa
1659            && matches!(
1660                std::env::var("QUALIA_LLM_MULTIROW").ok().as_deref(),
1661                Some("1") | Some("true")
1662            );
1663        let use_warp = use_coop
1664            && is_q4_soa
1665            && !use_multirow
1666            && matches!(
1667                std::env::var("QUALIA_LLM_WARP_GEMV").ok().as_deref(),
1668                Some("1") | Some("true")
1669            );
1670        // FFN multi-row: opt-in only (A/B lost on A2000 3B SoA).
1671        let use_ffn_warp = use_coop
1672            && is_q4_soa
1673            && matches!(
1674                std::env::var("QUALIA_LLM_FFN_WARP").ok().as_deref(),
1675                Some("1") | Some("true")
1676            );
1677        let use_ffn_mr = use_coop
1678            && is_q4_soa
1679            && !use_ffn_warp
1680            && matches!(
1681                std::env::var("QUALIA_LLM_FFN_MR").ok().as_deref(),
1682                Some("1") | Some("true")
1683            );
1684        #[cfg(all(not(target_arch = "wasm32"), feature = "cuda"))]
1685        {
1686            let cuda_dense_cache = crate::weight_cache_len();
1687            let cuda_soa_weights = crate::q4k_device_weight_count();
1688            log::info!(
1689                "LLM_DECODE|resident-plan|built: {} layers, {} passes/token, fused_ffn={} triple_qkv={} dual_kv={} ffn_mr={} multirow={} cuda_soa_weights={} cuda_dense_cache={}",
1690                n_layer,
1691                passes_token,
1692                use_fused_ffn,
1693                use_triple,
1694                use_dual,
1695                use_ffn_mr,
1696                use_multirow,
1697                cuda_soa_weights,
1698                cuda_dense_cache,
1699            );
1700        }
1701        #[cfg(not(all(not(target_arch = "wasm32"), feature = "cuda")))]
1702        log::info!(
1703            "LLM_DECODE|resident-plan|built: {} layers, {} passes/token, fused_ffn={} ffn_mr={} ffn_warp={}",
1704            n_layer,
1705            passes_token,
1706            use_fused_ffn,
1707            use_ffn_mr,
1708            use_ffn_warp,
1709        );
1710        Some(Box::new(ResidentDecodePlan {
1711            key,
1712            n_embd,
1713            n_ffn,
1714            kv_dim,
1715            q_dim,
1716            n_head: n_head as u32,
1717            n_kv_head: n_kv as u32,
1718            layout,
1719            layer_protos,
1720            layers,
1721            rms_out,
1722            out_chunks,
1723            total_cands,
1724            attn_dyn_arena,
1725            dyn_scratch: vec![0u8; dyn_bytes],
1726            hidden_a,
1727            normed,
1728            staging,
1729            hidden_staging,
1730            use_coop,
1731            use_multirow,
1732            use_warp,
1733            use_ffn_mr,
1734            use_ffn_warp,
1735            use_fused_ffn,
1736            dispatches_per_token: passes_token as u32,
1737            readback_bytes_per_token: (total_cands * std::mem::size_of::<f32>()
1738                + total_cands * std::mem::size_of::<u32>())
1739                as u32,
1740        }))
1741    }
1742}