Skip to main content

memra_engine/
model.rs

1//! Dense transformer model: loads GGUF weights to GPU (Stage-1: dequant→f32), runs the
2//! shared full-attention + SwiGLU forward graph. Arch-agnostic via ModelConfig; this path is
3//! exactly the dense-transformer graph (qwen3) and the full-attention layers of hybrids.
4
5use crate::{
6    Engine, QT_BF16, QT_F32, QT_F8_E4M3, QT_IQ3_S, QT_IQ4_XS, QT_NVFP4, QT_NVFP4_RP, QT_Q2_K,
7    QT_Q3_K, QT_Q4_0, QT_Q4_K, QT_Q5_K, QT_Q6_K, QT_Q8_0,
8};
9use memra_gguf::config::ModelConfig;
10use memra_gguf::source::{DiskExtent, GgufSource, TensorSource};
11use memra_gguf::{dequant, GgmlType, GgufFile};
12use cudarc::driver::CudaSlice;
13use std::collections::HashMap;
14
15/// RESIDENCY CENSUS (lane/fp8-decode-v1, 2026-08-05) — per-qtype tally of the 2D matmul weights
16/// that actually went resident, keyed by `QT_*`. The FP8-ST decode arm's whole claim is about
17/// WHICH container the checkpoint's projections end up in, and the two candidate containers
18/// differ in bytes (e4m3 1.0 B/w vs the Q8_0 re-encode 1.0625 B/w). Before this instrument the
19/// only evidence available was end-to-end tok/s, which cannot distinguish "the arm ran and was
20/// flat" from "the arm never engaged" — the exact ambiguity in this lane's first loadprobe pair.
21/// Slot = qtype index; `.0` = tensor count, `.1` = resident bytes.
22static RESIDENCY_CENSUS: [(std::sync::atomic::AtomicUsize, std::sync::atomic::AtomicU64); 16] = {
23    #[allow(clippy::declare_interior_mutable_const)]
24    const Z: (std::sync::atomic::AtomicUsize, std::sync::atomic::AtomicU64) =
25        (std::sync::atomic::AtomicUsize::new(0), std::sync::atomic::AtomicU64::new(0));
26    [Z; 16]
27};
28
29fn residency_census_note(qtype: i32, bytes: usize) {
30    use std::sync::atomic::Ordering::Relaxed;
31    if let Some(slot) = RESIDENCY_CENSUS.get(qtype as usize) {
32        slot.0.fetch_add(1, Relaxed);
33        slot.1.fetch_add(bytes as u64, Relaxed);
34    }
35}
36
37/// Human-readable residency census: one line per qtype that took at least one 2D weight, plus a
38/// total. Callers print it right after load — see `run-gen`'s `MEMRA_RESIDENCY_CENSUS=1`.
39pub fn residency_census_report() -> String {
40    use std::sync::atomic::Ordering::Relaxed;
41    let name = |q: usize| -> &'static str {
42        match q as i32 {
43            QT_Q8_0 => "Q8_0", QT_Q4_K => "Q4_K", QT_Q6_K => "Q6_K", QT_Q5_K => "Q5_K",
44            QT_Q3_K => "Q3_K", QT_IQ4_XS => "IQ4_XS", QT_IQ3_S => "IQ3_S", QT_NVFP4 => "NVFP4",
45            QT_F32 => "F32", QT_NVFP4_RP => "NVFP4_RP", QT_F8_E4M3 => "F8_E4M3",
46            QT_BF16 => "BF16", QT_Q4_0 => "Q4_0", QT_Q2_K => "Q2_K", _ => "?",
47        }
48    };
49    let mut out = String::from("residency census (2D matmul weights, resident container):\n");
50    let (mut tn, mut tb) = (0usize, 0u64);
51    for (q, slot) in RESIDENCY_CENSUS.iter().enumerate() {
52        let (n, b) = (slot.0.load(Relaxed), slot.1.load(Relaxed));
53        if n == 0 { continue; }
54        tn += n; tb += b;
55        out += &format!("  {:>9}: {:>4} tensors  {:>9.3} MiB\n", name(q), n,
56                        b as f64 / (1024.0 * 1024.0));
57    }
58    out += &format!("  {:>9}: {:>4} tensors  {:>9.3} MiB", "TOTAL", tn,
59                    tb as f64 / (1024.0 * 1024.0));
60    out
61}
62
63/// A weight tensor resident on GPU. Quantized weights stay in GGUF block bytes (`Quant`);
64/// small non-quant tensors (norms, sometimes embed/lm_head) are kept dequantized as f32 (`Float`).
65/// This keeps VRAM ~= on-disk quant size (fixes the f32-on-load OOM).
66pub enum GpuTensor {
67    Quant {
68        bytes: CudaSlice<u8>,
69        qtype: i32,
70        row_bytes: usize,
71        ne: Vec<u64>,
72        scale: f32,
73        /// SPLIT-PLANE walk-order repack (A6, 2026-07-04): NVFP4 matmul weights are repacked at
74        /// load into [quant plane out_f x in_f/64 x 32B][scale plane out_f x in_f/64 x 4B] — same
75        /// bytes, same total size, but a lane's per-group weight read becomes ONE 16B-aligned
76        /// LDG.128 + a dense 4B scale word instead of 5 scattered 4B LDGs at 36B stride (the "18B
77        /// straggle"). Every consumer kernel has an `_rp` twin (bit-identical: pure byte
78        /// permutation, same dot order). `rp=false` = original GGUF block layout (all other
79        /// dtypes, MoE-staged expert bytes, MEMRA_RP=0 escape).
80        rp: bool,
81        /// CUTLASS NVFP4 prefill operand (repacked B + swizzled SFB), built ALONGSIDE `bytes` at load
82        /// when MEMRA_FP4_CUTLASS is set. `bytes` stays raw GGUF so decode (MMVQ/dp4a) is untouched;
83        /// prefill (m>=128) reads this. Only ever Some for NVFP4 weights under cfg(memra_cutlass).
84        #[cfg(memra_cutlass)]
85        cutlass: Option<CutlassWeight>,
86        /// FP8-ACT PREFILL operand (MEMRA_PP_FP8=1, probe verdict 2026-07-08): the checkpoint's RAW
87        /// e4m3 bytes + per-tensor f32 weight_scale, stashed ALONGSIDE the Q8_0 re-encode for the
88        /// F8-E4M3-origin 2D projections (~1 B/w extra on those layers). `bytes` stays Q8_0 so
89        /// decode (dp4a/MMVQ) is untouched; only the m>=16 prefill dispatch (cuBLASLt FP8 TN,
90        /// fp8_ffi.rs) reads this. None unless the env is set at load (zero VRAM cost by default).
91        fp8: Option<Fp8Weight>,
92        /// Q4_0 SPLIT-PLANE MIRROR (2026-07-10, the 18B-straggle cure for decode): qs plane
93        /// [out_f x nblk x 16B] + d plane [out_f x nblk x 2B] built device-side at model load
94        /// (q4_0_split_rp_build) for decode-hot trunk weights. Raw `bytes` stay resident —
95        /// prefill (gemm/MMQ) and Stage-A read those; the m<=8 mmvq/batched/fused dispatch
96        /// reads this when present (`_rp` twins; microprobe m=1 1.34x, m=3 1.17x, bitwise).
97        /// None everywhere except where the arch-load hook opted in (VRAM cost = weight size).
98        rp4: Option<CudaSlice<u8>>,
99        /// FP16 DEQUANT MIRROR (MEMRA_PP_F16=1, probe 2026-07-26): row-major fp16 of a 2D Q8_0
100        /// projection, built device-side at load (f16_ffi::build_q8_f16). `bytes` stay Q8_0 so
101        /// decode is untouched; the m>=16 prefill dispatch (cuBLASLt FP16 TN, 611-687 TF vs
102        /// MMQ's ~200 TF class) reads this. None unless the env is set (VRAM = 2 B/w extra).
103        f16: Option<CudaSlice<u8>>,
104    },
105    Float {
106        data: CudaSlice<f32>,
107        ne: Vec<u64>,
108    },
109    /// BF16-RESIDENT full-precision matmul weight (MEMRA_FULL_PREC only). Holds the checkpoint's raw
110    /// bf16 bytes (`u8`, little-endian u16 pairs) — 2 B/w vs the 4 B/w a `Float` f32 materialization
111    /// would cost, so the 9B trunk stays ~18GB in VRAM instead of ~36GB. Consumed via dequant-on-use:
112    /// each matmul expands this to a transient f32 scratch and rides the SAME cuBLASLt f32 GEMV the
113    /// `Float` arm uses (bit-identical to a load-time bf16->f32 dequant, just deferred). Never a norm
114    /// (norms stay `Float` f32); never on a fast/GEMM/MMQ path (uses_q8_1_fast/gemm_supports = false).
115    FloatBf16 {
116        data: CudaSlice<u8>,
117        ne: Vec<u64>,
118    },
119}
120
121/// FP8-native prefill operand: raw checkpoint e4m3 codes `[out_f, in_f]` row-major (EXACT — the
122/// weight side of the FP8 GEMM does no re-quantization) + its weight scale(s). Per-tensor class:
123/// `scale` is the dequant scalar folded into the GEMM's scale pointer together with the per-batch
124/// activation scale, `blk == None`. Block-128 class (Qwen official FP8): `blk == Some` and
125/// `scale == 1.0` — see `Fp8BlockScales` for the resident layout contract.
126pub struct Fp8Weight {
127    pub bytes: CudaSlice<u8>,
128    pub scale: f32,
129    pub blk: Option<Fp8BlockScales>,
130}
131
132/// Device-resident block-128 weight-scale grid for an e4m3 operand (B1b, lane fp8st 2026-08-03).
133///
134/// STORAGE LAYOUT (the canonical device layout every future consumer builds from): a flat f32
135/// buffer in the CHECKPOINT'S on-disk order — row-major `[rows = ceil(out_f/128),
136/// cols = ceil(in_f/128)]`, so `scales[ob * cols + kb]` scales the 128x128 weight tile at
137/// output-block `ob`, input-block `kb` (uploaded verbatim from `memra_gguf::source::F8BlockGrid`,
138/// no permutation — one host decode, one htod). Rationale: (1) the per-block-dequant mmvq twin
139/// (qmatvec_e4m3_mmvq extension, DECISION.md B1) indexes `(o >> 7) * cols + (e >> 7)` — natural
140/// in this order; (2) for cuBLASLt BLK128x128 the weight `[out, in]` row-major is the TN GEMM's
141/// column-major `[k=in, n=out]` A operand, and this same linear order IS that view's column-major
142/// block grid with ld = cols(=kblk) — probe P1 (`probe/fp8_lt_blk_probe.cu`) verifies whether
143/// sm_120 accepts it directly; if Lt wants a different order, the reorder happens at the GEMM
144/// plan build, NOT here. NO KERNEL CONSUMES THIS YET: the loader keeps every block-128 tensor's
145/// decode/prefill on the Q8_0 re-encode until the consuming kernels land (try_fp8_gemm skips
146/// blk operands; the QT_F8_E4M3 one-copy arm rejects them). This struct's job is bytes+scales
147/// resident and correct.
148pub struct Fp8BlockScales {
149    pub scales: CudaSlice<f32>,
150    pub rows: usize, // ceil(out_f/128)
151    pub cols: usize, // ceil(in_f/128)
152}
153
154/// Host-side split-plane repack of NVFP4 GGUF block bytes (A6). Input: out_f rows of in_f/64
155/// 36-byte blocks ([4B UE4M3 scales][32B packed e2m1]). Output (same length): quant plane
156/// (out_f x nsb64 x 32B) followed by scale plane (out_f x nsb64 x 4B). Pure byte permutation.
157pub fn repack_nvfp4_split(bytes: &[u8], out_f: usize) -> Vec<u8> {
158    let row_bytes = bytes.len() / out_f;
159    let nsb64 = row_bytes / 36;
160    debug_assert_eq!(
161        row_bytes % 36,
162        0,
163        "NVFP4 row_bytes must be a multiple of 36"
164    );
165    let qplane = out_f * nsb64 * 32;
166    let mut rp = vec![0u8; bytes.len()];
167    for o in 0..out_f {
168        for s in 0..nsb64 {
169            let src = &bytes[o * row_bytes + s * 36..o * row_bytes + s * 36 + 36];
170            rp[qplane + (o * nsb64 + s) * 4..qplane + (o * nsb64 + s) * 4 + 4]
171                .copy_from_slice(&src[0..4]);
172            rp[(o * nsb64 + s) * 32..(o * nsb64 + s) * 32 + 32].copy_from_slice(&src[4..36]);
173        }
174    }
175    rp
176}
177
178/// Inverse of `repack_nvfp4_split` (the roundtrip gate).
179pub fn unpack_nvfp4_split(rp: &[u8], out_f: usize) -> Vec<u8> {
180    let row_bytes = rp.len() / out_f;
181    let nsb64 = row_bytes / 36;
182    let qplane = out_f * nsb64 * 32;
183    let mut back = vec![0u8; rp.len()];
184    for o in 0..out_f {
185        for s in 0..nsb64 {
186            back[o * row_bytes + s * 36..o * row_bytes + s * 36 + 4].copy_from_slice(
187                &rp[qplane + (o * nsb64 + s) * 4..qplane + (o * nsb64 + s) * 4 + 4],
188            );
189            back[o * row_bytes + s * 36 + 4..o * row_bytes + s * 36 + 36]
190                .copy_from_slice(&rp[(o * nsb64 + s) * 32..(o * nsb64 + s) * 32 + 32]);
191        }
192    }
193    back
194}
195
196/// A6 repack seam: default ON, `MEMRA_RP=0` restores the GGUF block layout everywhere (rollback/A-B).
197pub fn rp_enabled() -> bool {
198    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
199    *ON.get_or_init(|| std::env::var("MEMRA_RP").map(|v| v != "0").unwrap_or(true))
200}
201
202/// FULL-PRECISION LOADER MODE (MEMRA_FULL_PREC=1, default OFF — MTP-heal research platform).
203/// Bypasses the standing loader law (large BF16/F8 -> Q8_0/NVFP4 re-encode, the "Float-poison"
204/// tripwire). Under this flag every weight loads as Float and compute rides the Stage-A f32 oracle
205/// path end to end — SLOW IS FINE, this mode exists for exactness (the MTP acceptance CEILING at
206/// full precision), not speed. Large 2D matmul weights stay bf16-resident (`GpuTensor::FloatBf16`)
207/// with dequant-on-use so the 9B (~18GB bf16) + f32 activations fit 24GB instead of blowing to
208/// ~38GB as an all-f32 materialization. The Float-poison tripwire warnings are CORRECT behavior
209/// here and are suppressed. See docs/FLAGS.md and HANDOVER "MEMRA DUAL-SHAPE".
210pub fn full_prec_enabled() -> bool {
211    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
212    *ON.get_or_init(|| {
213        std::env::var("MEMRA_FULL_PREC")
214            .map(|v| v == "1")
215            .unwrap_or(false)
216    })
217}
218
219/// LOADER-LAW allowlist (loadersweep audit 2026-07-08): 2D Float tensors that are DELIBERATELY
220/// Float despite being matmul-class. Every entry needs an audit rationale — this list silences
221/// the tripwire below, so an unjustified entry re-opens the trap.
222///   * ffn_gate_inp (MoE router, 35B GGUF F32 [2048,256] / M3 ST F32 [6144,64]): the router's
223///     top-k SELECTION is discontinuous — quantizing shifts logits and flips expert choice (a
224///     class change, not an FP-order change). llama.cpp keeps every router F32 (its converter
225///     forces F32) so Float is bench-parity, it sits on NO all-or-nothing predicate, and the
226///     decode-exact contract is already built around its cuBLASLt path
227///     (hybrid_forward.rs moe_ffn_sequential_zq8 router comment).
228fn float_2d_audited(name: &str) -> bool {
229    name.ends_with("ffn_gate_inp.weight")
230}
231
232/// Once-per-name-pattern loader-law warning (`blk.{il}.` collapses to `blk.*.` so a 48-layer
233/// offender prints ONE line, not 48). See the call site in `load_from_source` for the law.
234fn warn_float_2d_once(name: &str, ne: &[u64], src_type: GgmlType) {
235    use std::sync::{Mutex, OnceLock};
236    static SEEN: OnceLock<Mutex<std::collections::HashSet<String>>> = OnceLock::new();
237    let pat = match name.strip_prefix("blk.").and_then(|r| r.split_once('.')) {
238        Some((_, suffix)) => format!("blk.*.{suffix}"),
239        None => name.to_string(),
240    };
241    let mut seen = SEEN
242        .get_or_init(|| Mutex::new(std::collections::HashSet::new()))
243        .lock()
244        .unwrap();
245    if seen.insert(pat.clone()) {
246        eprintln!(
247            "[loader-law] WARNING: {pat} loads as 2D Float ne={ne:?} (src {src_type:?}) — \
248                   a Float matmul weight rides cuBLAS f32 GEMV and poisons all-or-nothing q8-fast \
249                   predicates (uses_q8_1_fast/mixer_in_q8_1_fast). If matmul-class: Q8_0-encode at \
250                   load (model.rs ssm arm / source.rs BF16+F8 gates). If deliberately Float: add \
251                   it to float_2d_audited with the audit rationale."
252        );
253    }
254}
255
256/// CUTLASS-layout NVFP4 weight (B operand) for the prefill FP4 GEMM. Built once at load from the raw
257/// GGUF bytes (de-interleave + SFB swizzle). Coexists with the raw `bytes` (decode reads bytes).
258#[cfg(memra_cutlass)]
259pub struct CutlassWeight {
260    /// Plain K-contiguous packed e2m1, [out_f, in_f/2] bytes.
261    pub b_packed: CudaSlice<u8>,
262    /// Swizzled SFB (CUTLASS SfAtom layout), sized via cutlass_sfb_size(out_f, in_f).
263    pub sfb_swizzled: CudaSlice<u8>,
264}
265
266impl GpuTensor {
267    pub fn ne(&self) -> &[u64] {
268        match self {
269            GpuTensor::Quant { ne, .. } => ne,
270            GpuTensor::Float { ne, .. } => ne,
271            GpuTensor::FloatBf16 { ne, .. } => ne,
272        }
273    }
274    pub fn in_features(&self) -> usize {
275        self.ne()[0] as usize
276    }
277    pub fn out_features(&self) -> usize {
278        self.ne()[1] as usize
279    }
280    /// Per-tensor post-matmul macro-scale (NVFP4 carries scale != 1.0; all others -> 1.0, a no-op).
281    /// Used by the fused SwiGLU epilogue to fold the gate/up scale into one kernel.
282    pub fn scale(&self) -> f32 {
283        match self {
284            GpuTensor::Quant { scale, .. } => *scale,
285            GpuTensor::Float { .. } | GpuTensor::FloatBf16 { .. } => 1.0,
286        }
287    }
288
289    /// Load a tensor, keeping quant types packed and float types as f32. (GGUF entry point —
290    /// thin wrapper over the source-agnostic `load_from_source`; behavior is unchanged.)
291    pub fn load(e: &Engine, g: &GgufFile, name: &str) -> Result<Self, Box<dyn std::error::Error>> {
292        Self::load_from_source(e, &GgufSource(g), name)
293    }
294
295    /// Source-agnostic load: works from any `TensorSource` (GGUF or safetensors). The engine's
296    /// forward graph only ever asks for ggml-style names; the source maps them to its own layout.
297    ///
298    /// RESIDENCY CENSUS (lane/fp8-decode-v1, 2026-08-05): the wrapper tallies what each 2D
299    /// matmul weight ACTUALLY became — resident qtype + resident bytes — so the FP8-ST decode
300    /// arm's claim ("e4m3 stays native instead of paying the Q8_0-slab tax") is a measured
301    /// per-checkpoint fact rather than an assumption about the checkpoint's dtype mix. Read it
302    /// with `residency_census_report()`; zero cost when never read.
303    pub fn load_from_source(
304        e: &Engine,
305        src: &dyn TensorSource,
306        name: &str,
307    ) -> Result<Self, Box<dyn std::error::Error>> {
308        let t = Self::load_from_source_inner(e, src, name)?;
309        if let GpuTensor::Quant { qtype, bytes, ne, .. } = &t {
310            if ne.len() == 2 {
311                residency_census_note(*qtype, bytes.len());
312            }
313        }
314        Ok(t)
315    }
316
317    fn load_from_source_inner(
318        e: &Engine,
319        src: &dyn TensorSource,
320        name: &str,
321    ) -> Result<Self, Box<dyn std::error::Error>> {
322        // A1 DIRECT NVFP4 IMPORT (2026-07-04): a PLAIN modelopt/Reza NVFP4 weight from a
323        // safetensors source repacks straight into the A6 split-plane resident layout in ONE host
324        // pass (nvfp4_repack::repack_modelopt_to_split — the scale plane is the file's
325        // weight_scale bytes verbatim), never materializing the GGUF 36B-block intermediate.
326        // The GGUF hop remains only for MEMRA_ST_DIRECT=0 (rollback/A-B seam — byte-identical
327        // resident weights either way), MEMRA_RP=0, the hybrid V-reorder transforms, and the
328        // opt-in CUTLASS resident operand (which is built from raw GGUF-layout bytes).
329        let cutlass_wants_raw = cfg!(memra_cutlass) && std::env::var("MEMRA_FP4_CUTLASS").is_ok();
330        let st_direct = std::env::var("MEMRA_ST_DIRECT")
331            .map(|v| v != "0")
332            .unwrap_or(true);
333        if rp_enabled() && st_direct && !cutlass_wants_raw {
334            if let Some(nv) = src.find_nvfp4_native(name) {
335                if nv.in_f % 64 == 0 && nv.out_f > 0 {
336                    // Same post-matmul macro-scale sibling lookup as the GGUF-layout arm below.
337                    let stem = name.strip_suffix(".weight").unwrap_or(name);
338                    let scale = match src.find(&format!("{stem}.scale")) {
339                        Some(sv) => f32::from_le_bytes(sv.bytes[..4].try_into().unwrap()),
340                        None => 1.0,
341                    };
342                    let bytes =
343                        e.htod_bytes(&memra_gguf::nvfp4_repack::repack_modelopt_to_split(
344                            nv.wbytes, nv.wscale, nv.out_f, nv.in_f,
345                        ))?;
346                    return Ok(GpuTensor::Quant {
347                        bytes,
348                        qtype: QT_NVFP4,
349                        row_bytes: nv.in_f / 64 * 36,
350                        ne: vec![nv.in_f as u64, nv.out_f as u64],
351                        scale,
352                        rp: true,
353                        #[cfg(memra_cutlass)]
354                        cutlass: None,
355                        fp8: None, f16: None,
356                        rp4: None,
357                    });
358                }
359            }
360        }
361        // E4M3-DIRECT (DEFAULT since lane/fp8-decode-v1 2026-08-05; MEMRA_ST_E4M3=0 rolls back to the
362        // Q8_0 slab. Introduced default-off by lane e4m3dec 2026-07-08): F8-E4M3-origin 2D projections keep
363        // the checkpoint's RAW e4m3 device bytes + per-tensor weight_scale as the ONE resident copy
364        // (QT_F8_E4M3) instead of the Q8_0 re-encode — decode dequants e4m3 in-kernel
365        // (qmatvec_e4m3_mmvq, the checkpoint's own precision, no lossy re-quant hop), prefill
366        // (m>=16) rides the cuBLASLt FP8 GEMM on the SAME bytes (try_fp8_gemm). Frees the Q8_0
367        // duplicate the MEMRA_PP_FP8 stash needed (~3.4GB on the NV-27B) — full FP8 prefill coverage
368        // with no VRAM budget. Placed BEFORE `find` so the host-side F8->Q8_0 re-encode is skipped
369        // entirely (faster load). in_f%32 is the q8_1 activation block gate (every F8 projection in
370        // the NV-27B satisfies it; a violator falls through to the Q8_0 arm unchanged).
371        // BLOCK-128 GATE: the QT_F8_E4M3 decode kernel family (qmatvec_e4m3_mmvq + batched
372        // twins) consumes ONE scalar weight scale — dispatching a block-128 operand through it
373        // would silently dequant every tile with scale 1.0. Until the per-block-dequant mmvq
374        // twin lands (DECISION.md B1 second half), block-128 tensors fall through to the Q8_0
375        // re-encode (correct floor); their raw bytes+scales still go resident via the
376        // MEMRA_PP_FP8 stash arm below for the P1 GEMM work.
377        if crate::fp8_ffi::st_e4m3_enabled() {
378            if let Some(f8) = src.find_fp8_native(name) {
379                if f8.blk.is_none() && f8.in_f % 32 == 0 && f8.out_f > 0 {
380                    return Ok(GpuTensor::Quant {
381                        bytes: e.htod_bytes(&f8.bytes)?,
382                        qtype: crate::QT_F8_E4M3,
383                        row_bytes: f8.in_f,
384                        ne: vec![f8.in_f as u64, f8.out_f as u64],
385                        scale: f8.scale,
386                        rp: false,
387                        #[cfg(memra_cutlass)]
388                        cutlass: None,
389                        fp8: None, f16: None,
390                        rp4: None,
391                    });
392                }
393            }
394        }
395        // ARM B' — GPU BLOCK-128 DEQUANT (MEMRA_FP8_BLK_GPU=1, default OFF; lane fp8-gemm-arm
396        // 2026-08-03). A block-128 FP8 checkpoint (Qwen official FP8 / DeepSeek-V3 lineage)
397        // currently loads via the host path: full f32 dequant of the tensor (f8_deq_f32) then a
398        // host Q8_0 re-encode (f32_to_q8_0) — correct, but a serial CPU pass over every byte of
399        // every projection. This arm does the same math on the GPU in ONE pass
400        // (cu/fp8_blk_dequant.cu): upload the raw e4m3 codes + the scale grid, write Q8_0
401        // blocks directly. BYTE-IDENTICAL to the host path (kernel-check [fp8-blk-gpu] arm
402        // asserts it on ragged and aligned shapes), so the resident tensor, the MMQ/MMVQ
403        // dispatch, and decode are all bit-for-bit unchanged — this is a LOAD-TIME
404        // optimization only, not a numeric config change.
405        //
406        // Placed BEFORE `find` for exactly the reason the MEMRA_ST_E4M3 arm above is: `find`
407        // would otherwise do the host dequant+re-encode we are replacing. Per-tensor and
408        // per-row scale classes are NOT touched (find_fp8_native returns blk=None / None for
409        // them) and neither are V-reorder Transform targets (find_fp8_native rejects those with
410        // a grid — the permutation invalidates the on-disk grid, so they keep the host path).
411        //
412        // NO st_e4m3 EXCLUSION (lane/fp8-decode-v1 2026-08-05): this arm used to carry
413        // `&& !st_e4m3_enabled()`, written when MEMRA_ST_E4M3 was default OFF and meant only as
414        // "the native arm above already claimed this tensor". Once native residency became the
415        // DEFAULT that condition would have been true on every run and silently disabled ARM B'
416        // for the whole block-128 class — the exact silent-slow-path landmine the flags doctrine
417        // forbids. The two arms are already disjoint by construction and need no cross-gate: the
418        // arm above returns only when `f8.blk.is_none()`, this one runs only when `f8.blk` is
419        // Some, so a tensor that reaches here was never eligible for native residency.
420        if crate::fp8_ffi::fp8_blk_gpu_enabled() {
421            if let Some(f8) = src.find_fp8_native(name) {
422                if let Some(grid) = f8.blk.as_ref() {
423                    let (in_f, out_f) = (f8.in_f, f8.out_f);
424                    if in_f % 32 == 0 && out_f > 0 && f8.bytes.len() == out_f * in_f {
425                        let bytes =
426                            e.fp8_blk_dequant_q8_0(&f8.bytes, &grid.scales, out_f, in_f)?;
427                        return Ok(GpuTensor::Quant {
428                            bytes,
429                            qtype: QT_Q8_0,
430                            row_bytes: in_f / 32 * 34,
431                            ne: vec![in_f as u64, out_f as u64],
432                            scale: 1.0,
433                            rp: false,
434                            #[cfg(memra_cutlass)]
435                            cutlass: None,
436                            fp8: None, f16: None,
437                            rp4: None,
438                        });
439                    }
440                }
441            }
442        }
443        let mut v = src
444            .find(name)
445            .unwrap_or_else(|| panic!("missing tensor {name}"));
446        // MEMRA_KQ_NVFP4=1 (opt-in, 2026-07-08): re-encode Q4_K/Q5_K 2D matmul weights to NVFP4 at
447        // load. The k-quant mmvq family runs at 61-70% of the bandwidth wall on this rig (measured
448        // BOTH engines — the kernels share ancestry) while the in-house NVFP4 path runs at 96%.
449        // The daily GGUF's quant mix was chosen for llama's kernels, not ours: Q4_K -> NVFP4 is
450        // 4-bit -> 4-bit at +26pp kernel efficiency; Q5_K -> NVFP4 also drops bytes (0.69 -> 0.56
451        // B/w) at a small real re-quant cost (5 -> 4 bit; gates + acceptance arbitrate). Q6_K/Q8_0
452        // excluded (6/8-bit -> 4-bit is a real quality cliff — the lm_head stays untouched).
453        // MEMRA_KQ_NVFP4 (opt-in SPEED-OVER-QUALITY mode, measured 2026-07-08 on the 9B):
454        // =2 (Q4_K+Q5_K -> NVFP4): +3.9% plain decode (129.5 -> 134.5, the Q5 bytes win),
455        //    acceptance tax ~3pts on hard content (p2 74.0 -> 70.7, p3 66.9 -> 64.9).
456        // =1 (Q4_K only): NO perf gain AND still ~3pts tax — Q4_K is ASYMMETRIC (6-bit
457        //    scale+min per 32); NVFP4 is symmetric e2m1: dropping the zero-point is real
458        //    error even 4-bit -> 4-bit. The "same bpw = same class" assumption is FALSE
459        //    across asymmetric/symmetric formats. Kept only for the record.
460        let kq = std::env::var("MEMRA_KQ_NVFP4")
461            .ok()
462            .and_then(|x| x.parse::<u8>().ok())
463            .unwrap_or(0);
464        if (kq >= 1 && v.ggml_type == GgmlType::Q4_K || kq >= 2 && v.ggml_type == GgmlType::Q5_K)
465            && v.ne.len() == 2
466            && v.ne[0] % 64 == 0
467            && !name.starts_with("output")
468        {
469            let n: u64 = v.ne.iter().product();
470            let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n as usize);
471            let packed = memra_gguf::nvfp4_repack::f32_to_nvfp4(&f32v);
472            v = memra_gguf::source::TensorView {
473                bytes: std::borrow::Cow::Owned(packed),
474                ggml_type: GgmlType::NVFP4,
475                ne: v.ne.clone(),
476            };
477        }
478        let qtype = match v.ggml_type {
479            GgmlType::Q8_0 => Some(QT_Q8_0),
480            GgmlType::Q4_K => Some(QT_Q4_K),
481            GgmlType::Q6_K => Some(QT_Q6_K),
482            GgmlType::Q5_K => Some(QT_Q5_K),
483            GgmlType::Q3_K => Some(QT_Q3_K),
484            GgmlType::IQ4_XS => Some(QT_IQ4_XS),
485            GgmlType::IQ3_S => Some(QT_IQ3_S),
486            GgmlType::NVFP4 => Some(QT_NVFP4),
487            GgmlType::Q4_0 => Some(QT_Q4_0),
488            // F32/F16/BF16 (the dtypes safetensors carries) -> Float path below.
489            _ => None,
490        };
491        match qtype {
492            Some(qt) => {
493                let out_f = v.ne[1] as usize;
494                let row_bytes = v.bytes.len() / out_f;
495                // NVFP4 two-level scale: per-16 ue4m3 micro-scale is in the dequant; the per-tensor
496                // F32 macro-scale lives in a sibling "<stem>.scale" tensor, applied POST-matmul
497                // (llama build_lora_mm: ggml_mul(res, w_s)). ".input_scale" is the W4A4 activation
498                // scale — UNUSED on our W4A16/f32 path. Only NVFP4 carries it; others -> 1.0 (no-op).
499                let scale = if qt == QT_NVFP4 {
500                    let stem = name.strip_suffix(".weight").unwrap_or(name);
501                    match src.find(&format!("{stem}.scale")) {
502                        Some(sv) => f32::from_le_bytes(sv.bytes[..4].try_into().unwrap()),
503                        None => 1.0,
504                    }
505                } else {
506                    1.0
507                };
508                // A6 SPLIT-PLANE repack: NVFP4 2-D matmul weights upload in walk-order layout
509                // (host-side permutation before htod — zero VRAM spike, layer-streamed by
510                // construction). Every consumer kernel dispatches its `_rp` twin off the flag.
511                let rp = qt == QT_NVFP4
512                    && v.ne.len() == 2
513                    && (v.ne[0] as usize) % 64 == 0
514                    && v.bytes.len() % out_f == 0
515                    && (v.bytes.len() / out_f) % 36 == 0
516                    && rp_enabled();
517                let bytes = if rp {
518                    e.htod_bytes(&repack_nvfp4_split(&v.bytes, out_f))?
519                } else {
520                    e.htod_bytes(&v.bytes)?
521                };
522                // CUTLASS NVFP4 prefill operand, built from the RAW GGUF bytes (a temp raw upload
523                // when the resident `bytes` are repacked). Gated: only NVFP4 weights, only when
524                // MEMRA_FP4_CUTLASS is set, only under cfg(memra_cutlass). in_f%64==0 is the NVFP4
525                // K-block constraint (same as the dispatch).
526                #[cfg(memra_cutlass)]
527                let cutlass = {
528                    let in_f = v.ne[0] as usize;
529                    // Skip the resident repack when OTF is requested (per-call repack instead) — the
530                    // resident path ~doubles NVFP4 weight VRAM and OOMs larger models (e.g. 27B/24GB).
531                    if qt == QT_NVFP4
532                        && in_f % 64 == 0
533                        && v.ne.len() == 2
534                        && std::env::var("MEMRA_FP4_CUTLASS").is_ok()
535                        && std::env::var("MEMRA_FP4_CUTLASS_OTF").is_err()
536                    {
537                        let raw_dev;
538                        let src_dev = if rp {
539                            raw_dev = e.htod_bytes(&v.bytes)?;
540                            &raw_dev
541                        } else {
542                            &bytes
543                        };
544                        let (b_packed, sfb_swizzled) =
545                            e.build_cutlass_weight(src_dev, out_f, in_f, row_bytes)?;
546                        Some(CutlassWeight {
547                            b_packed,
548                            sfb_swizzled,
549                        })
550                    } else {
551                        None
552                    }
553                };
554                // FP8-ACT PREFILL operand (MEMRA_PP_FP8=1): for F8-E4M3-sourced projections (they
555                // surface as Q8_0 from the source's re-encode) ALSO stash the raw e4m3 device
556                // bytes + weight_scale. The source guarantees byte order matches `v` (the
557                // Transform arm's V-reorder is baked into both); the ne check guards a mixup.
558                // VRAM BUDGET (24GB rigs, 2026-07-08): the stash duplicates every F8-origin
559                // projection (~+3.4GB on the 27B) — fine on the 96GB box, OOM here. The stash
560                // spends from MEMRA_PP_FP8_BUDGET_MB (default 1536); once spent, remaining
561                // tensors ride the old path. Load order is layer order, so the budget covers a
562                // PREFIX of layers — coverage (and the prefill win) scales with the budget.
563                // MEMRA_FP8_MMQ=1 (lane/fp8-mmq) admits the SAME stash for the block-128 class:
564                // the per-block MMQ prefill kernel is that class's consumer, and it needs exactly
565                // what this arm makes resident (raw e4m3 bytes + the verbatim f32 grid). It shares
566                // the budget accounting below, so a 24GB rig still caps the duplicate.
567                let fp8 = if qt == QT_Q8_0
568                    && (crate::fp8_ffi::pp_fp8_enabled() || crate::fp8_ffi::fp8_mmq_enabled())
569                {
570                    match src.find_fp8_native(name) {
571                        Some(f8)
572                            if v.ne.len() == 2
573                                && f8.in_f as u64 == v.ne[0]
574                                && f8.out_f as u64 == v.ne[1] =>
575                        {
576                            use std::sync::atomic::{AtomicUsize, Ordering};
577                            static FP8_SPENT: AtomicUsize = AtomicUsize::new(0);
578                            static FP8_BUDGET: std::sync::OnceLock<usize> =
579                                std::sync::OnceLock::new();
580                            let budget = *FP8_BUDGET.get_or_init(|| {
581                                std::env::var("MEMRA_PP_FP8_BUDGET_MB")
582                                    .ok()
583                                    .and_then(|v| v.parse::<usize>().ok())
584                                    .unwrap_or(1536)
585                                    << 20
586                            });
587                            let sz = f8.bytes.len();
588                            if FP8_SPENT.fetch_add(sz, Ordering::Relaxed) + sz <= budget {
589                                // Block-128 grid rides along resident (checkpoint order,
590                                // Fp8BlockScales layout contract). try_fp8_gemm still skips blk
591                                // operands (cuBLASLt takes no block grid on sm_120, P1-VERDICT);
592                                // try_fp8_blk_mmq is their consumer under MEMRA_FP8_MMQ=1.
593                                let blk = match f8.blk {
594                                    Some(g) => Some(Fp8BlockScales {
595                                        scales: e.htod(&g.scales)?,
596                                        rows: g.rows,
597                                        cols: g.cols,
598                                    }),
599                                    None => None,
600                                };
601                                Some(Fp8Weight {
602                                    bytes: e.htod_bytes(&f8.bytes)?,
603                                    scale: f8.scale,
604                                    blk,
605                                })
606                            } else {
607                                FP8_SPENT.fetch_sub(sz, Ordering::Relaxed);
608                                None
609                            }
610                        }
611                        _ => None,
612                    }
613                } else {
614                    None
615                };
616                Ok(GpuTensor::Quant {
617                    bytes,
618                    qtype: qt,
619                    row_bytes,
620                    ne: v.ne.clone(),
621                    scale,
622                    rp,
623                    #[cfg(memra_cutlass)]
624                    cutlass,
625                    fp8,
626                    rp4: None,
627                    f16: None,
628                })
629            }
630            None => {
631                let n: u64 = v.ne.iter().product();
632                // FULL-PRECISION MODE (MEMRA_FULL_PREC): NO re-encodes. Large 2D bf16 matmul weights
633                // stay bf16-resident (FloatBf16, dequant-on-use) so the trunk fits VRAM; everything
634                // else (small 2D, 1D norms, F16/F32) rides the exact f32 Float path below. The ssm
635                // Q8_0 re-encode and the Float-poison tripwire are BYPASSED here (both are the loader
636                // law this mode exists to suspend — the warnings would be correct but noise).
637                if full_prec_enabled() {
638                    // Only bf16 sources take the resident-bf16 arm; F16/F32 fall through to f32 Float
639                    // (exact, and tiny/absent in the bf16 ST checkpoints this mode targets). The 1M
640                    // threshold keeps small tensors (norms, gate_inp) on the proven f32 path — only
641                    // the big trunk matrices need the 2 B/w VRAM saving.
642                    if v.ggml_type == GgmlType::BF16 && v.ne.len() == 2 && n >= 1_000_000 {
643                        let data = e.htod_bytes(&v.bytes)?; // raw bf16 bytes, u16 LE pairs
644                        return Ok(GpuTensor::FloatBf16 {
645                            data,
646                            ne: v.ne.clone(),
647                        });
648                    }
649                    let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n as usize);
650                    return Ok(GpuTensor::Float {
651                        data: e.htod(&f32v)?,
652                        ne: v.ne.clone(),
653                    });
654                }
655                let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n as usize);
656                // ssm_beta/ssm_alpha stored F32 (the 35B GGUF): Q8_0-encode at load. F32 here
657                // fails `mixer_in_q8_1_fast` for the whole linear-attn mixer -> every linear
658                // layer falls off the fused norm+quantize chain onto cuBLAS f32 GEMV pairs
659                // (the NV-27B in_proj_a/b lesson, same all-or-nothing capability check; nsys
660                // 35B: 100 dot+reduce launches/token). Q8_0 of an F32 source is the same
661                // class-lossless step every 9B GGUF already ships for these tensors.
662                if v.ne.len() == 2
663                    && v.ne[0] % 32 == 0
664                    && (name.ends_with("ssm_beta.weight") || name.ends_with("ssm_alpha.weight")
665                        // E4B per_layer_model_proj (F16 [2560, 10752]): matmul-class — the
666                        // loader-law recipe (2026-07-12). As Float it rode cuBLAS f32 whose
667                        // m=1-vs-m=16 FP-order gap seeds inp_pl noise into EVERY layer's PLE
668                        // tail; the 42-layer stack amplifies it to logit maxdiff ~27 and the
669                        // chat-prompt prefill-vs-decode argmax gate fails.
670                        || name.ends_with("per_layer_model_proj.weight"))
671                {
672                    let q8 = memra_gguf::nvfp4_repack::f32_to_q8_0(&f32v);
673                    return GpuTensor::from_quant_bytes(
674                        e,
675                        &q8,
676                        GgmlType::Q8_0,
677                        v.ne[0],
678                        v.ne[1],
679                        1.0,
680                    );
681                }
682                // LOADER-LAW TRIPWIRE (loadersweep 2026-07-08): a 2D Float tensor with both dims
683                // >= 16 is almost certainly MATMUL-class, and a Float matmul weight (a) rides
684                // cuBLAS f32 GEMV pairs (dot_kernel + reduce_1Block in nsys) and (b) fails
685                // uses_q8_1_fast, poisoning every ALL-OR-NOTHING fast-path predicate it sits on
686                // (mixer_in_q8_1_fast etc.) — the trap that cost measurable perf 4 times (NV-27B
687                // in_proj_a/b BF16, 35B ssm_beta/alpha F32, M3 shexp cousin, M3 BF16 lm_head).
688                // Fix recipe: name-gated f32_to_q8_0 encode at load (see the ssm arm above /
689                // source.rs BF16+F8 gates). Norm-class tensors are 1D or have a dim < 16
690                // (conv1d ne[0]=4) and never reach this warning.
691                if v.ne.len() == 2 && v.ne[0] >= 16 && v.ne[1] >= 16 && !float_2d_audited(name) {
692                    warn_float_2d_once(name, &v.ne, v.ggml_type);
693                }
694                // F32/F16/BF16 (or as-yet-unhandled quant): dequant to f32. Small tensors only.
695                Ok(GpuTensor::Float {
696                    data: e.htod(&f32v)?,
697                    ne: v.ne.clone(),
698                })
699            }
700        }
701    }
702
703    /// Build a Quant tensor directly from raw ggml block bytes (FR-Spec self-trim: byte-level row
704    /// gather from an already-loaded weight — rows in every ggml quant are independent, so a
705    /// contiguous per-row byte copy is a lossless "trim"). `ne0` = in_features, `ne1` = rows.
706    pub fn from_quant_bytes(
707        e: &Engine,
708        bytes: &[u8],
709        ty: GgmlType,
710        ne0: u64,
711        ne1: u64,
712        scale: f32,
713    ) -> Result<Self, Box<dyn std::error::Error>> {
714        let qt = match ty {
715            GgmlType::Q8_0 => QT_Q8_0,
716            GgmlType::Q4_K => QT_Q4_K,
717            GgmlType::Q6_K => QT_Q6_K,
718            GgmlType::Q5_K => QT_Q5_K,
719            GgmlType::Q3_K => QT_Q3_K,
720            GgmlType::IQ4_XS => QT_IQ4_XS,
721            GgmlType::IQ3_S => QT_IQ3_S,
722            GgmlType::NVFP4 => QT_NVFP4,
723            GgmlType::Q4_0 => QT_Q4_0,
724            other => panic!("from_quant_bytes: unsupported dtype {other:?}"),
725        };
726        let row_bytes = bytes.len() / ne1 as usize;
727        // Same A6 repack as load_from_source: callers pass GGUF-layout host bytes (the FR-Spec
728        // self-trim row-gathers from the source file bytes, which are always original layout).
729        let rp = qt == QT_NVFP4 && ne0 % 64 == 0 && row_bytes % 36 == 0 && rp_enabled();
730        let dev = if rp {
731            e.htod_bytes(&repack_nvfp4_split(bytes, ne1 as usize))?
732        } else {
733            e.htod_bytes(bytes)?
734        };
735        Ok(GpuTensor::Quant {
736            bytes: dev,
737            qtype: qt,
738            row_bytes,
739            ne: vec![ne0, ne1],
740            scale,
741            rp,
742            #[cfg(memra_cutlass)]
743            cutlass: None,
744            fp8: None, f16: None,
745            rp4: None,
746        })
747    }
748
749    pub fn load_opt(
750        e: &Engine,
751        g: &GgufFile,
752        name: &str,
753    ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
754        Self::load_opt_from_source(e, &GgufSource(g), name)
755    }
756
757    pub fn load_opt_from_source(
758        e: &Engine,
759        src: &dyn TensorSource,
760        name: &str,
761    ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
762        if src.has(name) {
763            Ok(Some(Self::load_from_source(e, src, name)?))
764        } else {
765            Ok(None)
766        }
767    }
768
769    /// Accessor for tensors that MUST be f32 (norm weights). Panics if quantized.
770    pub fn float_data(&self) -> &CudaSlice<f32> {
771        match self {
772            GpuTensor::Float { data, .. } => data,
773            GpuTensor::Quant { .. } => panic!("expected float tensor (norm), got quantized"),
774            GpuTensor::FloatBf16 { .. } => {
775                panic!("expected f32 float tensor (norm), got bf16-resident matmul weight")
776            }
777        }
778    }
779}
780
781pub struct Layer {
782    pub attn_norm: GpuTensor,
783    pub wq: GpuTensor,
784    pub wk: GpuTensor,
785    pub wv: GpuTensor,
786    pub wo: GpuTensor,
787    pub q_norm: Option<GpuTensor>,
788    pub k_norm: Option<GpuTensor>,
789    pub ffn_norm: GpuTensor,
790    /// FFN: dense SwiGLU or routed MoE (OLMoE — dense attention + MoE FFN). Reuses the hybrid
791    /// `Ffn` enum + `load_ffn` so the routed-expert forward is shared with `HybridModel::moe_ffn`.
792    pub ffn: crate::hybrid::Ffn,
793}
794
795/// Host-resident embedding table for row gather (dequant only the needed token rows).
796pub struct EmbedHost {
797    pub raw: Vec<u8>,
798    pub ggml_type: GgmlType,
799    pub n_embd: usize,
800}
801impl EmbedHost {
802    pub fn from_gguf(g: &GgufFile, name: &str) -> Self {
803        Self::from_source(&GgufSource(g), name)
804    }
805    pub fn from_source(src: &dyn TensorSource, name: &str) -> Self {
806        let v = src
807            .find(name)
808            .unwrap_or_else(|| panic!("missing embed {name}"));
809        EmbedHost {
810            raw: v.bytes.to_vec(),
811            ggml_type: v.ggml_type,
812            n_embd: v.ne[0] as usize,
813        }
814    }
815    /// QT int + row_bytes for this embed table's dtype (for the device embed-gather kernel).
816    /// CUDA-GRAPH-PLAN Phase 1. Mirrors the GpuTensor qtype mapping.
817    pub fn qt_and_row_bytes(&self, n_embd: usize) -> (i32, usize) {
818        let (blk, tsize) = self.ggml_type.block_and_type_size();
819        let row_bytes = (n_embd as u64 / blk * tsize) as usize;
820        let qt = match self.ggml_type {
821            GgmlType::Q8_0 => QT_Q8_0,
822            GgmlType::Q4_K => QT_Q4_K,
823            GgmlType::Q6_K => QT_Q6_K,
824            GgmlType::Q5_K => QT_Q5_K,
825            GgmlType::Q3_K => QT_Q3_K,
826            GgmlType::IQ4_XS => QT_IQ4_XS,
827            GgmlType::IQ3_S => QT_IQ3_S,
828            GgmlType::NVFP4 => QT_NVFP4,
829            GgmlType::F32 => QT_F32,
830            // BF16 embed table (FULL_PREC research mode: qwen35-9b-hf) — device gather does the
831            // exact bits<<16 expansion; 2 B/elem resident instead of an f32-doubled table.
832            GgmlType::BF16 => QT_BF16,
833            other => panic!("embed_gather: unsupported dtype {other:?}"),
834        };
835        (qt, row_bytes)
836    }
837
838    /// Gather rows for tokens -> [T, n_embd] f32. Dequant per-row from raw bytes.
839    pub fn gather(&self, n_embd: usize, tokens: &[u32]) -> Vec<f32> {
840        let (blk, tsize) = self.ggml_type.block_and_type_size();
841        let row_bytes = (n_embd as u64 / blk * tsize) as usize;
842        let mut x = vec![0f32; tokens.len() * n_embd];
843        for (ti, &tok) in tokens.iter().enumerate() {
844            let off = tok as usize * row_bytes;
845            let row = dequant::dequantize(self.ggml_type, &self.raw[off..off + row_bytes], n_embd);
846            x[ti * n_embd..ti * n_embd + n_embd].copy_from_slice(&row);
847        }
848        x
849    }
850}
851
852pub struct Model {
853    pub cfg: ModelConfig,
854    pub embd: EmbedHost,
855    pub output_norm: GpuTensor,
856    pub output: GpuTensor,
857    pub layers: Vec<Layer>,
858}
859
860impl Model {
861    /// Load a dense (vanilla-transformer) model from GGUF. Thin wrapper over
862    /// `load_dense_from_source`. Panics if the arch has SSM/MoE layers.
863    pub fn load_dense(e: &Engine, g: &GgufFile) -> Result<Self, Box<dyn std::error::Error>> {
864        Self::load_dense_from_source(e, &GgufSource(g))
865    }
866
867    /// Load a dense-attention model from any `TensorSource` — GGUF or a safetensors HF checkpoint.
868    /// The whole loop speaks ggml names; the source maps them. The FFN is dense SwiGLU OR routed MoE
869    /// (OLMoE: dense full-attention + MoE FFN). Panics on hybrid (SSM) arches — use the hybrid path.
870    pub fn load_dense_from_source(
871        e: &Engine,
872        src: &dyn TensorSource,
873    ) -> Result<Self, Box<dyn std::error::Error>> {
874        let cfg = src.config();
875        assert!(
876            cfg.full_attention_interval == 0,
877            "model has linear-attn layers; use hybrid path"
878        );
879        // FP8-KV per-model door: OFF everywhere by default (explicit MEMRA_KV_FP8 wins).
880        // The 2026-07-12 9B "+0.7-4% scaling with depth" did NOT reproduce on the
881        // 2026-07-28 build (12k A/B: fp8 117.0/118.2 vs q8 119.3/119.2 = −1%; d1736
882        // flat; the fa-v3/f16pv/PDL stack moved underneath it). Adoption reverted by
883        // measurement — fp8-KV's remaining value is bytes (~45% smaller KV) for
884        // ctx-limited serving, not speed. Gates all green under both formats.
885        crate::KV_FP8_FORCE.store(0, std::sync::atomic::Ordering::Relaxed);
886
887        let embd = EmbedHost::from_source(src, "token_embd.weight");
888        let output_norm = GpuTensor::load_from_source(e, src, "output_norm.weight")?;
889        // tied embeddings: fall back to tok_embd if output.weight absent (OLMoE has untied output).
890        let output = if src.has("output.weight") {
891            GpuTensor::load_from_source(e, src, "output.weight")?
892        } else {
893            GpuTensor::load_from_source(e, src, "token_embd.weight")?
894        };
895
896        let mut layers = Vec::with_capacity(cfg.n_layer as usize);
897        for il in 0..cfg.n_layer {
898            let p = |s: &str| format!("blk.{il}.{s}");
899            let hy3_dense_ffn = cfg
900                .hy3
901                .as_ref()
902                .is_some_and(|h| il < h.first_k_dense_replace);
903            let ffn = if hy3_dense_ffn {
904                crate::hybrid::Ffn::Dense {
905                    ffn_gate: GpuTensor::load_from_source(e, src, &p("ffn_gate.weight"))?,
906                    ffn_up: GpuTensor::load_from_source(e, src, &p("ffn_up.weight"))?,
907                    ffn_down: GpuTensor::load_from_source(e, src, &p("ffn_down.weight"))?,
908                }
909            } else {
910                crate::hybrid::load_ffn(e, src, &cfg, il, None)?
911            };
912            layers.push(Layer {
913                attn_norm: GpuTensor::load_from_source(e, src, &p("attn_norm.weight"))?,
914                wq: GpuTensor::load_from_source(e, src, &p("attn_q.weight"))?,
915                wk: GpuTensor::load_from_source(e, src, &p("attn_k.weight"))?,
916                wv: GpuTensor::load_from_source(e, src, &p("attn_v.weight"))?,
917                wo: GpuTensor::load_from_source(e, src, &p("attn_output.weight"))?,
918                q_norm: GpuTensor::load_opt_from_source(e, src, &p("attn_q_norm.weight"))?,
919                k_norm: GpuTensor::load_opt_from_source(e, src, &p("attn_k_norm.weight"))?,
920                ffn_norm: GpuTensor::load_from_source(e, src, &p("ffn_norm.weight"))?,
921                ffn,
922            });
923        }
924        Ok(Model {
925            cfg,
926            embd,
927            output_norm,
928            output,
929            layers,
930        })
931    }
932
933    /// Largest expert block (bytes) across all MoE layers — the fixed cache-slot size (mirrors
934    /// `HybridModel::max_moe_block`). 0 for a dense (non-MoE) model.
935    pub(crate) fn max_moe_block(&self) -> usize {
936        use crate::hybrid::Ffn;
937        let mut mx = 0usize;
938        for l in &self.layers {
939            if let Ffn::Moe(m) = &l.ffn {
940                mx = mx
941                    .max(m.gate_exps.max_expert_bytes())
942                    .max(m.up_exps.max_expert_bytes())
943                    .max(m.down_exps.max_expert_bytes());
944            }
945        }
946        mx
947    }
948
949    /// Gather embedding rows into f32 [T, n_embd] (token-major) by dequantizing only the needed
950    /// rows from the host-side embedding bytes (token_embd is [n_embd, n_vocab], row per token).
951    pub fn embed_tokens(
952        &self,
953        e: &Engine,
954        tokens: &[u32],
955    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
956        let n_embd = self.cfg.n_embd as usize;
957        let x = self.embd.gather(n_embd, tokens);
958        Ok(e.htod(&x)?)
959    }
960}
961
962pub type TensorMap = HashMap<String, GpuTensor>;
963
964/// One layer's stacked 256-expert tensor, raw GGUF quant bytes held HOST-RESIDENT.
965///
966/// EDGE-1: these bytes are NEVER uploaded at load (uploading 29.75GB would OOM a 24GB GPU —
967/// this is BUG-4). Per token, only the 8 routed experts are staged H2D into a small GPU scratch.
968///
969/// ne = [in_f, out_f, n_expert]; the expert axis (ne[2]) is the slowest/highest-stride axis, so
970/// expert `e` occupies the CONTIGUOUS byte block `bytes[e*expert_stride .. (e+1)*expert_stride]`.
971///
972/// THE 3D FIX: GpuTensor::load computes `row_bytes = raw.len()/ne[1]`, which for a stacked 3D
973/// tensor ignores the 256-expert axis and is 256x too large (gate_exps -> 430080 instead of 1680).
974/// load() here uses `row_bytes = raw.len() / (out_f * n_expert)` (= 1680 gate/up, 544 down).
975/// Host byte storage for the expert blocks. Default = a pageable `Vec<u8>` (current behavior). Under
976/// MEMRA_MOE_PINNED (auto-on when MEMRA_MOE_CACHE is set), the bytes live in CUDA pinned host memory so
977/// the miss-path `memcpy_htod` is a true DMA, not a pageable bounce copy (MOE-SLRU-PLAN §C.1).
978///
979/// CAVEAT (§C.1): `alloc_pinned` uses CU_MEMHOSTALLOC_WRITECOMBINED — great for H2D-only (the expert
980/// bytes are never read by the CPU on the hot path), but write-combined memory is SLOW for CPU reads.
981/// A future CPU-VNNI cold-expert fallback must NOT read from this buffer.
982pub enum HostBuf {
983    Paged(Vec<u8>),
984    /// Pinned host memory. We keep the `PinnedHostSlice` alive (it owns the allocation; Drop frees it)
985    /// AND cache its raw base pointer + len so the hot-path `as_bytes()` needs no per-call event sync.
986    Pinned {
987        slice: std::sync::Arc<cudarc::driver::PinnedHostSlice<u8>>,
988        base: *const u8,
989        len: usize,
990    },
991    /// Alias into a shared pinned slab (ST pinned tier): `owner` keeps the slab alive; `base`/`len`
992    /// select this expert's window. Same DMA class as `Pinned`.
993    PinnedAlias {
994        owner: std::sync::Arc<HostBuf>,
995        base: *const u8,
996        len: usize,
997    },
998    /// SPILLING-PLAN §1, Tier 2 (disk): the bytes live in an mmap'd region of the GGUF file, NOT in
999    /// RAM. `map` is `MAP_SHARED`, no `MAP_POPULATE` — zero upfront copy. The first `memcpy_htod` of
1000    /// this slice page-faults → NVMe read → DMA (the demand-fault disk path). `off`/`len` select this
1001    /// expert's contiguous block within the shared file mmap. Bit-identical to `Paged`/`Pinned` —
1002    /// those copied FROM exactly these on-disk bytes, so the GEMM result is unchanged.
1003    Mmap {
1004        map: std::sync::Arc<memmap2::Mmap>,
1005        /// The same opened inode backing `map`. It must outlive the loader source so future explicit
1006        /// positioned reads cannot accidentally reopen a replaced path.
1007        file: std::sync::Arc<std::fs::File>,
1008        /// Absolute byte offset within both the whole-file mmap and `file`.
1009        off: usize,
1010        len: usize,
1011    },
1012}
1013// SAFETY: `base` is a stable pinned-host pointer owned by `slice`; the buffer is written once at load
1014// then only READ for H2D. HostExps is shared `&` across the (single per-Engine) forward, so Send/Sync
1015// mirror the underlying PinnedHostSlice (which is already Send+Sync). The `Mmap` arm holds
1016// `Arc<Mmap>` + `Arc<File>` (both Send+Sync) plus plain usize fields, so it does not weaken bounds.
1017unsafe impl Send for HostBuf {}
1018unsafe impl Sync for HostBuf {}
1019impl HostBuf {
1020    #[inline]
1021    pub fn as_bytes(&self) -> &[u8] {
1022        match self {
1023            HostBuf::Paged(v) => v.as_slice(),
1024            // SAFETY: base+len are the pinned allocation's stable extent; written once at load, then
1025            // read-only. We avoid `as_slice()` here because it would synchronize the buffer's event
1026            // on every hot-path call.
1027            HostBuf::Pinned { base, len, .. } => unsafe { std::slice::from_raw_parts(*base, *len) },
1028            HostBuf::PinnedAlias { base, len, .. } => unsafe {
1029                std::slice::from_raw_parts(*base, *len)
1030            },
1031            // Slicing the mmap is the same `&[u8]` the kernel DMAs; the read page-faults the NVMe.
1032            HostBuf::Mmap { map, off, len, .. } => &map[*off..*off + *len],
1033        }
1034    }
1035    #[inline]
1036    pub fn len(&self) -> usize {
1037        match self {
1038            HostBuf::Paged(v) => v.len(),
1039            HostBuf::Pinned { len, .. } => *len,
1040            HostBuf::PinnedAlias { len, .. } => *len,
1041            HostBuf::Mmap { len, .. } => *len,
1042        }
1043    }
1044
1045    /// Best-effort OS read-ahead for a future mmap-backed expert range. This does not touch or
1046    /// copy the bytes, so the zero-copy ownership contract is unchanged. Non-mmap buffers are
1047    /// already resident and need no advice. Kept fallible-at-the-OS but non-fatal at the call site:
1048    /// an unsupported/pressured kernel simply leaves the normal demand-fault path in place.
1049    #[inline]
1050    pub fn advise_willneed(&self, rel_off: usize, len: usize) -> bool {
1051        let HostBuf::Mmap {
1052            map,
1053            off,
1054            len: extent,
1055            ..
1056        } = self
1057        else {
1058            return false;
1059        };
1060        if len == 0 || rel_off > *extent || len > *extent - rel_off {
1061            return false;
1062        }
1063        #[cfg(unix)]
1064        {
1065            map.advise_range(memmap2::Advice::WillNeed, *off + rel_off, len)
1066                .is_ok()
1067        }
1068        #[cfg(not(unix))]
1069        {
1070            let _ = (map, off);
1071            false
1072        }
1073    }
1074
1075    #[inline]
1076    fn expert_source(&self, rel_off: usize, len: usize) -> ExpertSource<'_> {
1077        debug_assert!(rel_off <= self.len() && len <= self.len() - rel_off);
1078        match self {
1079            HostBuf::Mmap { map, file, off, .. } => {
1080                let offset = *off + rel_off;
1081                ExpertSource::Disk {
1082                    file,
1083                    offset: offset as u64,
1084                    len,
1085                    fallback: &map[offset..offset + len],
1086                    keepalive: ExpertKeepalive::Mmap(map.clone()),
1087                }
1088            }
1089            HostBuf::Pinned { slice, .. } => ExpertSource::Memory {
1090                bytes: &self.as_bytes()[rel_off..rel_off + len],
1091                keepalive: Some(ExpertKeepalive::Pinned(slice.clone())),
1092            },
1093            HostBuf::PinnedAlias { owner, .. } => ExpertSource::Memory {
1094                bytes: &self.as_bytes()[rel_off..rel_off + len],
1095                keepalive: Some(ExpertKeepalive::Buffer(owner.clone())),
1096            },
1097            HostBuf::Paged(_) => ExpertSource::Memory {
1098                bytes: &self.as_bytes()[rel_off..rel_off + len],
1099                // CUDA stages pageable input before returning from the async-copy API. Only true
1100                // pinned and mmap-backed sources need an explicit lifetime owner in the cache.
1101                keepalive: None,
1102            },
1103        }
1104    }
1105}
1106
1107/// Clonable ownership retained by asynchronous cache transfers. The payload is intentionally never
1108/// read: keeping it alive is the contract.
1109#[allow(dead_code)]
1110pub(crate) enum ExpertKeepalive {
1111    Pinned(std::sync::Arc<cudarc::driver::PinnedHostSlice<u8>>),
1112    Buffer(std::sync::Arc<HostBuf>),
1113    Mmap(std::sync::Arc<memmap2::Mmap>),
1114}
1115
1116/// Source-aware view of one expert block. The mmap fallback remains the byte oracle; retaining the
1117/// opened file enables a later explicit-read backend without changing tensor layout or numerics.
1118pub(crate) enum ExpertSource<'a> {
1119    Memory {
1120        bytes: &'a [u8],
1121        keepalive: Option<ExpertKeepalive>,
1122    },
1123    Disk {
1124        file: &'a std::sync::Arc<std::fs::File>,
1125        offset: u64,
1126        len: usize,
1127        fallback: &'a [u8],
1128        keepalive: ExpertKeepalive,
1129    },
1130}
1131
1132/// One layer's stacked 256-expert tensor, raw GGUF quant bytes held HOST-RESIDENT.
1133///
1134/// EDGE-1: these bytes are NEVER uploaded at load (uploading 29.75GB would OOM a 24GB GPU —
1135/// this is BUG-4). Per token, only the 8 routed experts are staged H2D into a small GPU scratch.
1136///
1137/// ne = [in_f, out_f, n_expert]; the expert axis (ne[2]) is the slowest/highest-stride axis, so
1138/// expert `e` occupies the CONTIGUOUS byte block `bytes[e*expert_stride .. (e+1)*expert_stride]`.
1139///
1140/// THE 3D FIX: GpuTensor::load computes `row_bytes = raw.len()/ne[1]`, which for a stacked 3D
1141/// tensor ignores the 256-expert axis and is 256x too large (gate_exps -> 430080 instead of 1680).
1142/// load() here uses `row_bytes = raw.len() / (out_f * n_expert)` (= 1680 gate/up, 544 down).
1143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1144pub struct ExpertLayout {
1145    pub offset: usize,
1146    pub len: usize,
1147    pub qtype: i32,
1148    pub row_bytes: usize,
1149}
1150
1151fn staged_expert_qtype(ty: GgmlType) -> Option<i32> {
1152    Some(match ty {
1153        GgmlType::Q8_0 => QT_Q8_0,
1154        GgmlType::Q2_K => QT_Q2_K,
1155        GgmlType::Q4_K => QT_Q4_K,
1156        GgmlType::Q6_K => QT_Q6_K,
1157        GgmlType::Q5_K => QT_Q5_K,
1158        GgmlType::Q3_K => QT_Q3_K,
1159        GgmlType::IQ4_XS => QT_IQ4_XS,
1160        GgmlType::IQ3_S => QT_IQ3_S,
1161        GgmlType::NVFP4 => QT_NVFP4,
1162        GgmlType::F32 => QT_F32,
1163        GgmlType::BF16 => QT_BF16,
1164        _ => return None,
1165    })
1166}
1167
1168fn staged_expert_row_bytes(ty: GgmlType, in_f: usize) -> Option<usize> {
1169    staged_expert_qtype(ty)?;
1170    let (block, type_size) = ty.block_and_type_size();
1171    assert_eq!(
1172        in_f as u64 % block,
1173        0,
1174        "expert row width {in_f} is not divisible by {ty:?} block {block}"
1175    );
1176    Some((in_f as u64 / block * type_size) as usize)
1177}
1178
1179fn find_expert_disk_strict(
1180    src: &dyn TensorSource,
1181    name: &str,
1182) -> Result<Option<DiskExtent>, Box<dyn std::error::Error>> {
1183    if let Some(extent) = src.find_expert_disk(name) {
1184        return Ok(Some(extent));
1185    }
1186    if src.find_expert_mmap(name).is_some() {
1187        return Err(std::io::Error::new(
1188            std::io::ErrorKind::InvalidData,
1189            format!(
1190                "expert tensor {name} exposes legacy find_expert_mmap without find_expert_disk; \
1191                 disk-backed expert loading requires a retained Arc<File>"
1192            ),
1193        )
1194        .into());
1195    }
1196    Ok(None)
1197}
1198
1199pub struct HostExps {
1200    pub bytes: HostBuf, // raw GGUF block bytes (host); per-token DMA src for the 8 routed exps
1201    /// SPILLING-PLAN §1.1: per-expert backing tier. `None` => the layer fits in one `bytes` store and
1202    /// every expert slices it (the unchanged in-RAM path). `Some` => per-expert split: the hottest
1203    /// experts are `Pinned` (Tier 1, fast async DMA), the rest `Mmap` into the GGUF (Tier 2, disk
1204    /// demand-fault). `expert_bytes(e)` resolves `tiers[e]` if present, else slices `bytes`.
1205    pub tiers: Option<Vec<HostBuf>>,
1206    pub qtype: i32,           // QT_Q6_K (gate/up) | QT_Q8_0 (down)
1207    pub in_f: usize,          // ne[0]   (gate/up = 2048, down = 512)
1208    pub out_f: usize,         // ne[1]   (gate/up = 512,  down = 2048)
1209    pub n_expert: usize,      // ne[2] = 256
1210    pub row_bytes: usize,     // raw.len()/(out_f*n_expert)  -> 1680 (gate/up) / 544 (down)
1211    pub expert_stride: usize, // raw.len()/n_expert          -> 860160 (gate/up) / 1114112 (down)
1212    /// Per-expert encoding metadata when experts in this projection do not share one dtype/layout.
1213    /// `None` preserves the existing uniform slab contract and every resident/fused fast path.
1214    /// `Some` routes through the per-expert staged/cache path, using each entry's qtype/row size.
1215    pub layouts: Option<Vec<ExpertLayout>>,
1216    /// Per-expert post-matmul macro-scale (ModelOpt NVFP4 `weight_scale_2`, one scalar per expert
1217    /// tensor). `None` => all 1.0 (GGUF experts; block scales carry everything). The MoE forward
1218    /// folds gate/up macros into the activation epilogue (gs/us) and the down macro into the
1219    /// per-expert accumulate weight.
1220    pub macros: Option<Vec<f32>>,
1221}
1222
1223impl HostExps {
1224    /// Load a stacked 3D expert tensor, keeping its quant bytes on the HOST. `e` supplies the CUDA
1225    /// context for the optional pinned allocation (§C.1). Default storage is pageable `Vec<u8>`
1226    /// (identical to the prior behavior); pinned is chosen when MEMRA_MOE_PINNED or MEMRA_MOE_CACHE is set.
1227    pub fn load(e: &Engine, g: &GgufFile, name: &str) -> Result<Self, Box<dyn std::error::Error>> {
1228        Self::load_stacked_from_source(e, &GgufSource(g), name)
1229    }
1230
1231    /// Load a STACKED 3D expert tensor (`ne=[in_f,out_f,n_expert]`) from any source. GGUF stores the
1232    /// experts this way; the source returns the same mmap bytes (`GgufSource::find` == `tensor_data`),
1233    /// so the GGUF path is byte-identical to the prior direct-`GgufFile` loader. (Safetensors stores N
1234    /// 2D tensors instead — those go through `load_from_source`, which gathers them.)
1235    /// Row-range variant for FUSED stacked tensors (gemma4 ffn_gate_up_exps: gate = rows
1236    /// [0,ff), up = [ff,2ff) per expert — llama-graph view convention). Copies only the range.
1237    pub fn load_stacked_split_from_source(
1238        e: &Engine,
1239        src: &dyn TensorSource,
1240        name: &str,
1241        row0: usize,
1242        row1: usize,
1243    ) -> Result<Self, Box<dyn std::error::Error>> {
1244        let t = src
1245            .find(name)
1246            .unwrap_or_else(|| panic!("missing exps tensor {name}"));
1247        assert_eq!(t.ne.len(), 3, "{name} is not 3D (ne={:?})", t.ne);
1248        let qtype = match t.ggml_type {
1249            GgmlType::Q8_0 => QT_Q8_0,
1250            GgmlType::Q4_K => QT_Q4_K,
1251            GgmlType::Q6_K => QT_Q6_K,
1252            GgmlType::Q5_K => QT_Q5_K,
1253            GgmlType::Q3_K => QT_Q3_K,
1254            GgmlType::IQ4_XS => QT_IQ4_XS,
1255            GgmlType::IQ3_S => QT_IQ3_S,
1256            GgmlType::NVFP4 => QT_NVFP4,
1257            GgmlType::Q4_0 => QT_Q4_0,
1258            other => panic!("exps {name} unsupported quant {other:?}"),
1259        };
1260        let raw: &[u8] = &t.bytes;
1261        let in_f = t.ne[0] as usize;
1262        let out_full = t.ne[1] as usize;
1263        let n_expert = t.ne[2] as usize;
1264        let full_stride = raw.len() / n_expert;
1265        let row_bytes = raw.len() / (out_full * n_expert);
1266        assert_eq!(full_stride, out_full * row_bytes, "{name} stride mismatch");
1267        let out_f = row1 - row0;
1268        let expert_stride = out_f * row_bytes;
1269        let mut buf = vec![0u8; n_expert * expert_stride];
1270        for ex in 0..n_expert {
1271            let s0 = ex * full_stride + row0 * row_bytes;
1272            buf[ex * expert_stride..(ex + 1) * expert_stride]
1273                .copy_from_slice(&raw[s0..s0 + expert_stride]);
1274        }
1275        let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
1276            || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
1277        let bytes = if pinned {
1278            let mut pn = unsafe { e.ctx().alloc_pinned::<u8>(buf.len())? };
1279            {
1280                let dst = pn.as_mut_slice()?;
1281                dst.copy_from_slice(&buf);
1282            }
1283            let base = pn.as_ptr()? as *const u8;
1284            let len = buf.len();
1285            HostBuf::Pinned {
1286                slice: std::sync::Arc::new(pn),
1287                base,
1288                len,
1289            }
1290        } else {
1291            HostBuf::Paged(buf)
1292        };
1293        Ok(HostExps {
1294            bytes,
1295            tiers: None,
1296            qtype,
1297            in_f,
1298            out_f,
1299            n_expert,
1300            row_bytes,
1301            expert_stride,
1302            layouts: None,
1303            macros: None,
1304        })
1305    }
1306
1307    /// Stacked per-expert macro-scale sidecar: `blk.N.ffn_{proj}_exps.scale` f32 [n_expert]
1308    /// (the qwen3.6 NVFP4 converter emits one per stacked expert tensor — compressed-tensors
1309    /// global scales, inverted to multipliers). Absent (every k-quant GGUF) => None.
1310    /// NOTE gemma4 consumes ffn_down_exps.scale through its OWN router-fold (Gemma4MoeBits) —
1311    /// its MoE forward does not read HostExps::macros, so a Some here is inert there.
1312    fn stacked_macros(src: &dyn TensorSource, name: &str) -> Option<Vec<f32>> {
1313        let stem = name.strip_suffix(".weight")?;
1314        let sv = src.find(&format!("{stem}.scale"))?;
1315        if sv.ggml_type != GgmlType::F32 { return None; }
1316        let macros: Vec<f32> = sv.bytes.chunks_exact(4)
1317            .map(|c| f32::from_le_bytes(c.try_into().unwrap())).collect();
1318        if macros.iter().all(|&m| m == 1.0) { None } else { Some(macros) }
1319    }
1320
1321    pub fn load_stacked_from_source(e: &Engine, src: &dyn TensorSource, name: &str)
1322                                    -> Result<Self, Box<dyn std::error::Error>> {
1323        let t = src.find(name).unwrap_or_else(|| panic!("missing exps tensor {name}"));
1324        assert_eq!(t.ne.len(), 3, "{name} is not a 3D stacked-expert tensor (ne={:?})", t.ne);
1325        // MMAP-BACKED SPILL TIER (Hy3 repack dir, 2026-07-09): when the source's on-disk layout IS
1326        // already the engine's expert layout (one expert-axis-slowest slab file per (layer, proj),
1327        // the transcoder's contract), back the HostExps with `HostBuf::Mmap` directly — ZERO host
1328        // copy. The default copy path below would pin/allocate the WHOLE stacked slab (80.5 GB for
1329        // Hy3-REAP50 on a 60 GB host = the M3 first-load OOM class); the mmap tier instead lets the
1330        // page cache carry the hot expert mass (RAM tier) and demand-faults the overflow from NVMe,
1331        // exactly like the proven M3 `.memra-repack` path (model.rs NVFP4 disk arm). Bit-identity:
1332        // `expert_bytes(e)` slices the same on-disk bytes the copy would have staged. The SLRU VRAM
1333        // cache stacks on top unchanged. The configured whole-map advice is applied at source open.
1334        if let Some(DiskExtent {
1335            map,
1336            file,
1337            offset,
1338            len,
1339        }) = find_expert_disk_strict(src, name)?
1340        {
1341            let off = usize::try_from(offset)
1342                .map_err(|_| format!("{name} disk offset {offset} does not fit usize"))?;
1343            let qtype = match t.ggml_type {
1344                GgmlType::Q8_0 => QT_Q8_0,
1345                GgmlType::Q4_K => QT_Q4_K,
1346                GgmlType::Q6_K => QT_Q6_K,
1347                GgmlType::Q5_K => QT_Q5_K,
1348                GgmlType::Q3_K => QT_Q3_K,
1349                GgmlType::IQ4_XS => QT_IQ4_XS,
1350                GgmlType::IQ3_S => QT_IQ3_S,
1351                GgmlType::NVFP4 => QT_NVFP4,
1352                GgmlType::Q4_0 => QT_Q4_0,
1353                other => panic!("exps {name} unsupported quant {other:?}"),
1354            };
1355            let in_f = t.ne[0] as usize;
1356            let out_f = t.ne[1] as usize;
1357            let n_expert = t.ne[2] as usize;
1358            let expert_stride = len / n_expert;
1359            let row_bytes = len / (out_f * n_expert);
1360            assert_eq!(expert_stride, out_f * row_bytes,
1361                "{name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}");
1362            assert_eq!(
1363                len,
1364                n_expert * expert_stride,
1365                "{name} mmap len != n_expert*stride"
1366            );
1367            return Ok(HostExps {
1368                bytes: HostBuf::Mmap { map, file, off, len },
1369                tiers: None, qtype, in_f, out_f, n_expert, row_bytes, expert_stride,
1370                layouts: None, macros: Self::stacked_macros(src, name),
1371            });
1372        }
1373        let raw: &[u8] = &t.bytes;
1374        // All quant types the staged-expert qmatvec can decode (dp4a-fast or Stage-A f32).
1375        let qtype = match t.ggml_type {
1376            GgmlType::Q8_0 => QT_Q8_0,
1377            GgmlType::Q4_K => QT_Q4_K,
1378            GgmlType::Q6_K => QT_Q6_K,
1379            GgmlType::Q5_K => QT_Q5_K,
1380            GgmlType::Q3_K => QT_Q3_K,
1381            GgmlType::IQ4_XS => QT_IQ4_XS,
1382            GgmlType::IQ3_S => QT_IQ3_S,
1383            GgmlType::NVFP4 => QT_NVFP4,
1384            GgmlType::Q4_0 => QT_Q4_0,
1385            other => panic!("exps {name} unsupported quant {other:?}"),
1386        };
1387        let in_f = t.ne[0] as usize;
1388        let out_f = t.ne[1] as usize;
1389        let n_expert = t.ne[2] as usize;
1390        // VERIFIED: gate/up Q6_K total/256 = 860160; row = total/(512*256) = 1680.
1391        //           down  Q8_0 total/256 = 1114112; row = total/(2048*256) = 544.
1392        let expert_stride = raw.len() / n_expert;
1393        let row_bytes = raw.len() / (out_f * n_expert);
1394        // sanity: expert_stride must equal out_f * row_bytes exactly (catches a dim mixup)
1395        assert_eq!(
1396            expert_stride,
1397            out_f * row_bytes,
1398            "{name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}"
1399        );
1400
1401        let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
1402            || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
1403        let bytes = if pinned {
1404            // alloc pinned host memory, copy the GGUF block bytes in once, cache the base pointer.
1405            let mut p = unsafe { e.ctx().alloc_pinned::<u8>(raw.len())? };
1406            {
1407                let dst = p.as_mut_slice()?;
1408                dst.copy_from_slice(raw);
1409            }
1410            let base = p.as_ptr()? as *const u8; // syncs once here at load; stable afterward
1411            let len = raw.len();
1412            HostBuf::Pinned {
1413                slice: std::sync::Arc::new(p),
1414                base,
1415                len,
1416            }
1417        } else {
1418            HostBuf::Paged(raw.to_vec())
1419        };
1420        Ok(HostExps { bytes, tiers: None, qtype, in_f, out_f, n_expert, row_bytes,
1421                      expert_stride, layouts: None, macros: Self::stacked_macros(src, name) })
1422    }
1423
1424    /// SPILLING-PLAN §1.1, §2 step 4: load a stacked 3D expert tensor with a PER-EXPERT tier split.
1425    /// Under `MEMRA_SPILL_DISK`, the hottest experts (greedy in expert order, until the shared pinned
1426    /// budget in `ctx` is exhausted) get `HostBuf::Pinned` (Tier 1, fast async DMA); every remaining
1427    /// expert is `HostBuf::Mmap` into the GGUF (Tier 2, demand-faulted from disk on first H2D). The
1428    /// resulting bytes are bit-identical to the in-RAM path either way — `qmatvec_view` is untouched.
1429    ///
1430    /// `ctx.file_map` is ONE shared `MAP_SHARED` mmap of the whole GGUF (`Arc`-cloned per spilled
1431    /// expert), so the 120 expert tensors of a 40-layer MoE never open the file more than once.
1432    pub fn load_tiered(
1433        e: &Engine,
1434        g: &GgufFile,
1435        name: &str,
1436        ctx: &mut crate::spill::SpillCtx,
1437    ) -> Result<Self, Box<dyn std::error::Error>> {
1438        let t = g
1439            .find(name)
1440            .unwrap_or_else(|| panic!("missing exps tensor {name}"));
1441        assert_eq!(
1442            t.ne.len(),
1443            3,
1444            "{name} is not a 3D stacked-expert tensor (ne={:?})",
1445            t.ne
1446        );
1447        let raw = g.tensor_data(t);
1448        let qtype = match t.ggml_type {
1449            GgmlType::Q8_0 => QT_Q8_0,
1450            GgmlType::Q4_K => QT_Q4_K,
1451            GgmlType::Q6_K => QT_Q6_K,
1452            GgmlType::Q5_K => QT_Q5_K,
1453            GgmlType::Q3_K => QT_Q3_K,
1454            GgmlType::IQ4_XS => QT_IQ4_XS,
1455            GgmlType::IQ3_S => QT_IQ3_S,
1456            GgmlType::NVFP4 => QT_NVFP4,
1457            GgmlType::Q4_0 => QT_Q4_0,
1458            other => panic!("exps {name} unsupported quant {other:?}"),
1459        };
1460        let in_f = t.ne[0] as usize;
1461        let out_f = t.ne[1] as usize;
1462        let n_expert = t.ne[2] as usize;
1463        let expert_stride = raw.len() / n_expert;
1464        let row_bytes = raw.len() / (out_f * n_expert);
1465        assert_eq!(
1466            expert_stride,
1467            out_f * row_bytes,
1468            "{name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}"
1469        );
1470
1471        // Absolute file offset of this tensor's data (start of expert 0); each expert is the next
1472        // `expert_stride` bytes. The `Mmap` arm slices `ctx.file_map` at these offsets.
1473        let (file_start, _file_end) = g.tensor_file_range(t);
1474
1475        // Per-expert tier decision under the shared running budget. `bytes` keeps a 0-byte sentinel
1476        // (`Paged(empty)`) since every read now goes through `tiers`.
1477        let mut tiers = Vec::with_capacity(n_expert);
1478        for ex in 0..n_expert {
1479            let blk = &raw[ex * expert_stride..(ex + 1) * expert_stride];
1480            let file_off = file_start + ex * expert_stride;
1481            tiers.push(crate::spill::place_expert(ctx, e, blk, file_off)?);
1482        }
1483        Ok(HostExps {
1484            bytes: HostBuf::Paged(Vec::new()), // unused when `tiers` is Some
1485            tiers: Some(tiers),
1486            qtype, in_f, out_f, n_expert, row_bytes, expert_stride, layouts: None,
1487            macros: Self::stacked_macros(&GgufSource(g), name),
1488        })
1489    }
1490
1491    /// MoE expert GATHER from a `TensorSource` (the safetensors path; ST-MOE-PLAN §1.3). GGUF stacks
1492    /// all experts into ONE 3D tensor; HF stores them as N separate 2D tensors
1493    /// `model.layers.{il}.mlp.experts.{e}.{gate,up,down}_proj.weight`. `find` returns `None` for the
1494    /// ggml `*_exps` name on purpose, so the experts are gathered out-of-band here.
1495    ///
1496    /// PATH A (load-time only, no quantize): each HF 2D expert tensor is dequantized to f32 and the
1497    /// per-expert blocks are concatenated expert-axis-slowest into ONE contiguous buffer — exactly the
1498    /// layout `expert_bytes(e)` slices and the staged `qmatvec_view` (qtype=QT_F32) reads. The same
1499    /// `expert_stride == out_f*row_bytes` invariant as the GGUF path is asserted at the end.
1500    ///
1501    /// `ggml_exps_name` is `blk.{il}.ffn_{gate,up,down}_exps.weight`; it is split to recover `il` and
1502    /// the proj. `n_expert` comes from `cfg.moe`. The HF per-expert literal `mlp.experts.{e}.{p}_proj`
1503    /// is the qwen3moe / olmoe layout (a future arch with `block_sparse_moe.experts.*` would need a
1504    /// branch in `hf_expert_name`).
1505    pub fn load_from_source(
1506        e: &Engine,
1507        src: &dyn TensorSource,
1508        ggml_exps_name: &str,
1509        n_expert: usize,
1510    ) -> Result<Self, Box<dyn std::error::Error>> {
1511        // Recover il + proj from `blk.{il}.ffn_{gate,up,down}_exps.weight`.
1512        let rest = ggml_exps_name
1513            .strip_prefix("blk.")
1514            .unwrap_or_else(|| panic!("not a blk.* name: {ggml_exps_name}"));
1515        let (il_s, suffix) = rest.split_once('.').unwrap();
1516        let il: u32 = il_s.parse().unwrap();
1517        let proj = match suffix {
1518            "ffn_gate_exps.weight" => "gate",
1519            "ffn_up_exps.weight" => "up",
1520            "ffn_down_exps.weight" => "down",
1521            other => panic!("not a *_exps suffix: {other}"),
1522        };
1523
1524        // A mixed-precision safetensors/repack source exposes experts as separate 2D tensors.
1525        // Detect a dtype/layout change before the uniform gather paths normalize the whole layer
1526        // to one encoding. Uniform checkpoints take the unchanged optimized path below.
1527        let mut signatures = Vec::with_capacity(n_expert);
1528        let active = src.active_experts(il);
1529        for ex in 0..n_expert {
1530            if active.is_some_and(|mask| !mask[ex]) {
1531                signatures.push((i32::MIN, 0));
1532                continue;
1533            }
1534            let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
1535            if let Some(nv) = src.find_nvfp4_native(&name) {
1536                signatures.push((QT_NVFP4, nv.in_f / 64 * 36));
1537            } else {
1538                let v = src
1539                    .find(&name)
1540                    .unwrap_or_else(|| panic!("missing expert tensor {name}"));
1541                let in_f = v.ne[0] as usize;
1542                signatures.push(match staged_expert_row_bytes(v.ggml_type, in_f) {
1543                    Some(row_bytes) => (staged_expert_qtype(v.ggml_type).unwrap(), row_bytes),
1544                    None => (QT_F32, in_f * 4),
1545                });
1546            }
1547        }
1548        let mixed_layout = signatures.windows(2).any(|pair| pair[0] != pair[1]);
1549        if src.preserve_expert_encodings() && !mixed_layout {
1550            if let Some(uniform) = Self::load_uniform_mmap_from_source(src, il, proj, n_expert)? {
1551                return Ok(uniform);
1552            }
1553        }
1554        if src.preserve_expert_encodings() || mixed_layout {
1555            return Self::load_mixed_from_source(src, il, proj, n_expert);
1556        }
1557
1558        // PATH B (NVFP4-NATIVE GATHER, 2026-07-05): when the source exposes the experts as packed
1559        // ModelOpt/Reza NVFP4 (find_nvfp4_native), keep them QUANTIZED — repack each expert's
1560        // modelopt bytes to the GGUF 36B-block layout the staged qmatvec decodes, and concatenate.
1561        // No f32 blow-up: a 129GB checkpoint gathers to ~the same bytes instead of ~8x (which is
1562        // what makes MiniMax-M3 REAP50 loadable on a 60GB-RAM host at all, with spill on top).
1563        // Per-expert `weight_scale_2` macros go to `macros` (folded post-matmul by the MoE forward).
1564        {
1565            let name0 = format!("blk.{il}.ffn_{proj}_exps.0.weight");
1566            if let Some(nv0) = src.find_nvfp4_native(&name0) {
1567                let (in_f, out_f) = (nv0.in_f, nv0.out_f);
1568                let row_bytes = in_f / 64 * 36;
1569                let expert_stride = out_f * row_bytes;
1570                // ST DISK TIER (2026-07-06, the MiniMax OOM fix): when the total expert bytes
1571                // exceed host RAM (M3 REAP50 = 122GB repacked on a 60GB host, first-load host-OOM
1572                // at layer ~24), repack each layer ONCE into an on-disk cache file next to the
1573                // checkpoint and mmap it (HostBuf::Mmap, MAP_SHARED no-populate — the same tier-2
1574                // mechanism the GGUF spill path uses). Reloads hit the cache (size-checked), pay
1575                // zero repack. MEMRA_ST_REPACK_DISK=0 forces the old in-RAM gather.
1576                let disk = std::env::var("MEMRA_ST_REPACK_DISK")
1577                    .map(|v| v != "0")
1578                    .unwrap_or(true)
1579                    && src.st_dir().is_some();
1580                let cache_path = src.st_dir().map(|d| {
1581                    let cd = d.join(".memra-repack");
1582                    let _ = std::fs::create_dir_all(&cd);
1583                    cd.join(format!("blk{il}-{proj}-{n_expert}x{out_f}x{in_f}.nvfp4"))
1584                });
1585                let total = n_expert * expert_stride;
1586                let mut macros = vec![1.0f32; n_expert];
1587                let read_macros = |macros: &mut Vec<f32>| {
1588                    for ex in 0..n_expert {
1589                        let stem = format!("blk.{il}.ffn_{proj}_exps.{ex}");
1590                        if let Some(sv) = src.find(&format!("{stem}.scale")) {
1591                            macros[ex] = f32::from_le_bytes(sv.bytes[..4].try_into().unwrap());
1592                        }
1593                    }
1594                };
1595                let bytes = if disk {
1596                    let cp = cache_path.as_ref().unwrap();
1597                    let fresh = std::fs::metadata(cp)
1598                        .map(|m| m.len() as usize == total)
1599                        .unwrap_or(false);
1600                    if !fresh {
1601                        // stream one expert at a time to disk — peak RAM = one expert (~8MB)
1602                        use std::io::Write;
1603                        let mut f = std::io::BufWriter::new(std::fs::File::create(cp)?);
1604                        for ex in 0..n_expert {
1605                            let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
1606                            let nv = src.find_nvfp4_native(&name).unwrap_or_else(|| {
1607                                panic!("expert {name} lost NVFP4-native mid-gather")
1608                            });
1609                            assert_eq!(
1610                                (nv.in_f, nv.out_f),
1611                                (in_f, out_f),
1612                                "expert {ex} dims ({},{}) != expert 0 ({in_f},{out_f})",
1613                                nv.in_f,
1614                                nv.out_f
1615                            );
1616                            f.write_all(&memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
1617                                nv.wbytes, nv.wscale, out_f, in_f,
1618                            ))?;
1619                        }
1620                        f.flush()?;
1621                    }
1622                    read_macros(&mut macros);
1623                    let file = std::sync::Arc::new(std::fs::File::open(cp)?);
1624                    let map = unsafe { memmap2::Mmap::map(file.as_ref())? };
1625                    assert_eq!(map.len(), total, "repack cache {cp:?} size mismatch");
1626                    // Default random preserves the original policy; normal lets Linux readahead
1627                    // within each multi-megabyte expert on the spill-bound path.
1628                    let _ = memra_gguf::source::apply_expert_mmap_advice(&map);
1629                    let map = std::sync::Arc::new(map);
1630                    // ST PINNED TIER (2026-07-07, the M3 1.5-tok/s lever): mmap-only backing makes
1631                    // every SLRU miss a page-cache (or NVMe) synchronous read into the H2D copy.
1632                    // Pin as many experts as the live budget allows (same MemBudget probe + 0.6
1633                    // MemAvailable cap as the GGUF spill tier) — pinned pages upload via true
1634                    // async DMA at full PCIe. Budget is GLOBAL across layers (first-come: earlier
1635                    // layers pin first; routing is roughly uniform so early-layer bias is benign).
1636                    // MEMRA_ST_PINNED=0 disables (pure-mmap, the 2026-07-06 behavior).
1637                    // DEFAULT OFF (2026-07-07 measured): with a 122GB expert set on 60GB RAM,
1638                    // pinning 26GB EVICTED the page cache backing the mmap tier — every unpinned
1639                    // expert faulted cold from NVMe and gen fell 1.5 -> 0.05 tok/s (30x WORSE).
1640                    // Pinning only pays when (total - pinned) fits page cache; here it never can.
1641                    // MEMRA_ST_PINNED=1 opt-in for fits-in-RAM checkpoints (e.g. REAP-heavier cuts).
1642                    let tiers = if std::env::var("MEMRA_ST_PINNED")
1643                        .map(|v| v == "1")
1644                        .unwrap_or(false)
1645                    {
1646                        static PIN_BUDGET: std::sync::OnceLock<std::sync::Mutex<usize>> =
1647                            std::sync::OnceLock::new();
1648                        let budget = PIN_BUDGET.get_or_init(|| {
1649                            let b = crate::spill::MemBudget::probe(e)
1650                                .map(|b| b.free_pinnable_ram)
1651                                .unwrap_or(0);
1652                            eprintln!("[st-spill] pinned budget {:.1} GB", b as f64 / 1e9);
1653                            std::sync::Mutex::new(b)
1654                        });
1655                        let mut rem = budget.lock().unwrap();
1656                        // ONE pinned slab per file prefix (n_pin experts contiguous): 1 alloc +
1657                        // 1 bulk copy instead of n_pin small allocs (per-expert cudaHostAllocs
1658                        // stalled the 122GB M3 load >10min).
1659                        let n_pin = (*rem / expert_stride).min(n_expert);
1660                        if n_pin == 0 {
1661                            None
1662                        } else {
1663                            let slab_len = n_pin * expert_stride;
1664                            let mut pn = unsafe { e.ctx().alloc_pinned::<u8>(slab_len)? };
1665                            {
1666                                let dst = pn.as_mut_slice()?;
1667                                dst.copy_from_slice(&map[..slab_len]);
1668                            }
1669                            let base = pn.as_ptr()? as *const u8;
1670                            *rem -= slab_len;
1671                            let slab = std::sync::Arc::new(HostBuf::Pinned {
1672                                slice: std::sync::Arc::new(pn),
1673                                base,
1674                                len: slab_len,
1675                            });
1676                            let mut tiers: Vec<HostBuf> = Vec::with_capacity(n_expert);
1677                            for ex in 0..n_expert {
1678                                let off = ex * expert_stride;
1679                                if ex < n_pin {
1680                                    tiers.push(HostBuf::PinnedAlias {
1681                                        owner: slab.clone(),
1682                                        base: unsafe { base.add(off) },
1683                                        len: expert_stride,
1684                                    });
1685                                } else {
1686                                    tiers.push(HostBuf::Mmap {
1687                                        map: map.clone(),
1688                                        file: file.clone(),
1689                                        off,
1690                                        len: expert_stride,
1691                                    });
1692                                }
1693                            }
1694                            Some(tiers)
1695                        }
1696                    } else {
1697                        None
1698                    };
1699                    if let Some(tiers) = tiers {
1700                        let all_one = macros.iter().all(|&m| m == 1.0);
1701                        return Ok(HostExps {
1702                            bytes: HostBuf::Mmap {
1703                                map,
1704                                file,
1705                                off: 0,
1706                                len: total,
1707                            },
1708                            tiers: Some(tiers),
1709                            qtype: QT_NVFP4,
1710                            in_f,
1711                            out_f,
1712                            n_expert,
1713                            row_bytes,
1714                            expert_stride,
1715                            layouts: None,
1716                            macros: if all_one { None } else { Some(macros) },
1717                        });
1718                    }
1719                    HostBuf::Mmap {
1720                        map,
1721                        file,
1722                        off: 0,
1723                        len: total,
1724                    }
1725                } else {
1726                    let mut buf: Vec<u8> = Vec::with_capacity(total);
1727                    for ex in 0..n_expert {
1728                        let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
1729                        let nv = src.find_nvfp4_native(&name).unwrap_or_else(|| {
1730                            panic!("expert {name} lost NVFP4-native mid-gather")
1731                        });
1732                        assert_eq!(
1733                            (nv.in_f, nv.out_f),
1734                            (in_f, out_f),
1735                            "expert {ex} dims ({},{}) != expert 0 ({in_f},{out_f})",
1736                            nv.in_f,
1737                            nv.out_f
1738                        );
1739                        buf.extend_from_slice(&memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
1740                            nv.wbytes, nv.wscale, out_f, in_f,
1741                        ));
1742                    }
1743                    assert_eq!(buf.len(), total);
1744                    read_macros(&mut macros);
1745                    let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
1746                        || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
1747                    if pinned {
1748                        let mut p = unsafe { e.ctx().alloc_pinned::<u8>(buf.len())? };
1749                        {
1750                            let dst = p.as_mut_slice()?;
1751                            dst.copy_from_slice(&buf);
1752                        }
1753                        let base = p.as_ptr()? as *const u8;
1754                        let len = buf.len();
1755                        HostBuf::Pinned {
1756                            slice: std::sync::Arc::new(p),
1757                            base,
1758                            len,
1759                        }
1760                    } else {
1761                        HostBuf::Paged(buf)
1762                    }
1763                };
1764                let all_one = macros.iter().all(|&m| m == 1.0);
1765                return Ok(HostExps {
1766                    bytes,
1767                    tiers: None,
1768                    qtype: QT_NVFP4,
1769                    in_f,
1770                    out_f,
1771                    n_expert,
1772                    row_bytes,
1773                    expert_stride,
1774                    layouts: None,
1775                    macros: if all_one { None } else { Some(macros) },
1776                });
1777            }
1778        }
1779
1780        // expert 0 fixes (in_f, out_f); every later expert must match (catches a layer/arch mixup).
1781        let mut buf: Vec<u8> = Vec::new();
1782        let mut in_f = 0usize;
1783        let mut out_f = 0usize;
1784        for ex in 0..n_expert {
1785            // Per-expert ggml name; the source maps it to the HF expert tensor (ST-MOE-PLAN §1.3).
1786            let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
1787            let v = src
1788                .find(&name)
1789                .unwrap_or_else(|| panic!("missing expert tensor {name}"));
1790            assert_eq!(v.ne.len(), 2, "expert {name} is not 2D (ne={:?})", v.ne);
1791            let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
1792            if ex == 0 {
1793                in_f = cur_in;
1794                out_f = cur_out;
1795            } else {
1796                assert_eq!(
1797                    (cur_in, cur_out),
1798                    (in_f, out_f),
1799                    "expert {ex} dims {:?} != expert 0 [{in_f},{out_f}]",
1800                    (cur_in, cur_out)
1801                );
1802            }
1803            // PATH A: dequant the 2D expert (F32/F16/BF16) to f32, append its bytes verbatim. The
1804            // dequantized [out_f, in_f] row-major f32 block is exactly one expert_stride slow→fast.
1805            let n = cur_in * cur_out;
1806            let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n);
1807            buf.reserve(n * 4);
1808            for f in &f32v {
1809                buf.extend_from_slice(&f.to_le_bytes());
1810            }
1811        }
1812        let row_bytes = in_f * 4; // one out-row = in_f contiguous f32s
1813        let expert_stride = out_f * row_bytes;
1814        assert_eq!(
1815            buf.len(),
1816            n_expert * expert_stride,
1817            "{ggml_exps_name} gather size {} != n_expert*stride {}",
1818            buf.len(),
1819            n_expert * expert_stride
1820        );
1821        // Hold to the identical invariant as the GGUF path (ST-MOE-PLAN §1.3 step 4).
1822        assert_eq!(expert_stride, out_f * row_bytes,
1823            "{ggml_exps_name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}");
1824
1825        // Same pinned-vs-paged choice as the GGUF loader (the bytes are H2D-only on the hot path).
1826        let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
1827            || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
1828        let bytes = if pinned {
1829            let mut p = unsafe { e.ctx().alloc_pinned::<u8>(buf.len())? };
1830            {
1831                let dst = p.as_mut_slice()?;
1832                dst.copy_from_slice(&buf);
1833            }
1834            let base = p.as_ptr()? as *const u8;
1835            let len = buf.len();
1836            HostBuf::Pinned {
1837                slice: std::sync::Arc::new(p),
1838                base,
1839                len,
1840            }
1841        } else {
1842            HostBuf::Paged(buf)
1843        };
1844        Ok(HostExps {
1845            bytes,
1846            tiers: None,
1847            qtype: QT_F32,
1848            in_f,
1849            out_f,
1850            n_expert,
1851            row_bytes,
1852            expert_stride,
1853            layouts: None,
1854            macros: None,
1855        })
1856    }
1857
1858    /// Coalesce a uniform v2 overlay back into the existing stacked-slab contract without copying.
1859    /// The artifact stores one record per original expert for coverage validation, but a full-bank
1860    /// uniform arm writes those records contiguously into one file. Keeping `layouts=None` preserves
1861    /// the uniform fused kernels while `HostBuf::Mmap` keeps the >RAM artifact zero-copy.
1862    fn load_uniform_mmap_from_source(
1863        src: &dyn TensorSource,
1864        il: u32,
1865        proj: &str,
1866        n_expert: usize,
1867    ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
1868        if src
1869            .active_experts(il)
1870            .is_some_and(|mask| mask.iter().any(|&active| !active))
1871        {
1872            return Ok(None);
1873        }
1874        let mut first_map = None;
1875        let mut first_file = None;
1876        let mut base_offset = 0u64;
1877        let mut expert_stride = 0usize;
1878        let mut in_f = 0usize;
1879        let mut out_f = 0usize;
1880        let mut qtype = 0i32;
1881        let mut row_bytes = 0usize;
1882        let mut macros = vec![1.0f32; n_expert];
1883        for ex in 0..n_expert {
1884            let stem = format!("blk.{il}.ffn_{proj}_exps.{ex}");
1885            let name = format!("{stem}.weight");
1886            let Some(DiskExtent {
1887                map,
1888                file,
1889                offset,
1890                len,
1891            }) = find_expert_disk_strict(src, &name)?
1892            else {
1893                return Ok(None);
1894            };
1895            let Some(v) = src.find(&name) else {
1896                return Ok(None);
1897            };
1898            if v.ne.len() != 2 {
1899                return Ok(None);
1900            }
1901            let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
1902            let Some(cur_row_bytes) = staged_expert_row_bytes(v.ggml_type, cur_in) else {
1903                return Ok(None);
1904            };
1905            let cur_qtype = staged_expert_qtype(v.ggml_type).unwrap();
1906            if ex == 0 {
1907                base_offset = offset;
1908                expert_stride = len;
1909                in_f = cur_in;
1910                out_f = cur_out;
1911                qtype = cur_qtype;
1912                row_bytes = cur_row_bytes;
1913                first_map = Some(map);
1914                first_file = Some(file);
1915            } else if !std::sync::Arc::ptr_eq(first_map.as_ref().unwrap(), &map)
1916                || !std::sync::Arc::ptr_eq(first_file.as_ref().unwrap(), &file)
1917                || offset != base_offset + (ex * expert_stride) as u64
1918                || len != expert_stride
1919                || (cur_in, cur_out, cur_qtype, cur_row_bytes) != (in_f, out_f, qtype, row_bytes)
1920            {
1921                return Ok(None);
1922            }
1923            if let Some(scale) = src.find(&format!("{stem}.scale")) {
1924                macros[ex] = f32::from_le_bytes(scale.bytes[..4].try_into().unwrap());
1925            }
1926        }
1927        assert_eq!(expert_stride, out_f * row_bytes);
1928        let total = n_expert * expert_stride;
1929        let off = usize::try_from(base_offset)
1930            .map_err(|_| format!("uniform expert disk offset {base_offset} does not fit usize"))?;
1931        let all_one = macros.iter().all(|&scale| scale == 1.0);
1932        Ok(Some(HostExps {
1933            bytes: HostBuf::Mmap {
1934                map: first_map.unwrap(),
1935                file: first_file.unwrap(),
1936                off,
1937                len: total,
1938            },
1939            tiers: None,
1940            qtype,
1941            in_f,
1942            out_f,
1943            n_expert,
1944            row_bytes,
1945            expert_stride,
1946            layouts: None,
1947            macros: if all_one { None } else { Some(macros) },
1948        }))
1949    }
1950
1951    fn load_mixed_from_source(
1952        src: &dyn TensorSource,
1953        il: u32,
1954        proj: &str,
1955        n_expert: usize,
1956    ) -> Result<Self, Box<dyn std::error::Error>> {
1957        let mut tiers = Vec::with_capacity(n_expert);
1958        let mut layouts = Vec::with_capacity(n_expert);
1959        let mut macros = vec![1.0f32; n_expert];
1960        let mut in_f = 0usize;
1961        let mut out_f = 0usize;
1962        let active = src.active_experts(il);
1963        let mut first_active = None;
1964
1965        for ex in 0..n_expert {
1966            if active.is_some_and(|mask| !mask[ex]) {
1967                layouts.push(ExpertLayout {
1968                    offset: 0,
1969                    len: 0,
1970                    qtype: QT_F32,
1971                    row_bytes: 0,
1972                });
1973                tiers.push(HostBuf::Paged(Vec::new()));
1974                continue;
1975            }
1976            let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
1977            let stem = format!("blk.{il}.ffn_{proj}_exps.{ex}");
1978            if let Some(scale) = src.find(&format!("{stem}.scale")) {
1979                macros[ex] = f32::from_le_bytes(scale.bytes[..4].try_into().unwrap());
1980            }
1981            let (host, byte_len, qtype, row_bytes, cur_in, cur_out) = if let Some(DiskExtent {
1982                map,
1983                file,
1984                offset,
1985                len,
1986            }) =
1987                find_expert_disk_strict(src, &name)?
1988            {
1989                let v = src
1990                    .find(&name)
1991                    .unwrap_or_else(|| panic!("missing expert tensor {name}"));
1992                assert_eq!(v.ne.len(), 2, "expert {name} is not 2D (ne={:?})", v.ne);
1993                let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
1994                let row_bytes = staged_expert_row_bytes(v.ggml_type, cur_in).ok_or_else(|| {
1995                    format!("mmap expert {name} has unsupported qtype {:?}", v.ggml_type)
1996                })?;
1997                let off = usize::try_from(offset).map_err(|_| {
1998                    format!("expert {name} disk offset {offset} does not fit usize")
1999                })?;
2000                (
2001                    HostBuf::Mmap {
2002                        map,
2003                        file,
2004                        off,
2005                        len,
2006                    },
2007                    len,
2008                    staged_expert_qtype(v.ggml_type).unwrap(),
2009                    row_bytes,
2010                    cur_in,
2011                    cur_out,
2012                )
2013            } else if let Some(nv) = src.find_nvfp4_native(&name) {
2014                let bytes = memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
2015                    nv.wbytes, nv.wscale, nv.out_f, nv.in_f,
2016                );
2017                let row_bytes = nv.in_f / 64 * 36;
2018                let byte_len = bytes.len();
2019                (
2020                    HostBuf::Paged(bytes),
2021                    byte_len,
2022                    QT_NVFP4,
2023                    row_bytes,
2024                    nv.in_f,
2025                    nv.out_f,
2026                )
2027            } else {
2028                let v = src
2029                    .find(&name)
2030                    .unwrap_or_else(|| panic!("missing expert tensor {name}"));
2031                assert_eq!(v.ne.len(), 2, "expert {name} is not 2D (ne={:?})", v.ne);
2032                let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
2033                if let Some(row_bytes) = staged_expert_row_bytes(v.ggml_type, cur_in) {
2034                    let bytes = v.bytes.into_owned();
2035                    let byte_len = bytes.len();
2036                    (
2037                        HostBuf::Paged(bytes),
2038                        byte_len,
2039                        staged_expert_qtype(v.ggml_type).unwrap(),
2040                        row_bytes,
2041                        cur_in,
2042                        cur_out,
2043                    )
2044                } else {
2045                    let f32v = dequant::dequantize(v.ggml_type, &v.bytes, cur_in * cur_out);
2046                    let mut bytes = Vec::with_capacity(f32v.len() * 4);
2047                    for f in f32v {
2048                        bytes.extend_from_slice(&f.to_le_bytes());
2049                    }
2050                    let byte_len = bytes.len();
2051                    (
2052                        HostBuf::Paged(bytes),
2053                        byte_len,
2054                        QT_F32,
2055                        cur_in * 4,
2056                        cur_in,
2057                        cur_out,
2058                    )
2059                }
2060            };
2061
2062            if first_active.is_none() {
2063                in_f = cur_in;
2064                out_f = cur_out;
2065                first_active = Some(ex);
2066            } else {
2067                assert_eq!(
2068                    (cur_in, cur_out),
2069                    (in_f, out_f),
2070                    "expert {ex} dims ({cur_in},{cur_out}) != first active expert ({in_f},{out_f})"
2071                );
2072            }
2073            assert_eq!(
2074                byte_len,
2075                cur_out * row_bytes,
2076                "expert {name} bytes {byte_len} != out_f*row_bytes {}",
2077                cur_out * row_bytes
2078            );
2079            layouts.push(ExpertLayout {
2080                offset: 0,
2081                len: byte_len,
2082                qtype,
2083                row_bytes,
2084            });
2085            tiers.push(host);
2086        }
2087
2088        let first = layouts[*first_active
2089            .as_ref()
2090            .expect("expert mask pruned every expert")];
2091        let expert_stride = layouts.iter().map(|layout| layout.len).max().unwrap_or(0);
2092        let all_one = macros.iter().all(|&scale| scale == 1.0);
2093        Ok(HostExps {
2094            bytes: HostBuf::Paged(Vec::new()),
2095            tiers: Some(tiers),
2096            qtype: first.qtype,
2097            in_f,
2098            out_f,
2099            n_expert,
2100            row_bytes: first.row_bytes,
2101            expert_stride,
2102            layouts: Some(layouts),
2103            macros: if all_one { None } else { Some(macros) },
2104        })
2105    }
2106
2107    /// Host byte slice for expert `e` (the H2D DMA source). Contiguous block, offset honored.
2108    /// Resolves the per-expert tier when spilling is active (`tiers` Some), else slices the single
2109    /// Per-expert post-matmul macro-scale (1.0 when absent).
2110    #[inline]
2111    pub fn macro_scale(&self, e: usize) -> f32 {
2112        self.macros.as_ref().map(|m| m[e]).unwrap_or(1.0)
2113    }
2114
2115    #[inline]
2116    pub fn is_uniform_layout(&self) -> bool {
2117        self.layouts.is_none()
2118    }
2119
2120    #[inline]
2121    pub fn expert_layout(&self, e: usize) -> ExpertLayout {
2122        debug_assert!(
2123            e < self.n_expert,
2124            "expert index {e} >= n_expert {}",
2125            self.n_expert
2126        );
2127        self.layouts
2128            .as_ref()
2129            .map(|layouts| layouts[e])
2130            .unwrap_or(ExpertLayout {
2131                offset: e * self.expert_stride,
2132                len: self.expert_stride,
2133                qtype: self.qtype,
2134                row_bytes: self.row_bytes,
2135            })
2136    }
2137
2138    #[inline]
2139    pub fn max_expert_bytes(&self) -> usize {
2140        self.layouts
2141            .as_ref()
2142            .and_then(|layouts| layouts.iter().map(|layout| layout.len).max())
2143            .unwrap_or(self.expert_stride)
2144    }
2145
2146    /// backing store (unchanged in-RAM path). Each `tiers[e]` is exactly one expert's stride.
2147    #[inline]
2148    pub fn expert_bytes(&self, e: usize) -> &[u8] {
2149        let layout = self.expert_layout(e);
2150        match &self.tiers {
2151            Some(tiers) => {
2152                debug_assert_eq!(tiers[e].len(), layout.len);
2153                tiers[e].as_bytes()
2154            }
2155            None => &self.bytes.as_bytes()[layout.offset..layout.offset + layout.len],
2156        }
2157    }
2158
2159    /// Source-aware twin of `expert_bytes`. Per-expert tiers already point at one exact block, while
2160    /// a uniform slab needs the expert layout offset added to its base. Keeping those cases separate
2161    /// prevents expert `e` from being offset twice when a tier vector is present.
2162    #[inline]
2163    pub(crate) fn expert_source(&self, e: usize) -> ExpertSource<'_> {
2164        let layout = self.expert_layout(e);
2165        match &self.tiers {
2166            Some(tiers) => tiers[e].expert_source(0, layout.len),
2167            None => self.bytes.expert_source(layout.offset, layout.len),
2168        }
2169    }
2170
2171    /// Hint that expert `e` will be staged soon. Uniform slabs advise only this expert's window;
2172    /// mixed/pruned layouts advise the selected per-expert mmap. Returns false for resident or
2173    /// empty buffers and on unsupported kernels; callers always retain the demand-fault fallback.
2174    #[inline]
2175    pub fn prefetch_expert_pages(&self, e: usize) -> bool {
2176        let layout = self.expert_layout(e);
2177        match &self.tiers {
2178            Some(tiers) => tiers[e].advise_willneed(0, layout.len),
2179            None => self.bytes.advise_willneed(layout.offset, layout.len),
2180        }
2181    }
2182}
2183
2184#[cfg(test)]
2185mod tests {
2186    use super::{
2187        repack_nvfp4_split, unpack_nvfp4_split, ExpertKeepalive, ExpertSource, HostBuf, HostExps,
2188        QT_BF16, QT_NVFP4, QT_Q2_K, QT_Q4_K,
2189    };
2190    use memra_gguf::nvfp4_repack::{repack_modelopt_to_gguf, repack_modelopt_to_split};
2191    use memra_gguf::source::{DiskExtent, TensorSource, TensorView};
2192    use memra_gguf::{config::ModelConfig, GgmlType};
2193    use std::borrow::Cow;
2194
2195    struct MixedExpertSource {
2196        bf16: Vec<u8>,
2197        q4k: Vec<u8>,
2198    }
2199
2200    impl TensorSource for MixedExpertSource {
2201        fn config(&self) -> ModelConfig {
2202            panic!("unused by HostExps mixed-loader test")
2203        }
2204
2205        fn find(&self, name: &str) -> Option<TensorView<'_>> {
2206            let (bytes, ggml_type) = if name == "blk.0.ffn_gate_exps.0.weight" {
2207                (&self.bf16, GgmlType::BF16)
2208            } else if name == "blk.0.ffn_gate_exps.1.weight" {
2209                (&self.q4k, GgmlType::Q4_K)
2210            } else {
2211                return None;
2212            };
2213            Some(TensorView {
2214                bytes: Cow::Borrowed(bytes),
2215                ggml_type,
2216                ne: vec![256, 2],
2217            })
2218        }
2219    }
2220
2221    struct PrunedExpertSource {
2222        q2k: Vec<u8>,
2223        nvfp4: Vec<u8>,
2224        active: Vec<bool>,
2225    }
2226
2227    struct MmapExpertSource {
2228        file: std::sync::Arc<std::fs::File>,
2229        map: std::sync::Arc<memmap2::Mmap>,
2230        base_offset: usize,
2231        expert_len: usize,
2232    }
2233
2234    struct LegacyMmapExpertSource {
2235        map: std::sync::Arc<memmap2::Mmap>,
2236        expert_len: usize,
2237    }
2238
2239    impl TensorSource for MmapExpertSource {
2240        fn config(&self) -> ModelConfig {
2241            panic!("unused by HostExps mmap-loader test")
2242        }
2243        fn preserve_expert_encodings(&self) -> bool {
2244            true
2245        }
2246        fn find(&self, name: &str) -> Option<TensorView<'_>> {
2247            let ex = match name {
2248                "blk.0.ffn_gate_exps.0.weight" => 0,
2249                "blk.0.ffn_gate_exps.1.weight" => 1,
2250                _ => return None,
2251            };
2252            let off = self.base_offset + ex * self.expert_len;
2253            Some(TensorView {
2254                bytes: Cow::Borrowed(&self.map[off..off + self.expert_len]),
2255                ggml_type: GgmlType::Q2_K,
2256                ne: vec![256, 2],
2257            })
2258        }
2259        fn find_expert_disk(&self, name: &str) -> Option<DiskExtent> {
2260            let ex = match name {
2261                "blk.0.ffn_gate_exps.0.weight" => 0,
2262                "blk.0.ffn_gate_exps.1.weight" => 1,
2263                _ => return None,
2264            };
2265            Some(DiskExtent {
2266                map: self.map.clone(),
2267                file: self.file.clone(),
2268                offset: (self.base_offset + ex * self.expert_len) as u64,
2269                len: self.expert_len,
2270            })
2271        }
2272    }
2273
2274    impl TensorSource for LegacyMmapExpertSource {
2275        fn config(&self) -> ModelConfig {
2276            panic!("unused by legacy mmap guard test")
2277        }
2278        fn preserve_expert_encodings(&self) -> bool {
2279            true
2280        }
2281        fn find(&self, name: &str) -> Option<TensorView<'_>> {
2282            let ex = match name {
2283                "blk.0.ffn_gate_exps.0.weight" => 0,
2284                "blk.0.ffn_gate_exps.1.weight" => 1,
2285                _ => return None,
2286            };
2287            let off = ex * self.expert_len;
2288            Some(TensorView {
2289                bytes: Cow::Borrowed(&self.map[off..off + self.expert_len]),
2290                ggml_type: GgmlType::Q2_K,
2291                ne: vec![256, 2],
2292            })
2293        }
2294        fn find_expert_mmap(
2295            &self,
2296            name: &str,
2297        ) -> Option<(std::sync::Arc<memmap2::Mmap>, usize, usize)> {
2298            let ex = match name {
2299                "blk.0.ffn_gate_exps.0.weight" => 0,
2300                "blk.0.ffn_gate_exps.1.weight" => 1,
2301                _ => return None,
2302            };
2303            Some((self.map.clone(), ex * self.expert_len, self.expert_len))
2304        }
2305    }
2306
2307    impl TensorSource for PrunedExpertSource {
2308        fn config(&self) -> ModelConfig {
2309            panic!("unused by HostExps pruned-loader test")
2310        }
2311        fn active_experts(&self, layer: u32) -> Option<&[bool]> {
2312            (layer == 0).then_some(self.active.as_slice())
2313        }
2314        fn find(&self, name: &str) -> Option<TensorView<'_>> {
2315            let (bytes, ggml_type) = match name {
2316                "blk.0.ffn_gate_exps.0.weight" => (&self.q2k, GgmlType::Q2_K),
2317                "blk.0.ffn_gate_exps.2.weight" => (&self.nvfp4, GgmlType::NVFP4),
2318                _ => return None,
2319            };
2320            Some(TensorView {
2321                bytes: Cow::Borrowed(bytes),
2322                ggml_type,
2323                ne: vec![256, 2],
2324            })
2325        }
2326    }
2327
2328    /// A1 direct-import gate (engine side): the fused modelopt->split repack must be byte-for-byte
2329    /// the composition of the two passes it replaces (modelopt->GGUF blocks, then the A6
2330    /// split-plane repack). Also pins the split roundtrip on the same buffers.
2331    #[test]
2332    fn direct_split_equals_chained() {
2333        for (out_f, in_f) in [(1usize, 64usize), (3, 128), (5, 320), (8, 1024)] {
2334            let mut w = vec![0u8; out_f * in_f / 2];
2335            let mut s = vec![0u8; out_f * in_f / 16];
2336            for (i, b) in w.iter_mut().enumerate() {
2337                *b = ((i * 41 + 7) & 0xFF) as u8;
2338            }
2339            for (i, b) in s.iter_mut().enumerate() {
2340                *b = (0x20 + ((i * 11 + 5) % 0x50)) as u8;
2341            }
2342            let gguf = repack_modelopt_to_gguf(&w, &s, out_f, in_f);
2343            let chained = repack_nvfp4_split(&gguf, out_f);
2344            let direct = repack_modelopt_to_split(&w, &s, out_f, in_f);
2345            assert_eq!(
2346                direct, chained,
2347                "fused != chained at out_f={out_f} in_f={in_f}"
2348            );
2349            assert_eq!(
2350                unpack_nvfp4_split(&direct, out_f),
2351                gguf,
2352                "split roundtrip broken at out_f={out_f} in_f={in_f}"
2353            );
2354        }
2355    }
2356
2357    #[test]
2358    fn mixed_expert_loader_keeps_each_encoding_and_extent() {
2359        let source = MixedExpertSource {
2360            bf16: vec![0x5a; 256 * 2 * 2],
2361            q4k: vec![0xa5; 2 * 144],
2362        };
2363        let exps = HostExps::load_mixed_from_source(&source, 0, "gate", 2).unwrap();
2364        assert!(!exps.is_uniform_layout());
2365        assert_eq!(exps.max_expert_bytes(), 1024);
2366        assert_eq!(exps.expert_layout(0).qtype, QT_BF16);
2367        assert_eq!(exps.expert_layout(0).row_bytes, 512);
2368        assert_eq!(exps.expert_layout(0).len, 1024);
2369        assert_eq!(exps.expert_layout(1).qtype, QT_Q4_K);
2370        assert_eq!(exps.expert_layout(1).row_bytes, 144);
2371        assert_eq!(exps.expert_layout(1).len, 288);
2372        assert_eq!(exps.expert_bytes(0), source.bf16);
2373        assert_eq!(exps.expert_bytes(1), source.q4k);
2374        match exps.expert_source(1) {
2375            ExpertSource::Memory { bytes, .. } => assert_eq!(bytes, source.q4k),
2376            ExpertSource::Disk { .. } => panic!("paged expert unexpectedly became disk-backed"),
2377        }
2378    }
2379
2380    #[test]
2381    fn mixed_expert_loader_omits_masked_expert_bytes() {
2382        let source = PrunedExpertSource {
2383            q2k: vec![0x22; 2 * 84],
2384            nvfp4: vec![0x44; 2 * 4 * 36],
2385            active: vec![true, false, true],
2386        };
2387        let exps = HostExps::load_mixed_from_source(&source, 0, "gate", 3).unwrap();
2388        assert_eq!(exps.expert_layout(0).qtype, QT_Q2_K);
2389        assert_eq!(exps.expert_layout(0).row_bytes, 84);
2390        assert_eq!(exps.expert_layout(1).len, 0);
2391        assert_eq!(exps.expert_bytes(1), &[]);
2392        assert_eq!(exps.expert_layout(2).qtype, QT_NVFP4);
2393        assert_eq!(exps.expert_layout(2).row_bytes, 4 * 36);
2394    }
2395
2396    #[test]
2397    fn mixed_expert_loader_keeps_mmap_backing_zero_copy() {
2398        let path = std::env::temp_dir().join(format!("memra-mixed-mmap-{}", std::process::id()));
2399        let base_offset = 3usize;
2400        let expert_len = 2 * 84;
2401        let mut bytes = vec![0xE1; base_offset];
2402        bytes.extend(vec![0x31; expert_len]);
2403        bytes.extend(vec![0x72; expert_len]);
2404        std::fs::write(&path, &bytes).unwrap();
2405        let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
2406        let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
2407        let source = MmapExpertSource {
2408            file: file.clone(),
2409            map,
2410            base_offset,
2411            expert_len,
2412        };
2413        let exps = HostExps::load_mixed_from_source(&source, 0, "gate", 2).unwrap();
2414        assert!(matches!(
2415            exps.tiers.as_ref().unwrap()[0],
2416            HostBuf::Mmap { .. }
2417        ));
2418        assert!(matches!(
2419            exps.tiers.as_ref().unwrap()[1],
2420            HostBuf::Mmap { .. }
2421        ));
2422        assert_eq!(
2423            exps.expert_bytes(0),
2424            &bytes[base_offset..base_offset + expert_len]
2425        );
2426        assert_eq!(exps.expert_bytes(1), &bytes[base_offset + expert_len..]);
2427        match exps.expert_source(1) {
2428            ExpertSource::Disk {
2429                file: got_file,
2430                offset,
2431                len,
2432                fallback,
2433                keepalive,
2434            } => {
2435                assert!(std::sync::Arc::ptr_eq(got_file, &file));
2436                assert_eq!(offset, (base_offset + expert_len) as u64);
2437                assert_eq!(len, expert_len);
2438                assert_eq!(fallback, &bytes[base_offset + expert_len..]);
2439                match keepalive {
2440                    ExpertKeepalive::Mmap(owner) => {
2441                        assert!(std::sync::Arc::ptr_eq(&owner, &source.map));
2442                    }
2443                    _ => panic!("mmap expert did not retain its mmap owner"),
2444                }
2445            }
2446            ExpertSource::Memory { .. } => panic!("mixed mmap tier lost its disk extent"),
2447        }
2448        #[cfg(unix)]
2449        assert!(exps.prefetch_expert_pages(1));
2450        std::fs::remove_file(path).ok();
2451    }
2452
2453    #[test]
2454    fn tiered_expert_source_does_not_double_apply_layout_offset() {
2455        let path =
2456            std::env::temp_dir().join(format!("memra-tiered-source-offset-{}", std::process::id()));
2457        let base_offset = 7usize;
2458        let expert_len = 2 * 84;
2459        let mut bytes = vec![0xE3; base_offset];
2460        bytes.extend(vec![0x41; expert_len]);
2461        bytes.extend(vec![0x82; expert_len]);
2462        std::fs::write(&path, &bytes).unwrap();
2463        let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
2464        let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
2465        let exps = HostExps {
2466            bytes: HostBuf::Paged(Vec::new()),
2467            tiers: Some(vec![
2468                HostBuf::Mmap {
2469                    map: map.clone(),
2470                    file: file.clone(),
2471                    off: base_offset,
2472                    len: expert_len,
2473                },
2474                HostBuf::Mmap {
2475                    map,
2476                    file: file.clone(),
2477                    off: base_offset + expert_len,
2478                    len: expert_len,
2479                },
2480            ]),
2481            qtype: QT_Q2_K,
2482            in_f: 256,
2483            out_f: 2,
2484            n_expert: 2,
2485            row_bytes: 84,
2486            expert_stride: expert_len,
2487            layouts: None,
2488            macros: None,
2489        };
2490
2491        // `expert_layout(1).offset == expert_len`, but tier 1 already starts at expert 1.
2492        assert_eq!(exps.expert_layout(1).offset, expert_len);
2493        match exps.expert_source(1) {
2494            ExpertSource::Disk {
2495                offset,
2496                len,
2497                fallback,
2498                ..
2499            } => {
2500                assert_eq!(offset, (base_offset + expert_len) as u64);
2501                assert_eq!(len, expert_len);
2502                assert_eq!(fallback, &bytes[base_offset + expert_len..]);
2503            }
2504            ExpertSource::Memory { .. } => panic!("tiered mmap expert lost its disk extent"),
2505        }
2506        std::fs::remove_file(path).ok();
2507    }
2508
2509    #[test]
2510    fn legacy_mmap_source_requires_retained_file_extent() {
2511        let path =
2512            std::env::temp_dir().join(format!("memra-legacy-mmap-source-{}", std::process::id()));
2513        let expert_len = 2 * 84;
2514        std::fs::write(&path, vec![0x64; 2 * expert_len]).unwrap();
2515        let file = std::fs::File::open(&path).unwrap();
2516        let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(&file).unwrap() });
2517        let source = LegacyMmapExpertSource { map, expert_len };
2518
2519        let err = match HostExps::load_uniform_mmap_from_source(&source, 0, "gate", 2) {
2520            Ok(_) => panic!("legacy mmap-only source silently fell back instead of failing"),
2521            Err(err) => err,
2522        };
2523        let message = err.to_string();
2524        assert!(
2525            message.contains("legacy find_expert_mmap without find_expert_disk"),
2526            "{message}"
2527        );
2528        assert!(message.contains("retained Arc<File>"), "{message}");
2529        std::fs::remove_file(path).ok();
2530    }
2531
2532    #[test]
2533    fn uniform_expert_loader_coalesces_contiguous_mmap() {
2534        let path = std::env::temp_dir().join(format!("memra-uniform-mmap-{}", std::process::id()));
2535        let base_offset = 5usize;
2536        let expert_len = 2 * 84;
2537        let mut bytes = vec![0xE2; base_offset];
2538        bytes.extend(vec![0x19; expert_len]);
2539        bytes.extend(vec![0x91; expert_len]);
2540        std::fs::write(&path, &bytes).unwrap();
2541        let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
2542        let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
2543        let source = MmapExpertSource {
2544            file: file.clone(),
2545            map,
2546            base_offset,
2547            expert_len,
2548        };
2549        let exps = HostExps::load_uniform_mmap_from_source(&source, 0, "gate", 2)
2550            .unwrap()
2551            .expect("contiguous mmap should coalesce");
2552        assert!(exps.is_uniform_layout());
2553        assert!(matches!(&exps.bytes, HostBuf::Mmap { .. }));
2554        assert_eq!(exps.expert_stride, expert_len);
2555        assert_eq!(
2556            exps.expert_bytes(0),
2557            &bytes[base_offset..base_offset + expert_len]
2558        );
2559        assert_eq!(exps.expert_bytes(1), &bytes[base_offset + expert_len..]);
2560        match exps.expert_source(1) {
2561            ExpertSource::Disk {
2562                file: got_file,
2563                offset,
2564                len,
2565                fallback,
2566                ..
2567            } => {
2568                assert!(std::sync::Arc::ptr_eq(got_file, &file));
2569                assert_eq!(offset, (base_offset + expert_len) as u64);
2570                assert_eq!(len, expert_len);
2571                assert_eq!(fallback, &bytes[base_offset + expert_len..]);
2572            }
2573            ExpertSource::Memory { .. } => panic!("uniform mmap slab lost its disk extent"),
2574        }
2575        #[cfg(unix)]
2576        assert!(exps.prefetch_expert_pages(1));
2577        std::fs::remove_file(path).ok();
2578    }
2579}