Skip to main content

qualia_core_db/inference/cuda_lane/
device.rs

1//! Multi-weight device slab management — permanent Q4 SoA weight residency,
2//! sticky activation buffers, and permanent device KV cache arena.
3
4use std::collections::HashMap;
5use std::sync::{Mutex, OnceLock};
6
7use crate::wgsl_forge::execute::memory::BufferView;
8use crate::wgsl_forge::execute::{CapturedCudaGraph, CudaComputeContext};
9
10use super::weight_cache::weight_fingerprint;
11
12/// Sticky activation buffers for the CUDA mega-pass, allocated once in the permanent
13/// slab region and overwritten in-place each decode step. Eliminates per-call
14/// transient allocation overhead (~15 buffers per decode).
15///
16/// Layout (all f32, allocated contiguously after KV in the permanent region):
17/// hidden_a[n_embd] | hidden_b[n_embd] |
18/// yq[q_dim] | yk[kv_dim] | yv[kv_dim] | attn_out[q_dim] |
19/// o_delta[n_embd] | ffn_mid[n_ffn] | ffn_out[n_embd] |
20/// param packs (small u32 arrays) |
21/// logits[max_vocab] | token[1]
22
23/// Multi-weight device residency: Q4 SoA matrices live permanently in one slab;
24/// activations use a **fixed sticky slot** (overwrite in place — no permanent growth).
25/// Permanent **device KV** (P4) lives after weights when reserved — same layout as
26/// host `KvCacheLayout` f32 mode so SDPA/KV write kernels match engine indices.
27///
28/// Transient y/dims are rewound to `permanent_end` each call. Slab is 2.5 GiB so a
29/// full Llama-3.2-3B Q4 weight set (~1.8 GiB) + f32 KV (~0.22 GiB) can stay resident.
30pub(crate) struct MultiWeightDevice {
31    pub ctx: CudaComputeContext,
32    /// Write cursor after permanent weights (+ sticky slot + optional KV). Transient starts here.
33    pub permanent_end: u64,
34    pub weights: HashMap<u64, crate::wgsl_forge::execute::memory::BufferView>,
35    /// Fixed sticky activation buffer (capacity in floats); content overwritten via write_view.
36    pub sticky_x_key: u64,
37    pub sticky_x_n_in: usize,
38    pub sticky_x_cap: usize,
39    pub sticky_x: Option<crate::wgsl_forge::execute::memory::BufferView>,
40    /// Permanent f32 KV arena (device SDPA). None until [`ensure_device_kv_cache`].
41    pub kv: Option<crate::wgsl_forge::execute::memory::BufferView>,
42    /// Prepared `[layer][logical_page] -> physical_page` indirection.
43    pub kv_block_table: Option<crate::wgsl_forge::execute::memory::BufferView>,
44    pub kv_block_size: u32,
45    pub kv_blocks_per_layer: u32,
46    pub kv_total_f32: usize,
47    pub kv_max_context: u32,
48    pub kv_n_layer: u32,
49    pub kv_n_kv_head: u32,
50    pub kv_head_dim: u32,
51    pub kv_slot_kv_elems: u32,
52    pub kv_layer_stride: u32,
53    /// Sticky mega-pass activation arena (allocated once, overwritten in-place).
54    pub mega_pass_arena: Option<MegaPassArena>,
55    /// Captured full-model decode graph for the current prepared-plan shape.
56    pub decode_graph: Option<CapturedCudaGraph>,
57    pub decode_graph_key: u64,
58    /// Exact number of device kernel nodes recorded in `decode_graph`.
59    pub decode_graph_node_count: u64,
60    /// Exact dynamic H2D traffic required before each graph launch.
61    pub decode_graph_h2d_bytes_per_token: u64,
62    /// Fingerprint of static parameter packs currently resident in the arena.
63    pub mega_params_key: u64,
64}
65
66/// CUDA slab for multi-weight SoA + device KV (bytes). 2.5 GiB covers 3B Q4 + KV headroom.
67const CUDA_SOA_SLAB_BYTES: u64 = (5 * 1024 * 1024 * 1024) / 2;
68
69pub(crate) fn multi_weight_device() -> &'static Mutex<Option<MultiWeightDevice>> {
70    static C: OnceLock<Mutex<Option<MultiWeightDevice>>> = OnceLock::new();
71    C.get_or_init(|| Mutex::new(None))
72}
73
74/// How many Q4 SoA matrices are sticky-resident on CUDA.
75pub fn q4k_device_weight_count() -> usize {
76    multi_weight_device()
77        .lock()
78        .ok()
79        .and_then(|g| g.as_ref().map(|d| d.weights.len()))
80        .unwrap_or(0)
81}
82
83pub fn q4k_weight_resident(key: u64) -> bool {
84    multi_weight_device()
85        .lock()
86        .ok()
87        .and_then(|guard| {
88            guard
89                .as_ref()
90                .map(|device| device.weights.contains_key(&key))
91        })
92        .unwrap_or(false)
93}
94
95/// Return the stable key of the instantiated full-decode CUDA graph, if one is live.
96///
97/// This is receipt telemetry only: callers cannot launch or mutate the graph through it.
98pub(crate) fn decode_graph_key() -> Option<u64> {
99    multi_weight_device()
100        .lock()
101        .ok()
102        .and_then(|guard| {
103            guard.as_ref().and_then(|device| {
104                device
105                    .decode_graph
106                    .as_ref()
107                    .map(|_| device.decode_graph_key)
108            })
109        })
110        .filter(|key| *key != 0)
111}
112
113/// Return the exact kernel-node count recorded in the live decode graph.
114///
115/// Keeping this beside the graph avoids reconstructing telemetry from stale schedule
116/// assumptions when an opt-in fusion candidate adds or removes nodes.
117pub(crate) fn decode_graph_node_count() -> Option<u64> {
118    multi_weight_device()
119        .lock()
120        .ok()
121        .and_then(|guard| {
122            guard.as_ref().and_then(|device| {
123                device
124                    .decode_graph
125                    .as_ref()
126                    .map(|_| device.decode_graph_node_count)
127            })
128        })
129        .filter(|count| *count != 0)
130}
131
132/// Return exact dynamic H2D bytes associated with the live captured graph.
133pub(crate) fn decode_graph_h2d_bytes_per_token() -> Option<u64> {
134    multi_weight_device().lock().ok().and_then(|guard| {
135        guard.as_ref().and_then(|device| {
136            device
137                .decode_graph
138                .as_ref()
139                .map(|_| device.decode_graph_h2d_bytes_per_token)
140        })
141    })
142}
143
144/// Upload an immutable prepared-plan blob to the permanent CUDA slab.
145///
146/// The caller supplies the stable content key. This is used for small f32 vectors such as
147/// RMSNorm weights as well as quantized matrices, so the token path never performs H2D writes.
148pub fn preload_resident_blob(key: u64, bytes: &[u8]) -> bool {
149    use crate::wgsl_forge::dispatch::{caps, ensure_cuda_runtime_path};
150
151    if key == 0 || bytes.is_empty() || bytes.len() > 256 * 1024 * 1024 {
152        return false;
153    }
154    ensure_cuda_runtime_path();
155    if !caps().cuda {
156        return false;
157    }
158    let Ok(mut guard) = multi_weight_device().lock() else {
159        return false;
160    };
161    if !ensure_device(&mut guard) {
162        return false;
163    }
164    ensure_weight_resident(guard.as_mut().unwrap(), key, bytes)
165}
166
167/// Bulk-preload Q4_K_SOA weight blobs into the multi-weight CUDA slab.
168/// Call once at plan build so first-token decode does not thrash PCIe.
169/// Each entry is `(raw_bytes, n_in, n_out)`. Returns how many newly resident.
170pub fn preload_q4k_soa_weights(weights: &[(&[u8], usize, usize)]) -> usize {
171    use crate::ggml_quants::{ggml_row_bytes, GGML_TYPE_Q4_K_SOA};
172    use crate::wgsl_forge::dispatch::{caps, ensure_cuda_runtime_path};
173
174    if !crate::inference_modes::prefer_tensor_core_gemm() {
175        return 0;
176    }
177    ensure_cuda_runtime_path();
178    if !caps().cuda {
179        return 0;
180    }
181    let Ok(mut guard) = multi_weight_device().lock() else {
182        return 0;
183    };
184    if !ensure_device(&mut guard) {
185        return 0;
186    }
187    let dev = guard.as_mut().unwrap();
188    let mut added = 0usize;
189    for &(raw, n_in, n_out) in weights {
190        if n_in == 0 || n_out == 0 || n_out > 131_072 {
191            continue;
192        }
193        let Some(row_bytes) = ggml_row_bytes(GGML_TYPE_Q4_K_SOA, n_in) else {
194            continue;
195        };
196        let need = row_bytes.saturating_mul(n_out);
197        if raw.len() < need || need > 256 * 1024 * 1024 {
198            continue;
199        }
200        let key = weight_fingerprint(&raw[..need], n_in, n_out);
201        if dev.weights.contains_key(&key) {
202            continue;
203        }
204        if ensure_weight_resident(dev, key, &raw[..need]) {
205            added += 1;
206        }
207    }
208    if added > 0 {
209        log::info!(
210            "cuda_lane|q4k_soa|preload|added={added}|total={}",
211            dev.weights.len()
212        );
213    }
214    added
215}
216
217/// Ensure the multi-weight CUDA context exists (NVIDIA clocks / driver warm).
218/// Safe to call from portable paths — brings A2000 out of idle so wgpu resident
219/// decode sees production clocks (measured ~4× vs cold portable on 3B).
220pub fn warm_cuda_context() -> bool {
221    use crate::wgsl_forge::dispatch::{caps, ensure_cuda_runtime_path};
222    ensure_cuda_runtime_path();
223    if !caps().cuda {
224        return false;
225    }
226    let Ok(mut guard) = multi_weight_device().lock() else {
227        return false;
228    };
229    let ok = ensure_device(&mut guard);
230    if ok {
231        log::info!("cuda_lane|warm_context|ok");
232    }
233    ok
234}
235
236fn empty_mw_device(ctx: CudaComputeContext) -> MultiWeightDevice {
237    MultiWeightDevice {
238        ctx,
239        permanent_end: 0,
240        weights: HashMap::new(),
241        sticky_x_key: 0,
242        sticky_x_n_in: 0,
243        sticky_x_cap: 0,
244        sticky_x: None,
245        kv: None,
246        kv_block_table: None,
247        kv_block_size: 0,
248        kv_blocks_per_layer: 0,
249        kv_total_f32: 0,
250        kv_max_context: 0,
251        kv_n_layer: 0,
252        kv_n_kv_head: 0,
253        kv_head_dim: 0,
254        kv_slot_kv_elems: 0,
255        kv_layer_stride: 0,
256        mega_pass_arena: None,
257        decode_graph: None,
258        decode_graph_key: 0,
259        decode_graph_node_count: 0,
260        decode_graph_h2d_bytes_per_token: 0,
261        mega_params_key: 0,
262    }
263}
264
265pub(crate) fn ensure_device(guard: &mut Option<MultiWeightDevice>) -> bool {
266    use crate::wgsl_forge::execute::CudaComputeContext;
267    if guard.is_some() {
268        return true;
269    }
270    // Prefer 2.5 GiB (weights + KV); fall back 2 GiB → 1 GiB under VRAM pressure.
271    let sizes: [u64; 3] = [
272        CUDA_SOA_SLAB_BYTES,
273        2 * 1024 * 1024 * 1024,
274        1024 * 1024 * 1024,
275    ];
276    let mut last_err = None;
277    for &bytes in &sizes {
278        match CudaComputeContext::new(bytes as usize) {
279            Ok(c) => {
280                log::info!(
281                    "cuda_lane|q4k_soa|multi_weight_context|{}MiB",
282                    bytes / (1024 * 1024)
283                );
284                *guard = Some(empty_mw_device(c));
285                return true;
286            }
287            Err(e) => {
288                last_err = Some(e);
289            }
290        }
291    }
292    log::warn!("cuda_lane|q4k_soa|ctx_fail|{last_err:?}");
293    false
294}
295
296/// Reserve permanent device KV matching host `KvCacheLayout` f32 indices (P4).
297/// Call **before** heavy weight preload when possible so the slab still has room.
298/// Returns false if layout is invalid or the slab cannot hold the arena.
299pub fn ensure_device_kv_cache(
300    max_context: u32,
301    n_layer: u32,
302    n_kv_head: u32,
303    head_dim: u32,
304    slot_kv_elems: u32,
305    layer_stride: u32,
306    total_f32_elems: usize,
307) -> bool {
308    use crate::wgsl_forge::dispatch::{caps, ensure_cuda_runtime_path};
309
310    if !crate::inference_modes::prefer_tensor_core_gemm() {
311        return false;
312    }
313    ensure_cuda_runtime_path();
314    if !caps().cuda {
315        return false;
316    }
317    if max_context == 0
318        || n_layer == 0
319        || n_kv_head == 0
320        || head_dim == 0
321        || total_f32_elems == 0
322        || total_f32_elems > 128 * 1024 * 1024
323    {
324        return false;
325    }
326    let Ok(mut guard) = multi_weight_device().lock() else {
327        return false;
328    };
329    if !ensure_device(&mut guard) {
330        return false;
331    }
332    let dev = guard.as_mut().unwrap();
333    if let Some(v) = dev.kv {
334        if dev.kv_total_f32 == total_f32_elems
335            && dev.kv_max_context == max_context
336            && dev.kv_n_layer == n_layer
337            && dev.kv_n_kv_head == n_kv_head
338            && dev.kv_head_dim == head_dim
339            && dev.kv_layer_stride == layer_stride
340            && dev.kv_block_table.is_some()
341        {
342            let _ = v;
343            return true;
344        }
345        // Layout change: cannot relocate without nuking permanent region — soft-fail.
346        log::warn!("cuda_lane|kv|layout_mismatch|refuse_realloc");
347        return false;
348    }
349    let bytes = total_f32_elems.saturating_mul(4);
350    let zeros = vec![0u8; bytes];
351    let Some(config) = crate::inference::runtime::kv::paged::PagedKvConfig::new(
352        n_layer,
353        n_kv_head,
354        head_dim,
355        max_context,
356    ) else {
357        return false;
358    };
359    let Ok(table) = crate::inference::runtime::kv::paged::GpuBlockTablePlan::identity(config)
360    else {
361        return false;
362    };
363    let checkpoint = dev.permanent_end;
364    dev.ctx.restore_checkpoint(dev.permanent_end);
365    match dev.ctx.allocate_and_write(&zeros, 0, 0) {
366        Ok(v) => {
367            let block_table =
368                match dev
369                    .ctx
370                    .allocate_and_write(bytemuck::cast_slice(table.entries()), 0, 0)
371                {
372                    Ok(table) => table,
373                    Err(error) => {
374                        dev.ctx.restore_checkpoint(checkpoint);
375                        log::warn!("cuda_lane|kv|block_table_alloc_fail|{error:?}");
376                        return false;
377                    }
378                };
379            dev.permanent_end = dev.ctx.write_checkpoint();
380            dev.kv = Some(v);
381            dev.kv_block_table = Some(block_table);
382            dev.kv_block_size = config.block_size;
383            dev.kv_blocks_per_layer = config.logical_blocks_per_layer();
384            dev.kv_total_f32 = total_f32_elems;
385            dev.kv_max_context = max_context;
386            dev.kv_n_layer = n_layer;
387            dev.kv_n_kv_head = n_kv_head;
388            dev.kv_head_dim = head_dim;
389            dev.kv_slot_kv_elems = slot_kv_elems;
390            dev.kv_layer_stride = layer_stride;
391            log::info!(
392                "cuda_lane|kv|resident_paged|elems={total_f32_elems}|MiB={}|page_tokens={}|pages_per_layer={}",
393                bytes / (1024 * 1024),
394                dev.kv_block_size,
395                dev.kv_blocks_per_layer,
396            );
397            true
398        }
399        Err(e) => {
400            log::warn!("cuda_lane|kv|alloc_fail|bytes={bytes}|{e:?}");
401            false
402        }
403    }
404}
405
406/// True when a permanent device KV arena is resident (P4 path eligible).
407pub fn device_kv_ready() -> bool {
408    multi_weight_device()
409        .lock()
410        .ok()
411        .and_then(|g| g.as_ref().map(|d| d.kv.is_some()))
412        .unwrap_or(false)
413}
414
415pub(crate) fn ensure_weight_resident(dev: &mut MultiWeightDevice, key: u64, raw: &[u8]) -> bool {
416    if dev.weights.contains_key(&key) {
417        return true;
418    }
419    // Weights only: restore to permanent_end (after weights + sticky slot).
420    dev.ctx.restore_checkpoint(dev.permanent_end);
421    match dev.ctx.allocate_and_write(raw, 1, 0) {
422        Ok(v) => {
423            dev.permanent_end = dev.ctx.write_checkpoint();
424            // Sticky slot sits after weights — if sticky was allocated first at
425            // a lower offset, permanent_end still grows correctly for weights.
426            dev.weights.insert(key, v);
427            log::debug!(
428                "cuda_lane|resident_blob|resident+|key={key:#x}|bytes={}|count={}",
429                raw.len(),
430                dev.weights.len()
431            );
432            true
433        }
434        Err(e) => {
435            // Soft-fail: do NOT nuke the whole resident set (that thrashing was
436            // the measured CUDA_DECODE ~1 tok/s killer). Caller falls back to wgpu.
437            log::warn!(
438                "cuda_lane|q4k_soa|slab_full_skip|key={key:#x}|bytes={}|err={e:?}",
439                raw.len()
440            );
441            false
442        }
443    }
444}
445
446/// Sticky host→device activation in a **fixed permanent slot** (overwrite in place).
447/// Content fingerprint skips H2D when unchanged; capacity grows once if needed.
448pub(crate) fn ensure_sticky_x(
449    dev: &mut MultiWeightDevice,
450    x: &[f32],
451) -> Option<crate::wgsl_forge::execute::memory::BufferView> {
452    let key = weight_fingerprint(bytemuck::cast_slice(x), x.len(), 0);
453    if let Some(v) = dev.sticky_x {
454        if dev.sticky_x_key == key && dev.sticky_x_n_in == x.len() {
455            return Some(v);
456        }
457        if dev.sticky_x_cap >= x.len() {
458            // In-place overwrite — permanent_end unchanged.
459            if let Err(e) = dev.ctx.write_view(&v, bytemuck::cast_slice(x)) {
460                log::warn!("cuda_lane|sticky_x|write_view|{e:?}");
461                return None;
462            }
463            dev.sticky_x_key = key;
464            dev.sticky_x_n_in = x.len();
465            return Some(v);
466        }
467    }
468    // First sticky alloc (or grow): permanent after current weights.
469    // Cap at least 8192 floats for typical LLM embd so we rarely re-grow.
470    let cap = x.len().max(8192);
471    let zeros = vec![0u8; cap * 4];
472    dev.ctx.restore_checkpoint(dev.permanent_end);
473    match dev.ctx.allocate_and_write(&zeros, 0, 0) {
474        Ok(v) => {
475            dev.permanent_end = dev.ctx.write_checkpoint();
476            if let Err(e) = dev.ctx.write_view(&v, bytemuck::cast_slice(x)) {
477                log::warn!("cuda_lane|sticky_x|init_write|{e:?}");
478                return None;
479            }
480            dev.sticky_x_key = key;
481            dev.sticky_x_n_in = x.len();
482            dev.sticky_x_cap = cap;
483            dev.sticky_x = Some(v);
484            log::info!("cuda_lane|sticky_x|alloc|cap={cap}|n_in={}", x.len());
485            Some(v)
486        }
487        Err(e) => {
488            log::warn!("cuda_lane|sticky_x|alloc_fail|{e:?}");
489            None
490        }
491    }
492}
493
494/// Sticky activation buffers for the CUDA mega-pass, allocated once in the permanent
495/// slab region and overwritten in-place each decode step. Eliminates per-call
496/// transient allocation overhead (~15 buffers per decode).
497pub(crate) struct MegaPassArena {
498    // Double-buffered hidden state (residual ↔ norm swap each layer).
499    pub hidden_a: BufferView,
500    pub hidden_b: BufferView,
501    // QKV outputs.
502    pub yq: BufferView,
503    pub yk: BufferView,
504    pub yv: BufferView,
505    // Attention output (post-SDPA).
506    pub attn_out: BufferView,
507    // Long-context online-softmax partials:
508    // [query_head][segment][max, sum, head_dim values].
509    pub attn_partials: BufferView,
510    // FFN intermediate (SwiGLU output).
511    pub ffn_mid: BufferView,
512    // Reusable transient-Q8 activation and one f32 scale per 32 values.
513    pub q8_activation: BufferView,
514    pub q8_activation_scales: BufferView,
515    // Norm weight upload buffer.
516    // Small param packs (reused per layer via write_view).
517    pub p_rms: BufferView,
518    pub p_qkv: BufferView,
519    pub p_rope: BufferView,
520    pub p_rope_k: BufferView,
521    pub p_kvw: BufferView,
522    pub p_sdpa: BufferView,
523    pub p_sdpa_scale: BufferView,
524    pub p_gemv_dims: BufferView,
525    pub p_ffn_dims: BufferView,
526    pub p_down_dims: BufferView,
527    // Logits + token buffers for lm_head path.
528    pub logits: BufferView,
529    pub token: BufferView,
530    pub p_argmax: BufferView,
531    pub p_lm_dims: BufferView,
532    /// One immutable device scalar per transformer layer.
533    pub p_layer_ids: Vec<BufferView>,
534    /// Dynamic `[absolute_position, ring_slot, token_id]`, updated once per token.
535    pub p_step: BufferView,
536    // Dims snapshot for validation.
537    pub n_embd: usize,
538    pub n_head: usize,
539    pub head_dim: usize,
540    pub q_dim: usize,
541    pub kv_dim: usize,
542    pub n_ffn: usize,
543    pub max_vocab: usize,
544    pub n_layer: usize,
545}
546
547/// Ensure the mega-pass sticky arena is allocated and dimensions match.
548/// Allocates in the permanent region after KV. Returns false if dims changed
549/// and the arena cannot be reallocated (would require nuking permanent region).
550pub(crate) fn ensure_mega_pass_arena(
551    dev: &mut MultiWeightDevice,
552    n_embd: usize,
553    n_head: usize,
554    head_dim: usize,
555    q_dim: usize,
556    kv_dim: usize,
557    n_ffn: usize,
558    max_vocab: usize,
559    n_layer: usize,
560) -> bool {
561    if let Some(ref arena) = dev.mega_pass_arena {
562        if arena.n_embd == n_embd
563            && arena.n_head == n_head
564            && arena.head_dim == head_dim
565            && arena.q_dim == q_dim
566            && arena.kv_dim == kv_dim
567            && arena.n_ffn == n_ffn
568            && arena.max_vocab == max_vocab
569            && arena.n_layer == n_layer
570        {
571            return true;
572        }
573        // Dim mismatch: cannot relocate without nuking permanent region — soft-fail.
574        log::warn!(
575            "cuda_lane|mega_pass_arena|dim_mismatch|refuse_realloc|old embd={} q={} kv={} ffn={} vocab={} | new embd={} q={} kv={} ffn={} vocab={}",
576            arena.n_embd, arena.q_dim, arena.kv_dim, arena.n_ffn, arena.max_vocab,
577            n_embd, q_dim, kv_dim, n_ffn, max_vocab
578        );
579        return false;
580    }
581
582    // Allocate all buffers contiguously in the permanent region.
583    dev.ctx.restore_checkpoint(dev.permanent_end);
584
585    let zeros_embd = vec![0.0f32; n_embd];
586    let zeros_q = vec![0.0f32; q_dim];
587    let zeros_kv = vec![0.0f32; kv_dim];
588    let zeros_attn_partials = vec![
589        0.0f32;
590        n_head
591            .saturating_mul(super::paged_attention::MAX_ATTENTION_SEGMENTS)
592            .saturating_mul(head_dim.saturating_add(2))
593    ];
594    let zeros_ffn = vec![0.0f32; n_ffn];
595    let zeros_vocab = vec![0.0f32; max_vocab];
596    let max_activation = n_embd.max(q_dim).max(n_ffn);
597    let zeros_q8_activation = vec![0u8; max_activation];
598    let zeros_q8_scales = vec![0.0f32; max_activation.div_ceil(32)];
599
600    let alloc = |ctx: &mut CudaComputeContext, data: &[u8]| -> Option<BufferView> {
601        ctx.allocate_and_write(data, 0, 0).ok()
602    };
603
604    macro_rules! try_alloc {
605        ($e:expr) => {
606            match $e {
607                Some(v) => v,
608                None => return false,
609            }
610        };
611    }
612
613    let hidden_a = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_embd)));
614    let hidden_b = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_embd)));
615    let yq = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_q)));
616    let yk = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_kv)));
617    let yv = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_kv)));
618    let attn_out = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_q)));
619    let attn_partials = try_alloc!(alloc(
620        &mut dev.ctx,
621        bytemuck::cast_slice(&zeros_attn_partials)
622    ));
623    let ffn_mid = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_ffn)));
624    let q8_activation = try_alloc!(alloc(&mut dev.ctx, &zeros_q8_activation));
625    let q8_activation_scales =
626        try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_q8_scales)));
627
628    // Small param packs.
629    let p_rms = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 2])));
630    let p_qkv = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 5])));
631    let p_rope = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 5])));
632    let p_rope_k = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 5])));
633    let p_kvw = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 5])));
634    let p_sdpa = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 9])));
635    let p_sdpa_scale = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 1])));
636    // Shared by plain GEMV (3 words) and fused RMSNorm+SwiGLU (4 words).
637    let p_gemv_dims = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 4])));
638    let p_ffn_dims = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 4])));
639    let p_down_dims = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 3])));
640
641    // Logits + token.
642    let logits = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&zeros_vocab)));
643    let token = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 1])));
644    let p_argmax = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 1])));
645    let p_lm_dims = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 3])));
646    let mut p_layer_ids = Vec::with_capacity(n_layer);
647    for layer in 0..n_layer {
648        p_layer_ids.push(try_alloc!(alloc(
649            &mut dev.ctx,
650            bytemuck::cast_slice(&[layer as u32]),
651        )));
652    }
653    let p_step = try_alloc!(alloc(&mut dev.ctx, bytemuck::cast_slice(&[0u32; 3]),));
654
655    dev.permanent_end = dev.ctx.write_checkpoint();
656
657    let total_floats = n_embd * 2 + q_dim * 2 + kv_dim * 2 + n_ffn + max_vocab;
658    let total_bytes = total_floats * 4
659        + zeros_q8_activation.len()
660        + zeros_q8_scales.len() * 4
661        + 3 * 4
662        + 5 * 4
663        + 5 * 4
664        + 5 * 4
665        + 7 * 4
666        + 9 * 4
667        + 4
668        + 4 * 4
669        + 4
670        + 3 * 4;
671    log::info!(
672        "cuda_lane|mega_pass_arena|alloc|embd={n_embd}|q={q_dim}|kv={kv_dim}|ffn={n_ffn}|vocab={max_vocab}|~{}KiB",
673        total_bytes / 1024
674    );
675
676    dev.mega_pass_arena = Some(MegaPassArena {
677        hidden_a,
678        hidden_b,
679        yq,
680        yk,
681        yv,
682        attn_out,
683        attn_partials,
684        ffn_mid,
685        q8_activation,
686        q8_activation_scales,
687        p_rms,
688        p_qkv,
689        p_rope,
690        p_rope_k,
691        p_kvw,
692        p_sdpa,
693        p_sdpa_scale,
694        p_gemv_dims,
695        p_ffn_dims,
696        p_down_dims,
697        logits,
698        token,
699        p_argmax,
700        p_lm_dims,
701        p_layer_ids,
702        p_step,
703        n_embd,
704        n_head,
705        head_dim,
706        q_dim,
707        kv_dim,
708        n_ffn,
709        max_vocab,
710        n_layer,
711    });
712    true
713}