1use crate::{
6 Engine, QT_BF16, QT_F8_E4M3, QT_F32, 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 cudarc::driver::CudaSlice;
10use memra_gguf::config::ModelConfig;
11use memra_gguf::source::{DiskExtent, GgufSource, TensorSource};
12use memra_gguf::{GgmlType, GgufFile, dequant};
13use std::collections::HashMap;
14use std::path::Path;
15
16static RESIDENCY_CENSUS: [(std::sync::atomic::AtomicUsize, std::sync::atomic::AtomicU64); 16] = {
24 #[allow(clippy::declare_interior_mutable_const)]
25 const Z: (std::sync::atomic::AtomicUsize, std::sync::atomic::AtomicU64) = (
26 std::sync::atomic::AtomicUsize::new(0),
27 std::sync::atomic::AtomicU64::new(0),
28 );
29 [Z; 16]
30};
31
32fn residency_census_note(qtype: i32, bytes: usize) {
33 use std::sync::atomic::Ordering::Relaxed;
34 if let Some(slot) = RESIDENCY_CENSUS.get(qtype as usize) {
35 slot.0.fetch_add(1, Relaxed);
36 slot.1.fetch_add(bytes as u64, Relaxed);
37 }
38}
39
40pub fn residency_census_report() -> String {
43 use std::sync::atomic::Ordering::Relaxed;
44 let name = |q: usize| -> &'static str {
45 match q as i32 {
46 QT_Q8_0 => "Q8_0",
47 QT_Q4_K => "Q4_K",
48 QT_Q6_K => "Q6_K",
49 QT_Q5_K => "Q5_K",
50 QT_Q3_K => "Q3_K",
51 QT_IQ4_XS => "IQ4_XS",
52 QT_IQ3_S => "IQ3_S",
53 QT_NVFP4 => "NVFP4",
54 QT_F32 => "F32",
55 QT_NVFP4_RP => "NVFP4_RP",
56 QT_F8_E4M3 => "F8_E4M3",
57 QT_BF16 => "BF16",
58 QT_Q4_0 => "Q4_0",
59 QT_Q2_K => "Q2_K",
60 crate::QT_F8_E4M3_BLK => "F8_E4M3_BLK",
61 _ => "?",
62 }
63 };
64 let mut out = String::from("residency census (2D matmul weights, resident container):\n");
65 let (mut tn, mut tb) = (0usize, 0u64);
66 for (q, slot) in RESIDENCY_CENSUS.iter().enumerate() {
67 let (n, b) = (slot.0.load(Relaxed), slot.1.load(Relaxed));
68 if n == 0 {
69 continue;
70 }
71 tn += n;
72 tb += b;
73 out += &format!(
74 " {:>9}: {:>4} tensors {:>9.3} MiB\n",
75 name(q),
76 n,
77 b as f64 / (1024.0 * 1024.0)
78 );
79 }
80 out += &format!(
81 " {:>9}: {:>4} tensors {:>9.3} MiB",
82 "TOTAL",
83 tn,
84 tb as f64 / (1024.0 * 1024.0)
85 );
86 out
87}
88
89fn ensure_repack_cache_dir(path: &Path) -> std::io::Result<()> {
97 match std::fs::symlink_metadata(path) {
98 Ok(meta) => {
99 if meta.file_type().is_symlink() || !meta.is_dir() {
100 return Err(std::io::Error::new(
101 std::io::ErrorKind::InvalidData,
102 format!("repack cache directory is not a real directory: {path:?}"),
103 ));
104 }
105 Ok(())
106 }
107 Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
108 match std::fs::create_dir(path) {
109 Ok(()) => Ok(()),
110 Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {
111 ensure_repack_cache_dir(path)
112 }
113 Err(error) => Err(error),
114 }
115 }
116 Err(error) => Err(error),
117 }
118}
119
120fn repack_cache_is_fresh(path: &Path, expected_len: usize) -> bool {
121 std::fs::symlink_metadata(path)
122 .is_ok_and(|meta| meta.file_type().is_file() && meta.len() == expected_len as u64)
123}
124
125#[cfg(unix)]
126fn open_repack_cache_dir(path: &Path) -> std::io::Result<std::fs::File> {
127 use std::os::unix::fs::OpenOptionsExt;
128 let mut options = std::fs::OpenOptions::new();
129 options
130 .read(true)
131 .custom_flags(libc::O_DIRECTORY | libc::O_NOFOLLOW);
132 options.open(path)
133}
134
135#[cfg(not(unix))]
136fn open_repack_cache_dir(path: &Path) -> std::io::Result<std::fs::File> {
137 std::fs::OpenOptions::new().read(true).open(path)
138}
139
140#[cfg(unix)]
141fn open_repack_cache(path: &Path, write: bool) -> std::io::Result<std::fs::File> {
142 use std::ffi::CString;
143 use std::os::unix::ffi::OsStrExt;
144 use std::os::unix::io::{AsRawFd, FromRawFd};
145
146 let parent = path.parent().ok_or_else(|| {
147 std::io::Error::new(
148 std::io::ErrorKind::InvalidInput,
149 "repack cache has no parent",
150 )
151 })?;
152 let name = path.file_name().ok_or_else(|| {
153 std::io::Error::new(
154 std::io::ErrorKind::InvalidInput,
155 "repack cache has no filename",
156 )
157 })?;
158 let name = CString::new(name.as_bytes()).map_err(|_| {
159 std::io::Error::new(
160 std::io::ErrorKind::InvalidInput,
161 "repack cache filename has NUL",
162 )
163 })?;
164 let dir = open_repack_cache_dir(parent)?;
165 let flags = if write {
166 libc::O_WRONLY | libc::O_CREAT | libc::O_EXCL | libc::O_NOFOLLOW
167 } else {
168 libc::O_RDONLY | libc::O_NOFOLLOW
169 };
170 let fd = unsafe { libc::openat(dir.as_raw_fd(), name.as_ptr(), flags, 0o600) };
171 if fd < 0 {
172 return Err(std::io::Error::last_os_error());
173 }
174 let file = unsafe { std::fs::File::from_raw_fd(fd) };
176 let metadata = file.metadata()?;
177 if !metadata.is_file() {
178 return Err(std::io::Error::new(
179 std::io::ErrorKind::InvalidData,
180 format!("repack cache is not a regular file: {path:?}"),
181 ));
182 }
183 if std::os::unix::fs::MetadataExt::nlink(&metadata) > 1 {
184 return Err(std::io::Error::new(
185 std::io::ErrorKind::InvalidData,
186 format!("repack cache refuses a multiply-linked file: {path:?}"),
187 ));
188 }
189 Ok(file)
190}
191
192#[cfg(not(unix))]
193fn open_repack_cache(path: &Path, write: bool) -> std::io::Result<std::fs::File> {
194 let metadata = std::fs::symlink_metadata(path)?;
195 if metadata.file_type().is_symlink() || !metadata.is_file() {
196 return Err(std::io::Error::new(
197 std::io::ErrorKind::InvalidData,
198 format!("repack cache is not a regular file: {path:?}"),
199 ));
200 }
201 let mut options = std::fs::OpenOptions::new();
202 options.read(!write).write(write);
203 options.open(path)
204}
205
206fn write_repack_cache<F>(path: &Path, write: F) -> std::io::Result<()>
212where
213 F: FnOnce(&mut std::io::BufWriter<std::fs::File>) -> std::io::Result<()>,
214{
215 use std::io::Write;
216
217 let parent = path.parent().ok_or_else(|| {
218 std::io::Error::new(
219 std::io::ErrorKind::InvalidInput,
220 "repack cache has no parent",
221 )
222 })?;
223 let name = path.file_name().ok_or_else(|| {
224 std::io::Error::new(
225 std::io::ErrorKind::InvalidInput,
226 "repack cache has no filename",
227 )
228 })?;
229 let dir = open_repack_cache_dir(parent)?;
230
231 #[cfg(unix)]
232 {
233 use std::ffi::CString;
234 use std::os::unix::ffi::OsStrExt;
235 use std::os::unix::io::{AsRawFd, FromRawFd};
236 static TEMP_COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
237 let name = CString::new(name.as_bytes()).map_err(|_| {
238 std::io::Error::new(
239 std::io::ErrorKind::InvalidInput,
240 "repack cache filename has NUL",
241 )
242 })?;
243 let mut temp_name = None;
244 let mut temp_file = None;
245 for _ in 0..32 {
246 let suffix = TEMP_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
247 let candidate = CString::new(format!(
248 ".{}.tmp-{}-{suffix}",
249 name.to_string_lossy(),
250 std::process::id()
251 ))
252 .map_err(|_| {
253 std::io::Error::new(
254 std::io::ErrorKind::InvalidInput,
255 "temporary filename has NUL",
256 )
257 })?;
258 let fd = unsafe {
259 libc::openat(
260 dir.as_raw_fd(),
261 candidate.as_ptr(),
262 libc::O_WRONLY | libc::O_CREAT | libc::O_EXCL | libc::O_NOFOLLOW,
263 0o600,
264 )
265 };
266 if fd >= 0 {
267 temp_name = Some(candidate);
268 temp_file = Some(unsafe { std::fs::File::from_raw_fd(fd) });
270 break;
271 }
272 let error = std::io::Error::last_os_error();
273 if error.kind() != std::io::ErrorKind::AlreadyExists {
274 return Err(error);
275 }
276 }
277 let temp_name = temp_name.ok_or_else(|| {
278 std::io::Error::new(
279 std::io::ErrorKind::AlreadyExists,
280 "could not allocate a unique repack cache temporary",
281 )
282 })?;
283 let mut out = std::io::BufWriter::new(temp_file.expect("temporary file accompanies name"));
284 let result = write(&mut out).and_then(|()| {
285 out.flush()?;
286 out.get_ref().sync_all()?;
287 Ok(())
288 });
289 drop(out);
290 if let Err(error) = result {
291 unsafe {
292 libc::unlinkat(dir.as_raw_fd(), temp_name.as_ptr(), 0);
293 }
294 return Err(error);
295 }
296
297 if let Ok(metadata) = std::fs::symlink_metadata(path)
301 && (metadata.file_type().is_symlink()
302 || !metadata.is_file()
303 || std::os::unix::fs::MetadataExt::nlink(&metadata) > 1)
304 {
305 unsafe {
306 libc::unlinkat(dir.as_raw_fd(), temp_name.as_ptr(), 0);
307 }
308 return Err(std::io::Error::new(
309 std::io::ErrorKind::InvalidData,
310 format!("repack cache target is not a private regular file: {path:?}"),
311 ));
312 }
313 let status = unsafe {
314 libc::renameat(
315 dir.as_raw_fd(),
316 temp_name.as_ptr(),
317 dir.as_raw_fd(),
318 name.as_ptr(),
319 )
320 };
321 if status != 0 {
322 unsafe {
323 libc::unlinkat(dir.as_raw_fd(), temp_name.as_ptr(), 0);
324 }
325 return Err(std::io::Error::last_os_error());
326 }
327 dir.sync_all()
328 }
329
330 #[cfg(not(unix))]
331 {
332 let temp = parent.join(format!(
333 ".{}.tmp-{}",
334 name.to_string_lossy(),
335 std::process::id()
336 ));
337 let mut out = std::io::BufWriter::new(
338 std::fs::OpenOptions::new()
339 .write(true)
340 .create_new(true)
341 .open(&temp)?,
342 );
343 write(&mut out)?;
344 out.flush()?;
345 out.get_ref().sync_all()?;
346 drop(out);
347 if let Ok(metadata) = std::fs::symlink_metadata(path) {
348 if metadata.file_type().is_symlink() || !metadata.is_file() {
349 std::fs::remove_file(&temp).ok();
350 return Err(std::io::Error::new(
351 std::io::ErrorKind::InvalidData,
352 format!("repack cache target is not a private regular file: {path:?}"),
353 ));
354 }
355 }
356 std::fs::rename(temp, path)
357 }
358}
359
360#[allow(clippy::large_enum_variant)] pub enum GpuTensor {
365 Quant {
366 bytes: CudaSlice<u8>,
367 qtype: i32,
368 row_bytes: usize,
369 ne: Vec<u64>,
370 scale: f32,
371 rp: bool,
379 #[cfg(memra_cutlass)]
383 cutlass: Option<CutlassWeight>,
384 fp8: Option<Fp8Weight>,
390 rp4: Option<CudaSlice<u8>>,
397 blk: Option<Fp8BlockScales>,
405 f16: Option<CudaSlice<u8>>,
410 },
411 Float {
412 data: CudaSlice<f32>,
413 ne: Vec<u64>,
414 },
415 FloatBf16 {
422 data: CudaSlice<u8>,
423 ne: Vec<u64>,
424 },
425}
426
427pub struct Fp8Weight {
433 pub bytes: CudaSlice<u8>,
434 pub scale: f32,
435 pub blk: Option<Fp8BlockScales>,
436}
437
438pub struct Fp8BlockScales {
455 pub scales: CudaSlice<f32>,
456 pub rows: usize, pub cols: usize, }
459
460pub fn repack_nvfp4_split(bytes: &[u8], out_f: usize) -> Vec<u8> {
464 let row_bytes = bytes.len() / out_f;
465 let nsb64 = row_bytes / 36;
466 debug_assert_eq!(
467 row_bytes % 36,
468 0,
469 "NVFP4 row_bytes must be a multiple of 36"
470 );
471 let qplane = out_f * nsb64 * 32;
472 let mut rp = vec![0u8; bytes.len()];
473 for o in 0..out_f {
474 for s in 0..nsb64 {
475 let src = &bytes[o * row_bytes + s * 36..o * row_bytes + s * 36 + 36];
476 rp[qplane + (o * nsb64 + s) * 4..qplane + (o * nsb64 + s) * 4 + 4]
477 .copy_from_slice(&src[0..4]);
478 rp[(o * nsb64 + s) * 32..(o * nsb64 + s) * 32 + 32].copy_from_slice(&src[4..36]);
479 }
480 }
481 rp
482}
483
484pub fn unpack_nvfp4_split(rp: &[u8], out_f: usize) -> Vec<u8> {
486 let row_bytes = rp.len() / out_f;
487 let nsb64 = row_bytes / 36;
488 let qplane = out_f * nsb64 * 32;
489 let mut back = vec![0u8; rp.len()];
490 for o in 0..out_f {
491 for s in 0..nsb64 {
492 back[o * row_bytes + s * 36..o * row_bytes + s * 36 + 4].copy_from_slice(
493 &rp[qplane + (o * nsb64 + s) * 4..qplane + (o * nsb64 + s) * 4 + 4],
494 );
495 back[o * row_bytes + s * 36 + 4..o * row_bytes + s * 36 + 36]
496 .copy_from_slice(&rp[(o * nsb64 + s) * 32..(o * nsb64 + s) * 32 + 32]);
497 }
498 }
499 back
500}
501
502pub fn rp_enabled() -> bool {
504 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
505 *ON.get_or_init(|| std::env::var("MEMRA_RP").map(|v| v != "0").unwrap_or(true))
506}
507
508pub fn full_prec_enabled() -> bool {
517 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
518 *ON.get_or_init(|| {
519 std::env::var("MEMRA_FULL_PREC")
520 .map(|v| v == "1")
521 .unwrap_or(false)
522 })
523}
524
525fn float_2d_audited(name: &str) -> bool {
535 name.ends_with("ffn_gate_inp.weight")
536 || name.ends_with("hc_attn_fn")
542 || name.ends_with("hc_ffn_fn")
543}
544
545fn warn_float_2d_once(name: &str, ne: &[u64], src_type: GgmlType) {
548 use std::sync::{Mutex, OnceLock};
549 static SEEN: OnceLock<Mutex<std::collections::HashSet<String>>> = OnceLock::new();
550 let pat = match name.strip_prefix("blk.").and_then(|r| r.split_once('.')) {
551 Some((_, suffix)) => format!("blk.*.{suffix}"),
552 None => name.to_string(),
553 };
554 let mut seen = SEEN
555 .get_or_init(|| Mutex::new(std::collections::HashSet::new()))
556 .lock()
557 .unwrap();
558 if seen.insert(pat.clone()) {
559 eprintln!(
560 "[loader-law] WARNING: {pat} loads as 2D Float ne={ne:?} (src {src_type:?}) — \
561 a Float matmul weight rides cuBLAS f32 GEMV and poisons all-or-nothing q8-fast \
562 predicates (uses_q8_1_fast/mixer_in_q8_1_fast). If matmul-class: Q8_0-encode at \
563 load (model.rs ssm arm / source.rs BF16+F8 gates). If deliberately Float: add \
564 it to float_2d_audited with the audit rationale."
565 );
566 }
567}
568
569#[cfg(memra_cutlass)]
572pub struct CutlassWeight {
573 pub b_packed: CudaSlice<u8>,
575 pub sfb_swizzled: CudaSlice<u8>,
577}
578
579impl GpuTensor {
580 pub fn nvfp4_rp_from_raw(
587 e: &Engine,
588 raw: &[u8],
589 in_f: usize,
590 out_f: usize,
591 scale: f32,
592 ) -> Result<Self, Box<dyn std::error::Error>> {
593 assert_eq!(raw.len() % out_f, 0, "raw bytes must tile out_f rows");
594 let row_bytes = raw.len() / out_f;
595 assert_eq!(
596 row_bytes,
597 in_f / 64 * 36,
598 "NVFP4 row layout: 36B per 64 values"
599 );
600 let bytes = e.htod_bytes(&repack_nvfp4_split(raw, out_f))?;
601 Ok(GpuTensor::Quant {
602 bytes,
603 qtype: crate::QT_NVFP4,
604 row_bytes,
605 ne: vec![in_f as u64, out_f as u64],
606 scale,
607 rp: true,
608 #[cfg(memra_cutlass)]
609 cutlass: None,
610 fp8: None,
611 rp4: None,
612 blk: None,
613 f16: None,
614 })
615 }
616
617 pub fn ne(&self) -> &[u64] {
618 match self {
619 GpuTensor::Quant { ne, .. } => ne,
620 GpuTensor::Float { ne, .. } => ne,
621 GpuTensor::FloatBf16 { ne, .. } => ne,
622 }
623 }
624 pub fn in_features(&self) -> usize {
625 self.ne()[0] as usize
626 }
627 pub fn out_features(&self) -> usize {
628 self.ne()[1] as usize
629 }
630 pub fn scale(&self) -> f32 {
633 match self {
634 GpuTensor::Quant { scale, .. } => *scale,
635 GpuTensor::Float { .. } | GpuTensor::FloatBf16 { .. } => 1.0,
636 }
637 }
638
639 pub fn load(e: &Engine, g: &GgufFile, name: &str) -> Result<Self, Box<dyn std::error::Error>> {
642 Self::load_from_source(e, &GgufSource(g), name)
643 }
644
645 pub fn load_from_source(
654 e: &Engine,
655 src: &dyn TensorSource,
656 name: &str,
657 ) -> Result<Self, Box<dyn std::error::Error>> {
658 let t = Self::load_from_source_inner(e, src, name)?;
659 if let GpuTensor::Quant {
660 qtype, bytes, ne, ..
661 } = &t
662 && ne.len() == 2
663 {
664 residency_census_note(*qtype, bytes.len());
665 }
666 Ok(t)
667 }
668
669 #[allow(clippy::manual_is_multiple_of)] fn load_from_source_inner(
671 e: &Engine,
672 src: &dyn TensorSource,
673 name: &str,
674 ) -> Result<Self, Box<dyn std::error::Error>> {
675 let cutlass_wants_raw = cfg!(memra_cutlass) && std::env::var("MEMRA_FP4_CUTLASS").is_ok();
683 let st_direct = std::env::var("MEMRA_ST_DIRECT")
684 .map(|v| v != "0")
685 .unwrap_or(true);
686 if rp_enabled()
687 && st_direct
688 && !cutlass_wants_raw
689 && let Some(nv) = src.find_nvfp4_native(name)
690 && nv.in_f % 64 == 0
691 && nv.out_f > 0
692 {
693 let stem = name.strip_suffix(".weight").unwrap_or(name);
695 let scale = match src.find(&format!("{stem}.scale")) {
696 Some(sv) => f32::from_le_bytes(sv.bytes[..4].try_into().unwrap()),
697 None => 1.0,
698 };
699 let bytes = e.htod_bytes(&memra_gguf::nvfp4_repack::repack_modelopt_to_split(
700 nv.wbytes, nv.wscale, nv.out_f, nv.in_f,
701 ))?;
702 return Ok(GpuTensor::Quant {
703 bytes,
704 qtype: QT_NVFP4,
705 row_bytes: nv.in_f / 64 * 36,
706 ne: vec![nv.in_f as u64, nv.out_f as u64],
707 scale,
708 rp: true,
709 #[cfg(memra_cutlass)]
710 cutlass: None,
711 fp8: None,
712 blk: None,
713 f16: None,
714 rp4: None,
715 });
716 }
717 if crate::fp8_ffi::st_e4m3_enabled()
732 && let Some(f8) = src.find_fp8_native(name)
733 && f8.blk.is_none()
734 && f8.in_f % 32 == 0
735 && f8.out_f > 0
736 {
737 return Ok(GpuTensor::Quant {
738 bytes: e.htod_bytes(&f8.bytes)?,
739 qtype: crate::QT_F8_E4M3,
740 row_bytes: f8.in_f,
741 ne: vec![f8.in_f as u64, f8.out_f as u64],
742 scale: f8.scale,
743 rp: false,
744 #[cfg(memra_cutlass)]
745 cutlass: None,
746 fp8: None,
747 blk: None,
748 f16: None,
749 rp4: None,
750 });
751 }
752 if crate::fp8_ffi::st_e4m3_blk_enabled()
779 && let Some(f8) = src.find_fp8_native(name)
780 && let Some(grid) = f8.blk.as_ref()
781 {
782 let (in_f, out_f) = (f8.in_f, f8.out_f);
783 if in_f % 32 == 0
789 && out_f > 0
790 && f8.bytes.len() == out_f * in_f
791 && grid.rows == out_f.div_ceil(128)
792 && grid.cols == in_f.div_ceil(128)
793 && grid.scales.len() == grid.rows * grid.cols
794 && f8.scale == 1.0
795 {
796 let bytes = e.htod_bytes(&f8.bytes)?;
797 if e.fp8_blk_nan_count(&bytes)? == 0 {
798 let scales = e.htod(&grid.scales)?;
799 return Ok(GpuTensor::Quant {
800 bytes,
801 qtype: crate::QT_F8_E4M3_BLK,
802 row_bytes: in_f,
803 ne: vec![in_f as u64, out_f as u64],
804 scale: 1.0,
805 rp: false,
806 #[cfg(memra_cutlass)]
807 cutlass: None,
808 fp8: None,
809 blk: Some(Fp8BlockScales {
810 scales,
811 rows: grid.rows,
812 cols: grid.cols,
813 }),
814 f16: None,
815 rp4: None,
816 });
817 }
818 crate::fp8_ffi::note_blk_native_nan_refused();
819 }
820 }
821 if crate::fp8_ffi::fp8_blk_gpu_enabled()
847 && let Some(f8) = src.find_fp8_native(name)
848 && let Some(grid) = f8.blk.as_ref()
849 {
850 let (in_f, out_f) = (f8.in_f, f8.out_f);
851 if in_f % 32 == 0 && out_f > 0 && f8.bytes.len() == out_f * in_f {
852 let bytes = e.fp8_blk_dequant_q8_0(&f8.bytes, &grid.scales, out_f, in_f)?;
853 return Ok(GpuTensor::Quant {
854 bytes,
855 qtype: QT_Q8_0,
856 row_bytes: in_f / 32 * 34,
857 ne: vec![in_f as u64, out_f as u64],
858 scale: 1.0,
859 rp: false,
860 #[cfg(memra_cutlass)]
861 cutlass: None,
862 fp8: None,
863 blk: None,
864 f16: None,
865 rp4: None,
866 });
867 }
868 }
869 let mut v = src
870 .find(name)
871 .unwrap_or_else(|| panic!("missing tensor {name}"));
872 let kq = std::env::var("MEMRA_KQ_NVFP4")
887 .ok()
888 .and_then(|x| x.parse::<u8>().ok())
889 .unwrap_or(0);
890 if (kq >= 1 && v.ggml_type == GgmlType::Q4_K || kq >= 2 && v.ggml_type == GgmlType::Q5_K)
891 && v.ne.len() == 2
892 && v.ne[0].is_multiple_of(64)
893 && !name.starts_with("output")
894 {
895 let n: u64 = v.ne.iter().product();
896 let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n as usize);
897 let packed = memra_gguf::nvfp4_repack::f32_to_nvfp4(&f32v);
898 v = memra_gguf::source::TensorView {
899 bytes: std::borrow::Cow::Owned(packed),
900 ggml_type: GgmlType::NVFP4,
901 ne: v.ne.clone(),
902 };
903 }
904 let qtype = match v.ggml_type {
905 GgmlType::Q8_0 => Some(QT_Q8_0),
906 GgmlType::Q4_K => Some(QT_Q4_K),
907 GgmlType::Q6_K => Some(QT_Q6_K),
908 GgmlType::Q5_K => Some(QT_Q5_K),
909 GgmlType::Q3_K => Some(QT_Q3_K),
910 GgmlType::IQ4_XS => Some(QT_IQ4_XS),
911 GgmlType::IQ3_S => Some(QT_IQ3_S),
912 GgmlType::NVFP4 => Some(QT_NVFP4),
913 GgmlType::Q4_0 => Some(QT_Q4_0),
914 _ => None,
916 };
917 match qtype {
918 Some(qt) => {
919 if v.ne.len() != 2 {
932 return Err(format!(
933 "{name}: quantized tensor (qtype {qt}) has {}-D ne {:?}, but every \
934 quantized resident layout in this engine is 2-D — row_bytes is derived \
935 from ne[1] as the out-feature count and would be wrong here. A 3-D \
936 operand must be dequantized at the source (see TensorTransform::\
937 SplitMlaKv) or split per head before it reaches the loader.",
938 v.ne.len(),
939 v.ne
940 )
941 .into());
942 }
943 let out_f = v.ne[1] as usize;
944 let row_bytes = v.bytes.len() / out_f;
945 let scale = if qt == QT_NVFP4 {
950 let stem = name.strip_suffix(".weight").unwrap_or(name);
951 match src.find(&format!("{stem}.scale")) {
952 Some(sv) => f32::from_le_bytes(sv.bytes[..4].try_into().unwrap()),
953 None => 1.0,
954 }
955 } else {
956 1.0
957 };
958 let rp = qt == QT_NVFP4
962 && v.ne.len() == 2
963 && (v.ne[0] as usize).is_multiple_of(64)
964 && v.bytes.len() % out_f == 0
965 && (v.bytes.len() / out_f).is_multiple_of(36)
966 && rp_enabled();
967 let bytes = if rp {
968 e.htod_bytes(&repack_nvfp4_split(&v.bytes, out_f))?
969 } else {
970 e.htod_bytes(&v.bytes)?
971 };
972 #[cfg(memra_cutlass)]
977 let cutlass = {
978 let in_f = v.ne[0] as usize;
979 if qt == QT_NVFP4
982 && in_f % 64 == 0
983 && v.ne.len() == 2
984 && std::env::var("MEMRA_FP4_CUTLASS").is_ok()
985 && std::env::var("MEMRA_FP4_CUTLASS_OTF").is_err()
986 {
987 let raw_dev;
988 let src_dev = if rp {
989 raw_dev = e.htod_bytes(&v.bytes)?;
990 &raw_dev
991 } else {
992 &bytes
993 };
994 let (b_packed, sfb_swizzled) =
995 e.build_cutlass_weight(src_dev, out_f, in_f, row_bytes)?;
996 Some(CutlassWeight {
997 b_packed,
998 sfb_swizzled,
999 })
1000 } else {
1001 None
1002 }
1003 };
1004 let fp8 = if qt == QT_Q8_0
1024 && (crate::fp8_ffi::pp_fp8_enabled() || crate::fp8_ffi::fp8_mmq_enabled())
1025 {
1026 match src.find_fp8_native(name) {
1027 Some(f8)
1028 if v.ne.len() == 2
1029 && f8.in_f as u64 == v.ne[0]
1030 && f8.out_f as u64 == v.ne[1] =>
1031 {
1032 use std::sync::atomic::{AtomicUsize, Ordering};
1033 static FP8_SPENT: AtomicUsize = AtomicUsize::new(0);
1034 static FP8_BUDGET: std::sync::OnceLock<usize> =
1035 std::sync::OnceLock::new();
1036 let budget = *FP8_BUDGET.get_or_init(|| {
1037 std::env::var("MEMRA_PP_FP8_BUDGET_MB")
1038 .ok()
1039 .and_then(|v| v.parse::<usize>().ok())
1040 .unwrap_or(1536)
1041 << 20
1042 });
1043 let sz = f8.bytes.len();
1044 if FP8_SPENT.fetch_add(sz, Ordering::Relaxed) + sz <= budget {
1045 let blk = match f8.blk {
1050 Some(g) => Some(Fp8BlockScales {
1051 scales: e.htod(&g.scales)?,
1052 rows: g.rows,
1053 cols: g.cols,
1054 }),
1055 None => None,
1056 };
1057 Some(Fp8Weight {
1058 bytes: e.htod_bytes(&f8.bytes)?,
1059 scale: f8.scale,
1060 blk,
1061 })
1062 } else {
1063 FP8_SPENT.fetch_sub(sz, Ordering::Relaxed);
1064 None
1065 }
1066 }
1067 _ => None,
1068 }
1069 } else {
1070 None
1071 };
1072 Ok(GpuTensor::Quant {
1073 bytes,
1074 qtype: qt,
1075 row_bytes,
1076 ne: v.ne.clone(),
1077 scale,
1078 rp,
1079 #[cfg(memra_cutlass)]
1080 cutlass,
1081 fp8,
1082 blk: None,
1083 rp4: None,
1084 f16: None,
1085 })
1086 }
1087 None => {
1088 let n: u64 = v.ne.iter().product();
1089 if full_prec_enabled() || crate::Engine::bf16_mmv_on() {
1101 let threshold = if full_prec_enabled() {
1108 1_000_000
1109 } else {
1110 2_000_000
1111 };
1112 if v.ggml_type == GgmlType::BF16 && v.ne.len() == 2 && n >= threshold {
1113 let data = e.htod_bytes(&v.bytes)?; eprintln!(
1124 "[bf16-mmv] RESIDENT {name} ne={:?} n={n} admit={}",
1125 v.ne,
1126 if full_prec_enabled() {
1127 "full_prec"
1128 } else {
1129 "bf16_mmv"
1130 }
1131 );
1132 return Ok(GpuTensor::FloatBf16 {
1133 data,
1134 ne: v.ne.clone(),
1135 });
1136 }
1137 if full_prec_enabled() {
1138 let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n as usize);
1139 return Ok(GpuTensor::Float {
1140 data: e.htod(&f32v)?,
1141 ne: v.ne.clone(),
1142 });
1143 }
1144 }
1145 let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n as usize);
1146 if v.ne.len() == 2
1153 && v.ne[0].is_multiple_of(32)
1154 && (name.ends_with("ssm_beta.weight") || name.ends_with("ssm_alpha.weight")
1155 || name.ends_with("per_layer_model_proj.weight"))
1161 {
1162 let q8 = memra_gguf::nvfp4_repack::f32_to_q8_0(&f32v);
1163 return GpuTensor::from_quant_bytes(
1164 e,
1165 &q8,
1166 GgmlType::Q8_0,
1167 v.ne[0],
1168 v.ne[1],
1169 1.0,
1170 );
1171 }
1172 if v.ne.len() == 2 && v.ne[0] >= 16 && v.ne[1] >= 16 && !float_2d_audited(name) {
1182 warn_float_2d_once(name, &v.ne, v.ggml_type);
1183 }
1184 Ok(GpuTensor::Float {
1186 data: e.htod(&f32v)?,
1187 ne: v.ne.clone(),
1188 })
1189 }
1190 }
1191 }
1192
1193 pub fn from_quant_bytes(
1197 e: &Engine,
1198 bytes: &[u8],
1199 ty: GgmlType,
1200 ne0: u64,
1201 ne1: u64,
1202 scale: f32,
1203 ) -> Result<Self, Box<dyn std::error::Error>> {
1204 let qt = match ty {
1205 GgmlType::Q8_0 => QT_Q8_0,
1206 GgmlType::Q4_K => QT_Q4_K,
1207 GgmlType::Q6_K => QT_Q6_K,
1208 GgmlType::Q5_K => QT_Q5_K,
1209 GgmlType::Q3_K => QT_Q3_K,
1210 GgmlType::IQ4_XS => QT_IQ4_XS,
1211 GgmlType::IQ3_S => QT_IQ3_S,
1212 GgmlType::NVFP4 => QT_NVFP4,
1213 GgmlType::Q4_0 => QT_Q4_0,
1214 other => panic!("from_quant_bytes: unsupported dtype {other:?}"),
1215 };
1216 let row_bytes = bytes.len() / ne1 as usize;
1217 let rp = qt == QT_NVFP4
1220 && ne0.is_multiple_of(64)
1221 && row_bytes.is_multiple_of(36)
1222 && rp_enabled();
1223 let dev = if rp {
1224 e.htod_bytes(&repack_nvfp4_split(bytes, ne1 as usize))?
1225 } else {
1226 e.htod_bytes(bytes)?
1227 };
1228 Ok(GpuTensor::Quant {
1229 bytes: dev,
1230 qtype: qt,
1231 row_bytes,
1232 ne: vec![ne0, ne1],
1233 scale,
1234 rp,
1235 #[cfg(memra_cutlass)]
1236 cutlass: None,
1237 fp8: None,
1238 blk: None,
1239 f16: None,
1240 rp4: None,
1241 })
1242 }
1243
1244 pub fn load_opt(
1245 e: &Engine,
1246 g: &GgufFile,
1247 name: &str,
1248 ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
1249 Self::load_opt_from_source(e, &GgufSource(g), name)
1250 }
1251
1252 pub fn load_opt_from_source(
1253 e: &Engine,
1254 src: &dyn TensorSource,
1255 name: &str,
1256 ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
1257 if src.has(name) {
1258 Ok(Some(Self::load_from_source(e, src, name)?))
1259 } else {
1260 Ok(None)
1261 }
1262 }
1263
1264 pub fn float_data(&self) -> &CudaSlice<f32> {
1266 match self {
1267 GpuTensor::Float { data, .. } => data,
1268 GpuTensor::Quant { .. } => panic!("expected float tensor (norm), got quantized"),
1269 GpuTensor::FloatBf16 { .. } => {
1270 panic!("expected f32 float tensor (norm), got bf16-resident matmul weight")
1271 }
1272 }
1273 }
1274}
1275
1276pub struct Layer {
1277 pub attn_norm: GpuTensor,
1278 pub wq: GpuTensor,
1279 pub wk: GpuTensor,
1280 pub wv: GpuTensor,
1281 pub wo: GpuTensor,
1282 pub q_norm: Option<GpuTensor>,
1283 pub k_norm: Option<GpuTensor>,
1284 pub ffn_norm: GpuTensor,
1285 pub ffn: crate::hybrid::Ffn,
1288}
1289
1290pub struct EmbedHost {
1292 pub raw: Vec<u8>,
1293 pub ggml_type: GgmlType,
1294 pub n_embd: usize,
1295}
1296impl EmbedHost {
1297 pub fn from_gguf(g: &GgufFile, name: &str) -> Self {
1298 Self::from_source(&GgufSource(g), name)
1299 }
1300 pub fn from_source(src: &dyn TensorSource, name: &str) -> Self {
1301 let v = src
1302 .find(name)
1303 .unwrap_or_else(|| panic!("missing embed {name}"));
1304 EmbedHost {
1305 raw: v.bytes.to_vec(),
1306 ggml_type: v.ggml_type,
1307 n_embd: v.ne[0] as usize,
1308 }
1309 }
1310 pub fn qt_and_row_bytes(&self, n_embd: usize) -> (i32, usize) {
1313 let (blk, tsize) = self.ggml_type.block_and_type_size();
1314 let row_bytes = (n_embd as u64 / blk * tsize) as usize;
1315 let qt = match self.ggml_type {
1316 GgmlType::Q8_0 => QT_Q8_0,
1317 GgmlType::Q4_K => QT_Q4_K,
1318 GgmlType::Q6_K => QT_Q6_K,
1319 GgmlType::Q5_K => QT_Q5_K,
1320 GgmlType::Q3_K => QT_Q3_K,
1321 GgmlType::IQ4_XS => QT_IQ4_XS,
1322 GgmlType::IQ3_S => QT_IQ3_S,
1323 GgmlType::NVFP4 => QT_NVFP4,
1324 GgmlType::F32 => QT_F32,
1325 GgmlType::BF16 => QT_BF16,
1328 other => panic!("embed_gather: unsupported dtype {other:?}"),
1329 };
1330 (qt, row_bytes)
1331 }
1332
1333 pub fn rows(&self, n_embd: usize) -> usize {
1336 let (blk, tsize) = self.ggml_type.block_and_type_size();
1337 let row_bytes = (n_embd as u64 / blk * tsize) as usize;
1338 self.raw.len().checked_div(row_bytes).unwrap_or(0)
1339 }
1340
1341 pub fn try_gather(&self, n_embd: usize, tokens: &[u32]) -> Result<Vec<f32>, String> {
1355 let (blk, tsize) = self.ggml_type.block_and_type_size();
1356 let row_bytes = (n_embd as u64 / blk * tsize) as usize;
1357 let rows = self.rows(n_embd);
1358 let mut x = vec![0f32; tokens.len() * n_embd];
1359 for (ti, &tok) in tokens.iter().enumerate() {
1360 if tok as usize >= rows {
1361 return Err(format!(
1362 "embed gather: token id {tok} at position {ti} is outside this table's {rows} rows ({} raw bytes / {row_bytes} B per row, dtype {:?}). An out-of-range id is produced UPSTREAM — corrupt logits, a sampler reading a stale or non-finite row, or a tokenizer/vocab mismatch — so fix it there; this refusal exists so the worker does not die on the slice",
1363 self.raw.len(),
1364 self.ggml_type,
1365 ));
1366 }
1367 let off = tok as usize * row_bytes;
1368 let row = dequant::dequantize(self.ggml_type, &self.raw[off..off + row_bytes], n_embd);
1369 x[ti * n_embd..ti * n_embd + n_embd].copy_from_slice(&row);
1370 }
1371 Ok(x)
1372 }
1373
1374 pub fn gather(&self, n_embd: usize, tokens: &[u32]) -> Vec<f32> {
1377 self.try_gather(n_embd, tokens)
1378 .unwrap_or_else(|err| panic!("{err}"))
1379 }
1380}
1381
1382pub struct Model {
1383 pub cfg: ModelConfig,
1384 pub embd: EmbedHost,
1385 pub output_norm: GpuTensor,
1386 pub output: GpuTensor,
1387 pub layers: Vec<Layer>,
1388}
1389
1390impl Model {
1391 pub fn load_dense(e: &Engine, g: &GgufFile) -> Result<Self, Box<dyn std::error::Error>> {
1394 Self::load_dense_from_source(e, &GgufSource(g))
1395 }
1396
1397 pub fn load_dense_from_source(
1401 e: &Engine,
1402 src: &dyn TensorSource,
1403 ) -> Result<Self, Box<dyn std::error::Error>> {
1404 let cfg = src.try_config().map_err(std::io::Error::other)?;
1405 let plan = match memra_gguf::model_packs::for_config(&cfg) {
1406 Some(pack) => pack.compile_plan(&cfg)?,
1407 None => memra_gguf::model_plan::ModelPlan::compile(&cfg)?,
1408 };
1409 if plan.layers.iter().any(|layer| {
1410 !matches!(
1411 layer.attention,
1412 memra_gguf::model_plan::AttentionPlan::Full(_)
1413 )
1414 }) {
1415 return Err("plain executor requires full-attention ModelPlan layers".into());
1416 }
1417 crate::KV_FP8_FORCE.store(0, std::sync::atomic::Ordering::Relaxed);
1424
1425 let embd = EmbedHost::from_source(src, "token_embd.weight");
1426 let output_norm = GpuTensor::load_from_source(e, src, "output_norm.weight")?;
1427 let output = if src.has("output.weight") {
1429 GpuTensor::load_from_source(e, src, "output.weight")?
1430 } else {
1431 GpuTensor::load_from_source(e, src, "token_embd.weight")?
1432 };
1433 let mut resident = crate::hybrid::ResidentPlan::unsharded(e, src, &cfg);
1434 let mut step_runtimes = crate::hybrid::StepParallelRuntimeRegistry::default();
1435
1436 let mut layers = Vec::with_capacity(plan.layers.len());
1437 for (il, layer_plan) in plan.layers.iter().enumerate() {
1438 let il = il as u32;
1439 let p = |s: &str| format!("blk.{il}.{s}");
1440 let ffn = crate::hybrid::load_ffn(
1441 e,
1442 src,
1443 &cfg,
1444 &layer_plan.mlp,
1445 il,
1446 None,
1447 &mut resident,
1448 &mut step_runtimes,
1449 )?;
1450 layers.push(Layer {
1451 attn_norm: GpuTensor::load_from_source(e, src, &p("attn_norm.weight"))?,
1452 wq: GpuTensor::load_from_source(e, src, &p("attn_q.weight"))?,
1453 wk: GpuTensor::load_from_source(e, src, &p("attn_k.weight"))?,
1454 wv: GpuTensor::load_from_source(e, src, &p("attn_v.weight"))?,
1455 wo: GpuTensor::load_from_source(e, src, &p("attn_output.weight"))?,
1456 q_norm: GpuTensor::load_opt_from_source(e, src, &p("attn_q_norm.weight"))?,
1457 k_norm: GpuTensor::load_opt_from_source(e, src, &p("attn_k_norm.weight"))?,
1458 ffn_norm: GpuTensor::load_from_source(e, src, &p("ffn_norm.weight"))?,
1459 ffn,
1460 });
1461 }
1462 Ok(Model {
1463 cfg,
1464 embd,
1465 output_norm,
1466 output,
1467 layers,
1468 })
1469 }
1470
1471 pub(crate) fn max_moe_block(&self) -> usize {
1474 use crate::hybrid::Ffn;
1475 let mut mx = 0usize;
1476 for l in &self.layers {
1477 if let Ffn::Moe(m) = &l.ffn {
1478 mx = mx
1479 .max(m.gate_exps.max_expert_bytes())
1480 .max(m.up_exps.max_expert_bytes())
1481 .max(m.down_exps.max_expert_bytes());
1482 }
1483 }
1484 mx
1485 }
1486
1487 pub fn embed_tokens(
1490 &self,
1491 e: &Engine,
1492 tokens: &[u32],
1493 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
1494 let n_embd = self.cfg.n_embd as usize;
1495 let x = self.embd.try_gather(n_embd, tokens)?;
1496 e.htod(&x)
1497 }
1498}
1499
1500pub type TensorMap = HashMap<String, GpuTensor>;
1501
1502pub enum HostBuf {
1521 Paged(Vec<u8>),
1522 Pinned {
1525 slice: std::sync::Arc<cudarc::driver::PinnedHostSlice<u8>>,
1526 base: *const u8,
1527 len: usize,
1528 },
1529 PinnedAlias {
1532 owner: std::sync::Arc<HostBuf>,
1533 base: *const u8,
1534 len: usize,
1535 },
1536 Mmap {
1542 map: std::sync::Arc<memmap2::Mmap>,
1543 file: std::sync::Arc<std::fs::File>,
1546 off: usize,
1548 len: usize,
1549 },
1550}
1551unsafe impl Send for HostBuf {}
1556unsafe impl Sync for HostBuf {}
1557impl HostBuf {
1558 #[inline]
1559 pub fn as_bytes(&self) -> &[u8] {
1560 match self {
1561 HostBuf::Paged(v) => v.as_slice(),
1562 HostBuf::Pinned { base, len, .. } => unsafe { std::slice::from_raw_parts(*base, *len) },
1566 HostBuf::PinnedAlias { base, len, .. } => unsafe {
1567 std::slice::from_raw_parts(*base, *len)
1568 },
1569 HostBuf::Mmap { map, off, len, .. } => &map[*off..*off + *len],
1571 }
1572 }
1573 #[inline]
1574 #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize {
1576 match self {
1577 HostBuf::Paged(v) => v.len(),
1578 HostBuf::Pinned { len, .. } => *len,
1579 HostBuf::PinnedAlias { len, .. } => *len,
1580 HostBuf::Mmap { len, .. } => *len,
1581 }
1582 }
1583
1584 #[inline]
1589 pub fn advise_willneed(&self, rel_off: usize, len: usize) -> bool {
1590 let HostBuf::Mmap {
1591 map,
1592 off,
1593 len: extent,
1594 ..
1595 } = self
1596 else {
1597 return false;
1598 };
1599 if len == 0 || rel_off > *extent || len > *extent - rel_off {
1600 return false;
1601 }
1602 #[cfg(unix)]
1603 {
1604 map.advise_range(memmap2::Advice::WillNeed, *off + rel_off, len)
1605 .is_ok()
1606 }
1607 #[cfg(not(unix))]
1608 {
1609 let _ = (map, off);
1610 false
1611 }
1612 }
1613
1614 #[inline]
1615 fn expert_source(&self, rel_off: usize, len: usize) -> ExpertSource<'_> {
1616 debug_assert!(rel_off <= self.len() && len <= self.len() - rel_off);
1617 match self {
1618 HostBuf::Mmap { map, file, off, .. } => {
1619 let offset = *off + rel_off;
1620 ExpertSource::Disk {
1621 file,
1622 offset: offset as u64,
1623 len,
1624 fallback: &map[offset..offset + len],
1625 keepalive: ExpertKeepalive::Mmap(map.clone()),
1626 }
1627 }
1628 HostBuf::Pinned { slice, .. } => ExpertSource::Memory {
1629 bytes: &self.as_bytes()[rel_off..rel_off + len],
1630 keepalive: Some(ExpertKeepalive::Pinned(slice.clone())),
1631 },
1632 HostBuf::PinnedAlias { owner, .. } => ExpertSource::Memory {
1633 bytes: &self.as_bytes()[rel_off..rel_off + len],
1634 keepalive: Some(ExpertKeepalive::Buffer(owner.clone())),
1635 },
1636 HostBuf::Paged(_) => ExpertSource::Memory {
1637 bytes: &self.as_bytes()[rel_off..rel_off + len],
1638 keepalive: None,
1641 },
1642 }
1643 }
1644}
1645
1646#[allow(dead_code)]
1649pub(crate) enum ExpertKeepalive {
1650 Pinned(std::sync::Arc<cudarc::driver::PinnedHostSlice<u8>>),
1651 Buffer(std::sync::Arc<HostBuf>),
1652 Mmap(std::sync::Arc<memmap2::Mmap>),
1653}
1654
1655pub(crate) enum ExpertSource<'a> {
1658 Memory {
1659 bytes: &'a [u8],
1660 keepalive: Option<ExpertKeepalive>,
1661 },
1662 Disk {
1663 file: &'a std::sync::Arc<std::fs::File>,
1664 offset: u64,
1665 len: usize,
1666 fallback: &'a [u8],
1667 keepalive: ExpertKeepalive,
1668 },
1669}
1670
1671#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1683pub struct ExpertLayout {
1684 pub offset: usize,
1685 pub len: usize,
1686 pub qtype: i32,
1687 pub row_bytes: usize,
1688}
1689
1690fn staged_expert_qtype(ty: GgmlType) -> Option<i32> {
1691 Some(match ty {
1692 GgmlType::Q8_0 => QT_Q8_0,
1693 GgmlType::Q2_K => QT_Q2_K,
1694 GgmlType::Q4_K => QT_Q4_K,
1695 GgmlType::Q6_K => QT_Q6_K,
1696 GgmlType::Q5_K => QT_Q5_K,
1697 GgmlType::Q3_K => QT_Q3_K,
1698 GgmlType::IQ4_XS => QT_IQ4_XS,
1699 GgmlType::IQ3_S => QT_IQ3_S,
1700 GgmlType::NVFP4 => QT_NVFP4,
1701 GgmlType::F32 => QT_F32,
1702 GgmlType::BF16 => QT_BF16,
1703 _ => return None,
1704 })
1705}
1706
1707fn staged_expert_row_bytes(ty: GgmlType, in_f: usize) -> Option<usize> {
1708 staged_expert_qtype(ty)?;
1709 let (block, type_size) = ty.block_and_type_size();
1710 assert_eq!(
1711 in_f as u64 % block,
1712 0,
1713 "expert row width {in_f} is not divisible by {ty:?} block {block}"
1714 );
1715 Some((in_f as u64 / block * type_size) as usize)
1716}
1717
1718fn find_expert_disk_strict(
1719 src: &dyn TensorSource,
1720 name: &str,
1721) -> Result<Option<DiskExtent>, Box<dyn std::error::Error>> {
1722 if let Some(extent) = src.find_expert_disk(name) {
1723 return Ok(Some(extent));
1724 }
1725 if src.find_expert_mmap(name).is_some() {
1726 return Err(std::io::Error::new(
1727 std::io::ErrorKind::InvalidData,
1728 format!(
1729 "expert tensor {name} exposes legacy find_expert_mmap without find_expert_disk; \
1730 disk-backed expert loading requires a retained Arc<File>"
1731 ),
1732 )
1733 .into());
1734 }
1735 Ok(None)
1736}
1737
1738pub struct HostExps {
1739 pub bytes: HostBuf, pub tiers: Option<Vec<HostBuf>>,
1745 pub qtype: i32, pub in_f: usize, pub out_f: usize, pub n_expert: usize, pub row_bytes: usize, pub expert_stride: usize, pub layouts: Option<Vec<ExpertLayout>>,
1755 pub macros: Option<Vec<f32>>,
1760 pub fp8_blk: Option<HostExpertFp8BlockScales>,
1763}
1764
1765pub struct HostExpertFp8BlockScales {
1766 pub scales: Vec<f32>,
1767 pub rows: usize,
1768 pub cols: usize,
1769 pub expert_stride: usize,
1770}
1771
1772impl HostExps {
1773 pub fn load(e: &Engine, g: &GgufFile, name: &str) -> Result<Self, Box<dyn std::error::Error>> {
1777 Self::load_stacked_from_source(e, &GgufSource(g), name)
1778 }
1779
1780 pub fn load_stacked_split_from_source(
1787 e: &Engine,
1788 src: &dyn TensorSource,
1789 name: &str,
1790 row0: usize,
1791 row1: usize,
1792 ) -> Result<Self, Box<dyn std::error::Error>> {
1793 let t = src
1794 .find(name)
1795 .unwrap_or_else(|| panic!("missing exps tensor {name}"));
1796 assert_eq!(t.ne.len(), 3, "{name} is not 3D (ne={:?})", t.ne);
1797 let qtype = match t.ggml_type {
1798 GgmlType::Q8_0 => QT_Q8_0,
1799 GgmlType::Q4_K => QT_Q4_K,
1800 GgmlType::Q6_K => QT_Q6_K,
1801 GgmlType::Q5_K => QT_Q5_K,
1802 GgmlType::Q3_K => QT_Q3_K,
1803 GgmlType::IQ4_XS => QT_IQ4_XS,
1804 GgmlType::IQ3_S => QT_IQ3_S,
1805 GgmlType::NVFP4 => QT_NVFP4,
1806 GgmlType::Q4_0 => QT_Q4_0,
1807 other => panic!("exps {name} unsupported quant {other:?}"),
1808 };
1809 let raw: &[u8] = &t.bytes;
1810 let in_f = t.ne[0] as usize;
1811 let out_full = t.ne[1] as usize;
1812 let n_expert = t.ne[2] as usize;
1813 let full_stride = raw.len() / n_expert;
1814 let row_bytes = raw.len() / (out_full * n_expert);
1815 assert_eq!(full_stride, out_full * row_bytes, "{name} stride mismatch");
1816 let out_f = row1 - row0;
1817 let expert_stride = out_f * row_bytes;
1818 let mut buf = vec![0u8; n_expert * expert_stride];
1819 for ex in 0..n_expert {
1820 let s0 = ex * full_stride + row0 * row_bytes;
1821 buf[ex * expert_stride..(ex + 1) * expert_stride]
1822 .copy_from_slice(&raw[s0..s0 + expert_stride]);
1823 }
1824 let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
1825 || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
1826 let bytes = if pinned {
1827 let mut pn = unsafe { e.ctx().alloc_pinned::<u8>(buf.len())? };
1828 {
1829 let dst = pn.as_mut_slice()?;
1830 dst.copy_from_slice(&buf);
1831 }
1832 let base = pn.as_ptr()?;
1833 let len = buf.len();
1834 HostBuf::Pinned {
1835 slice: std::sync::Arc::new(pn),
1836 base,
1837 len,
1838 }
1839 } else {
1840 HostBuf::Paged(buf)
1841 };
1842 Ok(HostExps {
1843 bytes,
1844 tiers: None,
1845 qtype,
1846 in_f,
1847 out_f,
1848 n_expert,
1849 row_bytes,
1850 expert_stride,
1851 layouts: None,
1852 macros: None,
1853 fp8_blk: None,
1854 })
1855 }
1856
1857 fn stacked_macros(src: &dyn TensorSource, name: &str) -> Option<Vec<f32>> {
1863 let stem = name.strip_suffix(".weight")?;
1864 let sv = src.find(&format!("{stem}.scale"))?;
1865 if sv.ggml_type != GgmlType::F32 {
1866 return None;
1867 }
1868 let macros: Vec<f32> = sv
1869 .bytes
1870 .chunks_exact(4)
1871 .map(|c| f32::from_le_bytes(c.try_into().unwrap()))
1872 .collect();
1873 if macros.iter().all(|&m| m == 1.0) {
1874 None
1875 } else {
1876 Some(macros)
1877 }
1878 }
1879
1880 fn load_nvfp4_stacked_native(
1888 src: &dyn TensorSource,
1889 name: &str,
1890 ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
1891 let Some(bank) = src.find_nvfp4_stacked_native(name) else {
1892 return Ok(None);
1893 };
1894 let (n_expert, out_f, in_f) = (bank.n_expert, bank.out_f, bank.in_f);
1895 if in_f % 64 != 0 {
1896 return Err(
1897 format!("{name} stacked NVFP4 in_features {in_f} is not 64-aligned").into(),
1898 );
1899 }
1900 let row_bytes = in_f / 64 * 36;
1901 let expert_stride = out_f * row_bytes;
1902 let total = n_expert * expert_stride;
1903 let code_stride = out_f * in_f / 2;
1904 let scale_stride = out_f * in_f / 16;
1905 let macros = bank.macros.clone();
1906 let cache_path = if let Some(dir) = src.st_dir() {
1907 let cache_dir = dir.join(".memra-repack");
1908 ensure_repack_cache_dir(&cache_dir)?;
1909 Some(cache_dir.join(format!(
1910 "{}-stacked-{n_expert}x{out_f}x{in_f}.nvfp4",
1911 name.replace(['.', '/'], "-")
1912 )))
1913 } else {
1914 None
1915 };
1916 let bytes = if let Some(cache) = cache_path.as_ref() {
1917 let fresh = repack_cache_is_fresh(cache, total);
1918 if !fresh {
1919 write_repack_cache(cache, |out| {
1920 for expert in 0..n_expert {
1921 use std::io::Write;
1922 out.write_all(&memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
1923 &bank.codes[expert * code_stride..(expert + 1) * code_stride],
1924 &bank.scales[expert * scale_stride..(expert + 1) * scale_stride],
1925 out_f,
1926 in_f,
1927 ))?;
1928 }
1929 Ok(())
1930 })?;
1931 }
1932 let file = std::sync::Arc::new(open_repack_cache(cache, false)?);
1933 let map = unsafe { memmap2::Mmap::map(file.as_ref())? };
1934 assert_eq!(map.len(), total, "repack cache {cache:?} size mismatch");
1935 let _ = memra_gguf::source::apply_expert_mmap_advice(&map);
1936 memra_gguf::source::populate_expert_slab(&file, total, name);
1937 HostBuf::Mmap {
1938 map: std::sync::Arc::new(map),
1939 file,
1940 off: 0,
1941 len: total,
1942 }
1943 } else {
1944 let mut buf: Vec<u8> = Vec::with_capacity(total);
1945 for expert in 0..n_expert {
1946 buf.extend_from_slice(&memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
1947 &bank.codes[expert * code_stride..(expert + 1) * code_stride],
1948 &bank.scales[expert * scale_stride..(expert + 1) * scale_stride],
1949 out_f,
1950 in_f,
1951 ));
1952 }
1953 assert_eq!(buf.len(), total);
1954 HostBuf::Paged(buf)
1955 };
1956 let all_one = macros.iter().all(|&value| value == 1.0);
1957 Ok(Some(HostExps {
1958 bytes,
1959 tiers: None,
1960 qtype: QT_NVFP4,
1961 in_f,
1962 out_f,
1963 n_expert,
1964 row_bytes,
1965 expert_stride,
1966 layouts: None,
1967 macros: if all_one { None } else { Some(macros) },
1968 fp8_blk: None,
1969 }))
1970 }
1971
1972 fn load_fp8_stacked_native_with_policy(
1973 src: &dyn TensorSource,
1974 name: &str,
1975 native_enabled: bool,
1976 ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
1977 let Some(f8) = src.find_fp8_stacked_native(name) else {
1978 return Ok(None);
1979 };
1980 if f8.scale_rows != f8.out_f.div_ceil(128) || f8.scale_cols != f8.in_f.div_ceil(128) {
1981 return Err(format!(
1982 "{name} FP8 scale geometry mismatch: got {}x{}, expected {}x{}",
1983 f8.scale_rows,
1984 f8.scale_cols,
1985 f8.out_f.div_ceil(128),
1986 f8.in_f.div_ceil(128)
1987 )
1988 .into());
1989 }
1990 if f8.bytes.iter().any(|code| code & 0x7f == 0x7f) {
1991 return Err(format!("{name} FP8 code slab contains non-finite E4M3 values").into());
1992 }
1993 let scale_stride = f8.scale_rows * f8.scale_cols;
1994 if !native_enabled {
1995 if f8.in_f % 32 != 0 {
1996 return Err(format!(
1997 "{name} FP8 rollback requires an input width divisible by 32, got {}",
1998 f8.in_f
1999 )
2000 .into());
2001 }
2002 let mut q8 = Vec::new();
2003 for expert in 0..f8.n_expert {
2004 let mut data = Vec::with_capacity(f8.out_f * f8.in_f);
2005 for output in 0..f8.out_f {
2006 let row = (expert * f8.out_f + output) * f8.in_f;
2007 for input in 0..f8.in_f {
2008 let scale = f8.scales
2009 [expert * scale_stride + (output / 128) * f8.scale_cols + input / 128];
2010 data.push(
2011 memra_gguf::nvfp4_repack::fp8_e4m3_to_f32(f8.bytes[row + input])
2012 * scale,
2013 );
2014 }
2015 }
2016 q8.extend_from_slice(&memra_gguf::nvfp4_repack::f32_to_q8_0(&data));
2017 }
2018 let row_bytes = f8.in_f / 32 * 34;
2019 let expert_stride = f8.out_f * row_bytes;
2020 assert_eq!(q8.len(), f8.n_expert * expert_stride);
2021 return Ok(Some(HostExps {
2022 bytes: HostBuf::Paged(q8),
2023 tiers: None,
2024 qtype: QT_Q8_0,
2025 in_f: f8.in_f,
2026 out_f: f8.out_f,
2027 n_expert: f8.n_expert,
2028 row_bytes,
2029 expert_stride,
2030 layouts: None,
2031 macros: None,
2032 fp8_blk: None,
2033 }));
2034 }
2035
2036 assert_eq!(
2037 f8.bytes.len(),
2038 f8.n_expert * f8.out_f * f8.in_f,
2039 "{name} FP8 code slab length mismatch"
2040 );
2041 assert_eq!(
2042 f8.scales.len(),
2043 f8.n_expert * scale_stride,
2044 "{name} FP8 scale slab length mismatch"
2045 );
2046 let expert_stride = f8.out_f * f8.in_f;
2047 let bytes = match find_expert_disk_strict(src, name)? {
2048 Some(extent) => {
2049 if extent.len != f8.bytes.len() {
2050 return Err(format!(
2051 "{name} FP8 mmap length mismatch: extent={} tensor={}",
2052 extent.len,
2053 f8.bytes.len()
2054 )
2055 .into());
2056 }
2057 let off = usize::try_from(extent.offset).map_err(|_| {
2058 format!(
2059 "{name} FP8 mmap offset {} does not fit usize",
2060 extent.offset
2061 )
2062 })?;
2063 HostBuf::Mmap {
2064 map: extent.map,
2065 file: extent.file,
2066 off,
2067 len: extent.len,
2068 }
2069 }
2070 None => HostBuf::Paged(f8.bytes.to_vec()),
2071 };
2072 Ok(Some(HostExps {
2073 bytes,
2074 tiers: None,
2075 qtype: crate::QT_F8_E4M3_BLK,
2076 in_f: f8.in_f,
2077 out_f: f8.out_f,
2078 n_expert: f8.n_expert,
2079 row_bytes: f8.in_f,
2080 expert_stride,
2081 layouts: None,
2082 macros: None,
2083 fp8_blk: Some(HostExpertFp8BlockScales {
2084 scales: f8.scales,
2085 rows: f8.scale_rows,
2086 cols: f8.scale_cols,
2087 expert_stride: scale_stride,
2088 }),
2089 }))
2090 }
2091
2092 pub fn load_stacked_from_source(
2093 e: &Engine,
2094 src: &dyn TensorSource,
2095 name: &str,
2096 ) -> Result<Self, Box<dyn std::error::Error>> {
2097 if let Some(exps) = Self::load_fp8_stacked_native_with_policy(
2098 src,
2099 name,
2100 crate::fp8_ffi::st_e4m3_blk_enabled(),
2101 )? {
2102 return Ok(exps);
2103 }
2104 if let Some(exps) = Self::load_nvfp4_stacked_native(src, name)? {
2105 return Ok(exps);
2106 }
2107
2108 let t = src
2109 .find(name)
2110 .unwrap_or_else(|| panic!("missing exps tensor {name}"));
2111 assert_eq!(
2112 t.ne.len(),
2113 3,
2114 "{name} is not a 3D stacked-expert tensor (ne={:?})",
2115 t.ne
2116 );
2117 if let Some(DiskExtent {
2127 map,
2128 file,
2129 offset,
2130 len,
2131 }) = find_expert_disk_strict(src, name)?
2132 {
2133 let off = usize::try_from(offset)
2134 .map_err(|_| format!("{name} disk offset {offset} does not fit usize"))?;
2135 let qtype = match t.ggml_type {
2136 GgmlType::Q8_0 => QT_Q8_0,
2137 GgmlType::Q4_K => QT_Q4_K,
2138 GgmlType::Q6_K => QT_Q6_K,
2139 GgmlType::Q5_K => QT_Q5_K,
2140 GgmlType::Q3_K => QT_Q3_K,
2141 GgmlType::IQ4_XS => QT_IQ4_XS,
2142 GgmlType::IQ3_S => QT_IQ3_S,
2143 GgmlType::NVFP4 => QT_NVFP4,
2144 GgmlType::Q4_0 => QT_Q4_0,
2145 other => panic!("exps {name} unsupported quant {other:?}"),
2146 };
2147 let in_f = t.ne[0] as usize;
2148 let out_f = t.ne[1] as usize;
2149 let n_expert = t.ne[2] as usize;
2150 let expert_stride = len / n_expert;
2151 let row_bytes = len / (out_f * n_expert);
2152 assert_eq!(
2153 expert_stride,
2154 out_f * row_bytes,
2155 "{name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}"
2156 );
2157 assert_eq!(
2158 len,
2159 n_expert * expert_stride,
2160 "{name} mmap len != n_expert*stride"
2161 );
2162 return Ok(HostExps {
2163 bytes: HostBuf::Mmap {
2164 map,
2165 file,
2166 off,
2167 len,
2168 },
2169 tiers: None,
2170 qtype,
2171 in_f,
2172 out_f,
2173 n_expert,
2174 row_bytes,
2175 expert_stride,
2176 layouts: None,
2177 macros: Self::stacked_macros(src, name),
2178 fp8_blk: None,
2179 });
2180 }
2181 let raw: &[u8] = &t.bytes;
2182 let qtype = match t.ggml_type {
2184 GgmlType::Q8_0 => QT_Q8_0,
2185 GgmlType::Q4_K => QT_Q4_K,
2186 GgmlType::Q6_K => QT_Q6_K,
2187 GgmlType::Q5_K => QT_Q5_K,
2188 GgmlType::Q3_K => QT_Q3_K,
2189 GgmlType::IQ4_XS => QT_IQ4_XS,
2190 GgmlType::IQ3_S => QT_IQ3_S,
2191 GgmlType::NVFP4 => QT_NVFP4,
2192 GgmlType::Q4_0 => QT_Q4_0,
2193 other => panic!("exps {name} unsupported quant {other:?}"),
2194 };
2195 let in_f = t.ne[0] as usize;
2196 let out_f = t.ne[1] as usize;
2197 let n_expert = t.ne[2] as usize;
2198 let expert_stride = raw.len() / n_expert;
2201 let row_bytes = raw.len() / (out_f * n_expert);
2202 assert_eq!(
2204 expert_stride,
2205 out_f * row_bytes,
2206 "{name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}"
2207 );
2208
2209 let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
2210 || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
2211 let bytes = if pinned {
2212 let mut p = unsafe { e.ctx().alloc_pinned::<u8>(raw.len())? };
2214 {
2215 let dst = p.as_mut_slice()?;
2216 dst.copy_from_slice(raw);
2217 }
2218 let base = p.as_ptr()?; let len = raw.len();
2220 HostBuf::Pinned {
2221 slice: std::sync::Arc::new(p),
2222 base,
2223 len,
2224 }
2225 } else {
2226 HostBuf::Paged(raw.to_vec())
2227 };
2228 Ok(HostExps {
2229 bytes,
2230 tiers: None,
2231 qtype,
2232 in_f,
2233 out_f,
2234 n_expert,
2235 row_bytes,
2236 expert_stride,
2237 layouts: None,
2238 macros: Self::stacked_macros(src, name),
2239 fp8_blk: None,
2240 })
2241 }
2242
2243 pub fn load_tiered(
2252 e: &Engine,
2253 g: &GgufFile,
2254 name: &str,
2255 ctx: &mut crate::spill::SpillCtx,
2256 ) -> Result<Self, Box<dyn std::error::Error>> {
2257 let t = g
2258 .find(name)
2259 .unwrap_or_else(|| panic!("missing exps tensor {name}"));
2260 assert_eq!(
2261 t.ne.len(),
2262 3,
2263 "{name} is not a 3D stacked-expert tensor (ne={:?})",
2264 t.ne
2265 );
2266 let raw = g.tensor_data(t);
2267 let qtype = match t.ggml_type {
2268 GgmlType::Q8_0 => QT_Q8_0,
2269 GgmlType::Q4_K => QT_Q4_K,
2270 GgmlType::Q6_K => QT_Q6_K,
2271 GgmlType::Q5_K => QT_Q5_K,
2272 GgmlType::Q3_K => QT_Q3_K,
2273 GgmlType::IQ4_XS => QT_IQ4_XS,
2274 GgmlType::IQ3_S => QT_IQ3_S,
2275 GgmlType::NVFP4 => QT_NVFP4,
2276 GgmlType::Q4_0 => QT_Q4_0,
2277 other => panic!("exps {name} unsupported quant {other:?}"),
2278 };
2279 let in_f = t.ne[0] as usize;
2280 let out_f = t.ne[1] as usize;
2281 let n_expert = t.ne[2] as usize;
2282 let expert_stride = raw.len() / n_expert;
2283 let row_bytes = raw.len() / (out_f * n_expert);
2284 assert_eq!(
2285 expert_stride,
2286 out_f * row_bytes,
2287 "{name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}"
2288 );
2289
2290 let (file_start, _file_end) = g.tensor_file_range(t);
2294
2295 let mut tiers = Vec::with_capacity(n_expert);
2298 for ex in 0..n_expert {
2299 let blk = &raw[ex * expert_stride..(ex + 1) * expert_stride];
2300 let file_off = file_start + ex * expert_stride;
2301 tiers.push(crate::spill::place_expert(ctx, e, blk, file_off, t.shard)?);
2302 }
2303 Ok(HostExps {
2304 bytes: HostBuf::Paged(Vec::new()), tiers: Some(tiers),
2306 qtype,
2307 in_f,
2308 out_f,
2309 n_expert,
2310 row_bytes,
2311 expert_stride,
2312 layouts: None,
2313 macros: Self::stacked_macros(&GgufSource(g), name),
2314 fp8_blk: None,
2315 })
2316 }
2317
2318 pub fn load_from_source(
2333 e: &Engine,
2334 src: &dyn TensorSource,
2335 ggml_exps_name: &str,
2336 n_expert: usize,
2337 ) -> Result<Self, Box<dyn std::error::Error>> {
2338 let rest = ggml_exps_name
2340 .strip_prefix("blk.")
2341 .unwrap_or_else(|| panic!("not a blk.* name: {ggml_exps_name}"));
2342 let (il_s, suffix) = rest.split_once('.').unwrap();
2343 let il: u32 = il_s.parse().unwrap();
2344 let proj = match suffix {
2345 "ffn_gate_exps.weight" => "gate",
2346 "ffn_up_exps.weight" => "up",
2347 "ffn_down_exps.weight" => "down",
2348 other => panic!("not a *_exps suffix: {other}"),
2349 };
2350
2351 let mut signatures = Vec::with_capacity(n_expert);
2355 let active = src.active_experts(il);
2356 for ex in 0..n_expert {
2357 if active.is_some_and(|mask| !mask[ex]) {
2358 signatures.push((i32::MIN, 0));
2359 continue;
2360 }
2361 let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
2362 if let Some(nv) = src.find_nvfp4_native(&name) {
2363 signatures.push((QT_NVFP4, nv.in_f / 64 * 36));
2364 } else {
2365 let v = src
2366 .find(&name)
2367 .unwrap_or_else(|| panic!("missing expert tensor {name}"));
2368 let in_f = v.ne[0] as usize;
2369 signatures.push(match staged_expert_row_bytes(v.ggml_type, in_f) {
2370 Some(row_bytes) => (staged_expert_qtype(v.ggml_type).unwrap(), row_bytes),
2371 None => (QT_F32, in_f * 4),
2372 });
2373 }
2374 }
2375 let mixed_layout = signatures.windows(2).any(|pair| pair[0] != pair[1]);
2376 if src.preserve_expert_encodings()
2377 && !mixed_layout
2378 && let Some(uniform) = Self::load_uniform_mmap_from_source(src, il, proj, n_expert)?
2379 {
2380 return Ok(uniform);
2381 }
2382 if src.preserve_expert_encodings() || mixed_layout {
2383 return Self::load_mixed_from_source(src, il, proj, n_expert);
2384 }
2385
2386 {
2393 let name0 = format!("blk.{il}.ffn_{proj}_exps.0.weight");
2394 if let Some(nv0) = src.find_nvfp4_native(&name0) {
2395 let (in_f, out_f) = (nv0.in_f, nv0.out_f);
2396 let row_bytes = in_f / 64 * 36;
2397 let expert_stride = out_f * row_bytes;
2398 let disk = std::env::var("MEMRA_ST_REPACK_DISK")
2405 .map(|v| v != "0")
2406 .unwrap_or(true)
2407 && src.st_dir().is_some();
2408 let cache_path = if let Some(dir) = src.st_dir() {
2409 let cache_dir = dir.join(".memra-repack");
2410 ensure_repack_cache_dir(&cache_dir)?;
2411 Some(cache_dir.join(format!("blk{il}-{proj}-{n_expert}x{out_f}x{in_f}.nvfp4")))
2412 } else {
2413 None
2414 };
2415 let total = n_expert * expert_stride;
2416 let mut macros = vec![1.0f32; n_expert];
2417 let read_macros = |macros: &mut Vec<f32>| {
2418 #[allow(clippy::needless_range_loop)]
2419 for ex in 0..n_expert {
2421 let stem = format!("blk.{il}.ffn_{proj}_exps.{ex}");
2422 if let Some(sv) = src.find(&format!("{stem}.scale")) {
2423 macros[ex] = f32::from_le_bytes(sv.bytes[..4].try_into().unwrap());
2424 }
2425 }
2426 };
2427 let bytes = if disk {
2428 let cp = cache_path.as_ref().unwrap();
2429 let fresh = repack_cache_is_fresh(cp, total);
2430 if !fresh {
2431 write_repack_cache(cp, |out| {
2433 for ex in 0..n_expert {
2434 use std::io::Write;
2435 let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
2436 let nv = src.find_nvfp4_native(&name).unwrap_or_else(|| {
2437 panic!("expert {name} lost NVFP4-native mid-gather")
2438 });
2439 assert_eq!(
2440 (nv.in_f, nv.out_f),
2441 (in_f, out_f),
2442 "expert {ex} dims ({},{}) != expert 0 ({in_f},{out_f})",
2443 nv.in_f,
2444 nv.out_f
2445 );
2446 out.write_all(&memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
2447 nv.wbytes, nv.wscale, out_f, in_f,
2448 ))?;
2449 }
2450 Ok(())
2451 })?;
2452 }
2453 read_macros(&mut macros);
2454 let file = std::sync::Arc::new(open_repack_cache(cp, false)?);
2455 let map = unsafe { memmap2::Mmap::map(file.as_ref())? };
2456 assert_eq!(map.len(), total, "repack cache {cp:?} size mismatch");
2457 let _ = memra_gguf::source::apply_expert_mmap_advice(&map);
2460 memra_gguf::source::populate_expert_slab(
2461 &file,
2462 total,
2463 &format!("blk{il}-{proj}"),
2464 );
2465 let map = std::sync::Arc::new(map);
2466 let tiers = if std::env::var("MEMRA_ST_PINNED")
2479 .map(|v| v == "1")
2480 .unwrap_or(false)
2481 {
2482 static PIN_BUDGET: std::sync::OnceLock<std::sync::Mutex<usize>> =
2483 std::sync::OnceLock::new();
2484 let budget = PIN_BUDGET.get_or_init(|| {
2485 let b = crate::spill::MemBudget::probe(e)
2486 .map(|b| b.free_pinnable_ram)
2487 .unwrap_or(0);
2488 eprintln!("[st-spill] free_pinnable_ram={} MiB", b >> 20);
2489 std::sync::Mutex::new(b)
2490 });
2491 let mut rem = budget.lock().unwrap();
2492 let n_pin = (*rem / expert_stride).min(n_expert);
2496 if n_pin == 0 {
2497 None
2498 } else {
2499 let slab_len = n_pin * expert_stride;
2500 let mut pn = unsafe { e.ctx().alloc_pinned::<u8>(slab_len)? };
2501 {
2502 let dst = pn.as_mut_slice()?;
2503 dst.copy_from_slice(&map[..slab_len]);
2504 }
2505 let base = pn.as_ptr()?;
2506 *rem -= slab_len;
2507 let slab = std::sync::Arc::new(HostBuf::Pinned {
2508 slice: std::sync::Arc::new(pn),
2509 base,
2510 len: slab_len,
2511 });
2512 let mut tiers: Vec<HostBuf> = Vec::with_capacity(n_expert);
2513 for ex in 0..n_expert {
2514 let off = ex * expert_stride;
2515 if ex < n_pin {
2516 tiers.push(HostBuf::PinnedAlias {
2517 owner: slab.clone(),
2518 base: unsafe { base.add(off) },
2519 len: expert_stride,
2520 });
2521 } else {
2522 tiers.push(HostBuf::Mmap {
2523 map: map.clone(),
2524 file: file.clone(),
2525 off,
2526 len: expert_stride,
2527 });
2528 }
2529 }
2530 Some(tiers)
2531 }
2532 } else {
2533 None
2534 };
2535 if let Some(tiers) = tiers {
2536 let all_one = macros.iter().all(|&m| m == 1.0);
2537 return Ok(HostExps {
2538 bytes: HostBuf::Mmap {
2539 map,
2540 file,
2541 off: 0,
2542 len: total,
2543 },
2544 tiers: Some(tiers),
2545 qtype: QT_NVFP4,
2546 in_f,
2547 out_f,
2548 n_expert,
2549 row_bytes,
2550 expert_stride,
2551 layouts: None,
2552 macros: if all_one { None } else { Some(macros) },
2553 fp8_blk: None,
2554 });
2555 }
2556 HostBuf::Mmap {
2557 map,
2558 file,
2559 off: 0,
2560 len: total,
2561 }
2562 } else {
2563 let mut buf: Vec<u8> = Vec::with_capacity(total);
2564 for ex in 0..n_expert {
2565 let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
2566 let nv = src.find_nvfp4_native(&name).unwrap_or_else(|| {
2567 panic!("expert {name} lost NVFP4-native mid-gather")
2568 });
2569 assert_eq!(
2570 (nv.in_f, nv.out_f),
2571 (in_f, out_f),
2572 "expert {ex} dims ({},{}) != expert 0 ({in_f},{out_f})",
2573 nv.in_f,
2574 nv.out_f
2575 );
2576 buf.extend_from_slice(&memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
2577 nv.wbytes, nv.wscale, out_f, in_f,
2578 ));
2579 }
2580 assert_eq!(buf.len(), total);
2581 read_macros(&mut macros);
2582 let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
2583 || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
2584 if pinned {
2585 let mut p = unsafe { e.ctx().alloc_pinned::<u8>(buf.len())? };
2586 {
2587 let dst = p.as_mut_slice()?;
2588 dst.copy_from_slice(&buf);
2589 }
2590 let base = p.as_ptr()?;
2591 let len = buf.len();
2592 HostBuf::Pinned {
2593 slice: std::sync::Arc::new(p),
2594 base,
2595 len,
2596 }
2597 } else {
2598 HostBuf::Paged(buf)
2599 }
2600 };
2601 let all_one = macros.iter().all(|&m| m == 1.0);
2602 return Ok(HostExps {
2603 bytes,
2604 tiers: None,
2605 qtype: QT_NVFP4,
2606 in_f,
2607 out_f,
2608 n_expert,
2609 row_bytes,
2610 expert_stride,
2611 layouts: None,
2612 macros: if all_one { None } else { Some(macros) },
2613 fp8_blk: None,
2614 });
2615 }
2616 }
2617
2618 let mut buf: Vec<u8> = Vec::new();
2620 let mut in_f = 0usize;
2621 let mut out_f = 0usize;
2622 for ex in 0..n_expert {
2623 let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
2625 let v = src
2626 .find(&name)
2627 .unwrap_or_else(|| panic!("missing expert tensor {name}"));
2628 assert_eq!(v.ne.len(), 2, "expert {name} is not 2D (ne={:?})", v.ne);
2629 let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
2630 if ex == 0 {
2631 in_f = cur_in;
2632 out_f = cur_out;
2633 } else {
2634 assert_eq!(
2635 (cur_in, cur_out),
2636 (in_f, out_f),
2637 "expert {ex} dims {:?} != expert 0 [{in_f},{out_f}]",
2638 (cur_in, cur_out)
2639 );
2640 }
2641 let n = cur_in * cur_out;
2644 let f32v = dequant::dequantize(v.ggml_type, &v.bytes, n);
2645 buf.reserve(n * 4);
2646 for f in &f32v {
2647 buf.extend_from_slice(&f.to_le_bytes());
2648 }
2649 }
2650 let row_bytes = in_f * 4; let expert_stride = out_f * row_bytes;
2652 assert_eq!(
2653 buf.len(),
2654 n_expert * expert_stride,
2655 "{ggml_exps_name} gather size {} != n_expert*stride {}",
2656 buf.len(),
2657 n_expert * expert_stride
2658 );
2659 assert_eq!(
2661 expert_stride,
2662 out_f * row_bytes,
2663 "{ggml_exps_name} stride mismatch: stride={expert_stride} out_f={out_f} row_bytes={row_bytes}"
2664 );
2665
2666 let pinned = std::env::var("MEMRA_MOE_PINNED").is_ok()
2668 || std::env::var("MEMRA_MOE_CACHE").as_deref() != Ok("0");
2669 let bytes = if pinned {
2670 let mut p = unsafe { e.ctx().alloc_pinned::<u8>(buf.len())? };
2671 {
2672 let dst = p.as_mut_slice()?;
2673 dst.copy_from_slice(&buf);
2674 }
2675 let base = p.as_ptr()?;
2676 let len = buf.len();
2677 HostBuf::Pinned {
2678 slice: std::sync::Arc::new(p),
2679 base,
2680 len,
2681 }
2682 } else {
2683 HostBuf::Paged(buf)
2684 };
2685 Ok(HostExps {
2686 bytes,
2687 tiers: None,
2688 qtype: QT_F32,
2689 in_f,
2690 out_f,
2691 n_expert,
2692 row_bytes,
2693 expert_stride,
2694 layouts: None,
2695 macros: None,
2696 fp8_blk: None,
2697 })
2698 }
2699
2700 fn load_uniform_mmap_from_source(
2705 src: &dyn TensorSource,
2706 il: u32,
2707 proj: &str,
2708 n_expert: usize,
2709 ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
2710 if src
2711 .active_experts(il)
2712 .is_some_and(|mask| mask.iter().any(|&active| !active))
2713 {
2714 return Ok(None);
2715 }
2716 let mut first_map = None;
2717 let mut first_file = None;
2718 let mut base_offset = 0u64;
2719 let mut expert_stride = 0usize;
2720 let mut in_f = 0usize;
2721 let mut out_f = 0usize;
2722 let mut qtype = 0i32;
2723 let mut row_bytes = 0usize;
2724 let mut macros = vec![1.0f32; n_expert];
2725 #[allow(clippy::needless_range_loop)]
2726 for ex in 0..n_expert {
2728 let stem = format!("blk.{il}.ffn_{proj}_exps.{ex}");
2729 let name = format!("{stem}.weight");
2730 let Some(DiskExtent {
2731 map,
2732 file,
2733 offset,
2734 len,
2735 }) = find_expert_disk_strict(src, &name)?
2736 else {
2737 return Ok(None);
2738 };
2739 let Some(v) = src.find(&name) else {
2740 return Ok(None);
2741 };
2742 if v.ne.len() != 2 {
2743 return Ok(None);
2744 }
2745 let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
2746 let Some(cur_row_bytes) = staged_expert_row_bytes(v.ggml_type, cur_in) else {
2747 return Ok(None);
2748 };
2749 let cur_qtype = staged_expert_qtype(v.ggml_type).unwrap();
2750 if ex == 0 {
2751 base_offset = offset;
2752 expert_stride = len;
2753 in_f = cur_in;
2754 out_f = cur_out;
2755 qtype = cur_qtype;
2756 row_bytes = cur_row_bytes;
2757 first_map = Some(map);
2758 first_file = Some(file);
2759 } else if !std::sync::Arc::ptr_eq(first_map.as_ref().unwrap(), &map)
2760 || !std::sync::Arc::ptr_eq(first_file.as_ref().unwrap(), &file)
2761 || offset != base_offset + (ex * expert_stride) as u64
2762 || len != expert_stride
2763 || (cur_in, cur_out, cur_qtype, cur_row_bytes) != (in_f, out_f, qtype, row_bytes)
2764 {
2765 return Ok(None);
2766 }
2767 if let Some(scale) = src.find(&format!("{stem}.scale")) {
2768 macros[ex] = f32::from_le_bytes(scale.bytes[..4].try_into().unwrap());
2769 }
2770 }
2771 assert_eq!(expert_stride, out_f * row_bytes);
2772 let total = n_expert * expert_stride;
2773 let off = usize::try_from(base_offset)
2774 .map_err(|_| format!("uniform expert disk offset {base_offset} does not fit usize"))?;
2775 let all_one = macros.iter().all(|&scale| scale == 1.0);
2776 Ok(Some(HostExps {
2777 bytes: HostBuf::Mmap {
2778 map: first_map.unwrap(),
2779 file: first_file.unwrap(),
2780 off,
2781 len: total,
2782 },
2783 tiers: None,
2784 qtype,
2785 in_f,
2786 out_f,
2787 n_expert,
2788 row_bytes,
2789 expert_stride,
2790 layouts: None,
2791 macros: if all_one { None } else { Some(macros) },
2792 fp8_blk: None,
2793 }))
2794 }
2795
2796 fn load_mixed_from_source(
2797 src: &dyn TensorSource,
2798 il: u32,
2799 proj: &str,
2800 n_expert: usize,
2801 ) -> Result<Self, Box<dyn std::error::Error>> {
2802 let mut tiers = Vec::with_capacity(n_expert);
2803 let mut layouts = Vec::with_capacity(n_expert);
2804 let mut macros = vec![1.0f32; n_expert];
2805 let mut in_f = 0usize;
2806 let mut out_f = 0usize;
2807 let active = src.active_experts(il);
2808 let mut first_active = None;
2809
2810 for ex in 0..n_expert {
2811 if active.is_some_and(|mask| !mask[ex]) {
2812 layouts.push(ExpertLayout {
2813 offset: 0,
2814 len: 0,
2815 qtype: QT_F32,
2816 row_bytes: 0,
2817 });
2818 tiers.push(HostBuf::Paged(Vec::new()));
2819 continue;
2820 }
2821 let name = format!("blk.{il}.ffn_{proj}_exps.{ex}.weight");
2822 let stem = format!("blk.{il}.ffn_{proj}_exps.{ex}");
2823 if let Some(scale) = src.find(&format!("{stem}.scale")) {
2824 macros[ex] = f32::from_le_bytes(scale.bytes[..4].try_into().unwrap());
2825 }
2826 let (host, byte_len, qtype, row_bytes, cur_in, cur_out) = if let Some(DiskExtent {
2827 map,
2828 file,
2829 offset,
2830 len,
2831 }) =
2832 find_expert_disk_strict(src, &name)?
2833 {
2834 let v = src
2835 .find(&name)
2836 .unwrap_or_else(|| panic!("missing expert tensor {name}"));
2837 assert_eq!(v.ne.len(), 2, "expert {name} is not 2D (ne={:?})", v.ne);
2838 let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
2839 let row_bytes = staged_expert_row_bytes(v.ggml_type, cur_in).ok_or_else(|| {
2840 format!("mmap expert {name} has unsupported qtype {:?}", v.ggml_type)
2841 })?;
2842 let off = usize::try_from(offset).map_err(|_| {
2843 format!("expert {name} disk offset {offset} does not fit usize")
2844 })?;
2845 (
2846 HostBuf::Mmap {
2847 map,
2848 file,
2849 off,
2850 len,
2851 },
2852 len,
2853 staged_expert_qtype(v.ggml_type).unwrap(),
2854 row_bytes,
2855 cur_in,
2856 cur_out,
2857 )
2858 } else if let Some(nv) = src.find_nvfp4_native(&name) {
2859 let bytes = memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
2860 nv.wbytes, nv.wscale, nv.out_f, nv.in_f,
2861 );
2862 let row_bytes = nv.in_f / 64 * 36;
2863 let byte_len = bytes.len();
2864 (
2865 HostBuf::Paged(bytes),
2866 byte_len,
2867 QT_NVFP4,
2868 row_bytes,
2869 nv.in_f,
2870 nv.out_f,
2871 )
2872 } else {
2873 let v = src
2874 .find(&name)
2875 .unwrap_or_else(|| panic!("missing expert tensor {name}"));
2876 assert_eq!(v.ne.len(), 2, "expert {name} is not 2D (ne={:?})", v.ne);
2877 let (cur_in, cur_out) = (v.ne[0] as usize, v.ne[1] as usize);
2878 if let Some(row_bytes) = staged_expert_row_bytes(v.ggml_type, cur_in) {
2879 let bytes = v.bytes.into_owned();
2880 let byte_len = bytes.len();
2881 (
2882 HostBuf::Paged(bytes),
2883 byte_len,
2884 staged_expert_qtype(v.ggml_type).unwrap(),
2885 row_bytes,
2886 cur_in,
2887 cur_out,
2888 )
2889 } else {
2890 let f32v = dequant::dequantize(v.ggml_type, &v.bytes, cur_in * cur_out);
2891 let mut bytes = Vec::with_capacity(f32v.len() * 4);
2892 for f in f32v {
2893 bytes.extend_from_slice(&f.to_le_bytes());
2894 }
2895 let byte_len = bytes.len();
2896 (
2897 HostBuf::Paged(bytes),
2898 byte_len,
2899 QT_F32,
2900 cur_in * 4,
2901 cur_in,
2902 cur_out,
2903 )
2904 }
2905 };
2906
2907 if first_active.is_none() {
2908 in_f = cur_in;
2909 out_f = cur_out;
2910 first_active = Some(ex);
2911 } else {
2912 assert_eq!(
2913 (cur_in, cur_out),
2914 (in_f, out_f),
2915 "expert {ex} dims ({cur_in},{cur_out}) != first active expert ({in_f},{out_f})"
2916 );
2917 }
2918 assert_eq!(
2919 byte_len,
2920 cur_out * row_bytes,
2921 "expert {name} bytes {byte_len} != out_f*row_bytes {}",
2922 cur_out * row_bytes
2923 );
2924 layouts.push(ExpertLayout {
2925 offset: 0,
2926 len: byte_len,
2927 qtype,
2928 row_bytes,
2929 });
2930 tiers.push(host);
2931 }
2932
2933 let first = layouts[*first_active
2934 .as_ref()
2935 .expect("expert mask pruned every expert")];
2936 let expert_stride = layouts.iter().map(|layout| layout.len).max().unwrap_or(0);
2937 let all_one = macros.iter().all(|&scale| scale == 1.0);
2938 Ok(HostExps {
2939 bytes: HostBuf::Paged(Vec::new()),
2940 tiers: Some(tiers),
2941 qtype: first.qtype,
2942 in_f,
2943 out_f,
2944 n_expert,
2945 row_bytes: first.row_bytes,
2946 expert_stride,
2947 layouts: Some(layouts),
2948 macros: if all_one { None } else { Some(macros) },
2949 fp8_blk: None,
2950 })
2951 }
2952
2953 #[inline]
2957 pub fn macro_scale(&self, e: usize) -> f32 {
2958 self.macros.as_ref().map(|m| m[e]).unwrap_or(1.0)
2959 }
2960
2961 #[inline]
2962 pub fn is_uniform_layout(&self) -> bool {
2963 self.layouts.is_none()
2964 }
2965
2966 #[inline]
2967 pub fn expert_layout(&self, e: usize) -> ExpertLayout {
2968 debug_assert!(
2969 e < self.n_expert,
2970 "expert index {e} >= n_expert {}",
2971 self.n_expert
2972 );
2973 self.layouts
2974 .as_ref()
2975 .map(|layouts| layouts[e])
2976 .unwrap_or(ExpertLayout {
2977 offset: e * self.expert_stride,
2978 len: self.expert_stride,
2979 qtype: self.qtype,
2980 row_bytes: self.row_bytes,
2981 })
2982 }
2983
2984 #[inline]
2985 pub fn max_expert_bytes(&self) -> usize {
2986 self.layouts
2987 .as_ref()
2988 .and_then(|layouts| layouts.iter().map(|layout| layout.len).max())
2989 .unwrap_or(self.expert_stride)
2990 }
2991
2992 #[inline]
2994 pub fn expert_bytes(&self, e: usize) -> &[u8] {
2995 let layout = self.expert_layout(e);
2996 match &self.tiers {
2997 Some(tiers) => {
2998 debug_assert_eq!(tiers[e].len(), layout.len);
2999 tiers[e].as_bytes()
3000 }
3001 None => &self.bytes.as_bytes()[layout.offset..layout.offset + layout.len],
3002 }
3003 }
3004
3005 #[inline]
3009 pub(crate) fn expert_source(&self, e: usize) -> ExpertSource<'_> {
3010 let layout = self.expert_layout(e);
3011 match &self.tiers {
3012 Some(tiers) => tiers[e].expert_source(0, layout.len),
3013 None => self.bytes.expert_source(layout.offset, layout.len),
3014 }
3015 }
3016
3017 #[inline]
3021 pub fn prefetch_expert_pages(&self, e: usize) -> bool {
3022 let layout = self.expert_layout(e);
3023 match &self.tiers {
3024 Some(tiers) => tiers[e].advise_willneed(0, layout.len),
3025 None => self.bytes.advise_willneed(layout.offset, layout.len),
3026 }
3027 }
3028}
3029
3030#[cfg(test)]
3031mod tests {
3032 use super::{
3033 ExpertKeepalive, ExpertSource, HostBuf, HostExps, QT_BF16, QT_NVFP4, QT_Q2_K, QT_Q4_K,
3034 ensure_repack_cache_dir, open_repack_cache, repack_cache_is_fresh, repack_nvfp4_split,
3035 unpack_nvfp4_split, write_repack_cache,
3036 };
3037 use memra_gguf::nvfp4_repack::{repack_modelopt_to_gguf, repack_modelopt_to_split};
3038 use memra_gguf::source::{DiskExtent, Fp8StackedNative, TensorSource, TensorView};
3039 use memra_gguf::{GgmlType, config::ModelConfig};
3040 use std::borrow::Cow;
3041
3042 #[cfg(unix)]
3043 #[test]
3044 fn repack_cache_refuses_symlinked_directory_and_file() {
3045 use std::os::unix::fs::symlink;
3046
3047 let root = std::env::temp_dir().join(format!("memra-repack-links-{}", std::process::id()));
3048 std::fs::create_dir_all(&root).unwrap();
3049 let target_dir = root.join("target-dir");
3050 std::fs::create_dir(&target_dir).unwrap();
3051 let cache_dir = root.join(".memra-repack");
3052 symlink(&target_dir, &cache_dir).unwrap();
3053 let error = ensure_repack_cache_dir(&cache_dir).unwrap_err();
3054 assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
3055
3056 std::fs::remove_file(&cache_dir).unwrap();
3057 std::fs::create_dir(&cache_dir).unwrap();
3058 let target = root.join("outside.bin");
3059 std::fs::write(&target, b"keep").unwrap();
3060 let cache_file = cache_dir.join("artifact.nvfp4");
3061 symlink(&target, &cache_file).unwrap();
3062 assert!(!repack_cache_is_fresh(&cache_file, 4));
3063 let error = open_repack_cache(&cache_file, true).unwrap_err();
3064 assert_ne!(error.kind(), std::io::ErrorKind::NotFound);
3065 assert_eq!(std::fs::read(&target).unwrap(), b"keep");
3066
3067 let hardlink = cache_dir.join("hardlink.nvfp4");
3068 std::fs::hard_link(&target, &hardlink).unwrap();
3069 let error = write_repack_cache(&hardlink, |out| {
3070 use std::io::Write;
3071 out.write_all(b"replacement")
3072 })
3073 .unwrap_err();
3074 assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
3075 assert_eq!(std::fs::read(&target).unwrap(), b"keep");
3076 std::fs::remove_dir_all(root).ok();
3077 }
3078
3079 struct MixedExpertSource {
3080 bf16: Vec<u8>,
3081 q4k: Vec<u8>,
3082 }
3083
3084 impl TensorSource for MixedExpertSource {
3085 fn config(&self) -> ModelConfig {
3086 panic!("unused by HostExps mixed-loader test")
3087 }
3088
3089 fn find(&self, name: &str) -> Option<TensorView<'_>> {
3090 let (bytes, ggml_type) = if name == "blk.0.ffn_gate_exps.0.weight" {
3091 (&self.bf16, GgmlType::BF16)
3092 } else if name == "blk.0.ffn_gate_exps.1.weight" {
3093 (&self.q4k, GgmlType::Q4_K)
3094 } else {
3095 return None;
3096 };
3097 Some(TensorView {
3098 bytes: Cow::Borrowed(bytes),
3099 ggml_type,
3100 ne: vec![256, 2],
3101 })
3102 }
3103 }
3104
3105 struct PrunedExpertSource {
3106 q2k: Vec<u8>,
3107 nvfp4: Vec<u8>,
3108 active: Vec<bool>,
3109 }
3110
3111 struct MmapExpertSource {
3112 file: std::sync::Arc<std::fs::File>,
3113 map: std::sync::Arc<memmap2::Mmap>,
3114 base_offset: usize,
3115 expert_len: usize,
3116 }
3117
3118 struct LegacyMmapExpertSource {
3119 map: std::sync::Arc<memmap2::Mmap>,
3120 expert_len: usize,
3121 }
3122
3123 struct StackedFp8Source {
3124 file: std::sync::Arc<std::fs::File>,
3125 map: std::sync::Arc<memmap2::Mmap>,
3126 offset: usize,
3127 len: usize,
3128 scales: Vec<f32>,
3129 }
3130
3131 impl TensorSource for StackedFp8Source {
3132 fn config(&self) -> ModelConfig {
3133 panic!("unused by stacked FP8 ownership test")
3134 }
3135
3136 fn find(&self, _name: &str) -> Option<TensorView<'_>> {
3137 None
3138 }
3139
3140 fn find_fp8_stacked_native(&self, name: &str) -> Option<Fp8StackedNative<'_>> {
3141 (name == "blk.0.ffn_gate_exps.weight").then(|| Fp8StackedNative {
3142 bytes: &self.map[self.offset..self.offset + self.len],
3143 scales: self.scales.clone(),
3144 n_expert: 2,
3145 out_f: 2,
3146 in_f: 32,
3147 scale_rows: 1,
3148 scale_cols: 1,
3149 })
3150 }
3151
3152 fn find_expert_disk(&self, name: &str) -> Option<DiskExtent> {
3153 (name == "blk.0.ffn_gate_exps.weight").then(|| DiskExtent {
3154 map: self.map.clone(),
3155 file: self.file.clone(),
3156 offset: self.offset as u64,
3157 len: self.len,
3158 })
3159 }
3160 }
3161
3162 impl TensorSource for MmapExpertSource {
3163 fn config(&self) -> ModelConfig {
3164 panic!("unused by HostExps mmap-loader test")
3165 }
3166 fn preserve_expert_encodings(&self) -> bool {
3167 true
3168 }
3169 fn find(&self, name: &str) -> Option<TensorView<'_>> {
3170 let ex = match name {
3171 "blk.0.ffn_gate_exps.0.weight" => 0,
3172 "blk.0.ffn_gate_exps.1.weight" => 1,
3173 _ => return None,
3174 };
3175 let off = self.base_offset + ex * self.expert_len;
3176 Some(TensorView {
3177 bytes: Cow::Borrowed(&self.map[off..off + self.expert_len]),
3178 ggml_type: GgmlType::Q2_K,
3179 ne: vec![256, 2],
3180 })
3181 }
3182 fn find_expert_disk(&self, name: &str) -> Option<DiskExtent> {
3183 let ex = match name {
3184 "blk.0.ffn_gate_exps.0.weight" => 0,
3185 "blk.0.ffn_gate_exps.1.weight" => 1,
3186 _ => return None,
3187 };
3188 Some(DiskExtent {
3189 map: self.map.clone(),
3190 file: self.file.clone(),
3191 offset: (self.base_offset + ex * self.expert_len) as u64,
3192 len: self.expert_len,
3193 })
3194 }
3195 }
3196
3197 impl TensorSource for LegacyMmapExpertSource {
3198 fn config(&self) -> ModelConfig {
3199 panic!("unused by legacy mmap guard test")
3200 }
3201 fn preserve_expert_encodings(&self) -> bool {
3202 true
3203 }
3204 fn find(&self, name: &str) -> Option<TensorView<'_>> {
3205 let ex = match name {
3206 "blk.0.ffn_gate_exps.0.weight" => 0,
3207 "blk.0.ffn_gate_exps.1.weight" => 1,
3208 _ => return None,
3209 };
3210 let off = ex * self.expert_len;
3211 Some(TensorView {
3212 bytes: Cow::Borrowed(&self.map[off..off + self.expert_len]),
3213 ggml_type: GgmlType::Q2_K,
3214 ne: vec![256, 2],
3215 })
3216 }
3217 fn find_expert_mmap(
3218 &self,
3219 name: &str,
3220 ) -> Option<(std::sync::Arc<memmap2::Mmap>, usize, usize)> {
3221 let ex = match name {
3222 "blk.0.ffn_gate_exps.0.weight" => 0,
3223 "blk.0.ffn_gate_exps.1.weight" => 1,
3224 _ => return None,
3225 };
3226 Some((self.map.clone(), ex * self.expert_len, self.expert_len))
3227 }
3228 }
3229
3230 impl TensorSource for PrunedExpertSource {
3231 fn config(&self) -> ModelConfig {
3232 panic!("unused by HostExps pruned-loader test")
3233 }
3234 fn active_experts(&self, layer: u32) -> Option<&[bool]> {
3235 (layer == 0).then_some(self.active.as_slice())
3236 }
3237 fn find(&self, name: &str) -> Option<TensorView<'_>> {
3238 let (bytes, ggml_type) = match name {
3239 "blk.0.ffn_gate_exps.0.weight" => (&self.q2k, GgmlType::Q2_K),
3240 "blk.0.ffn_gate_exps.2.weight" => (&self.nvfp4, GgmlType::NVFP4),
3241 _ => return None,
3242 };
3243 Some(TensorView {
3244 bytes: Cow::Borrowed(bytes),
3245 ggml_type,
3246 ne: vec![256, 2],
3247 })
3248 }
3249 }
3250
3251 #[test]
3252 fn stacked_fp8_experts_retain_owned_mmap_and_scale_geometry() {
3253 let path = std::env::temp_dir().join(format!("memra-stacked-fp8-{}", std::process::id()));
3254 let offset = 11usize;
3255 let len = 2 * 2 * 32;
3256 let mut file_bytes = vec![0xA5; offset];
3257 file_bytes.extend((0..len).map(|i| (i % 127) as u8));
3258 std::fs::write(&path, &file_bytes).unwrap();
3259 let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
3260 let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
3261 let source = StackedFp8Source {
3262 file,
3263 map,
3264 offset,
3265 len,
3266 scales: vec![0.5, 0.25],
3267 };
3268
3269 let exps = HostExps::load_fp8_stacked_native_with_policy(
3270 &source,
3271 "blk.0.ffn_gate_exps.weight",
3272 true,
3273 )
3274 .unwrap()
3275 .unwrap();
3276 assert_eq!(exps.qtype, crate::QT_F8_E4M3_BLK);
3277 assert_eq!((exps.n_expert, exps.out_f, exps.in_f), (2, 2, 32));
3278 assert_eq!(exps.expert_stride, 64);
3279 assert!(matches!(exps.bytes, HostBuf::Mmap { .. }));
3280 assert_eq!(exps.expert_bytes(0), &file_bytes[offset..offset + 64]);
3281 assert_eq!(exps.expert_bytes(1), &file_bytes[offset + 64..offset + len]);
3282 let fp8 = exps.fp8_blk.as_ref().unwrap();
3283 assert_eq!((fp8.rows, fp8.cols, fp8.expert_stride), (1, 1, 1));
3284 assert_eq!(fp8.scales, vec![0.5, 0.25]);
3285
3286 drop(source);
3287 assert_eq!(exps.expert_bytes(1), &file_bytes[offset + 64..offset + len]);
3288 std::fs::remove_file(path).ok();
3289 }
3290
3291 #[test]
3292 fn stacked_fp8_experts_reject_non_finite_codes() {
3293 let path =
3294 std::env::temp_dir().join(format!("memra-stacked-fp8-nan-{}", std::process::id()));
3295 let len = 2 * 2 * 32;
3296 let mut file_bytes = vec![0x12; len];
3297 file_bytes[73] = 0x7f;
3298 std::fs::write(&path, &file_bytes).unwrap();
3299 let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
3300 let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
3301 let source = StackedFp8Source {
3302 file,
3303 map,
3304 offset: 0,
3305 len,
3306 scales: vec![0.5, 0.25],
3307 };
3308
3309 let err = match HostExps::load_fp8_stacked_native_with_policy(
3310 &source,
3311 "blk.0.ffn_gate_exps.weight",
3312 true,
3313 ) {
3314 Ok(_) => panic!("non-finite E4M3 code was accepted"),
3315 Err(err) => err,
3316 };
3317 assert!(err.to_string().contains("non-finite E4M3"));
3318 std::fs::remove_file(path).ok();
3319 }
3320
3321 #[test]
3325 fn direct_split_equals_chained() {
3326 for (out_f, in_f) in [(1usize, 64usize), (3, 128), (5, 320), (8, 1024)] {
3327 let mut w = vec![0u8; out_f * in_f / 2];
3328 let mut s = vec![0u8; out_f * in_f / 16];
3329 for (i, b) in w.iter_mut().enumerate() {
3330 *b = ((i * 41 + 7) & 0xFF) as u8;
3331 }
3332 for (i, b) in s.iter_mut().enumerate() {
3333 *b = (0x20 + ((i * 11 + 5) % 0x50)) as u8;
3334 }
3335 let gguf = repack_modelopt_to_gguf(&w, &s, out_f, in_f);
3336 let chained = repack_nvfp4_split(&gguf, out_f);
3337 let direct = repack_modelopt_to_split(&w, &s, out_f, in_f);
3338 assert_eq!(
3339 direct, chained,
3340 "fused != chained at out_f={out_f} in_f={in_f}"
3341 );
3342 assert_eq!(
3343 unpack_nvfp4_split(&direct, out_f),
3344 gguf,
3345 "split roundtrip broken at out_f={out_f} in_f={in_f}"
3346 );
3347 }
3348 }
3349
3350 #[test]
3351 fn mixed_expert_loader_keeps_each_encoding_and_extent() {
3352 let source = MixedExpertSource {
3353 bf16: vec![0x5a; 256 * 2 * 2],
3354 q4k: vec![0xa5; 2 * 144],
3355 };
3356 let exps = HostExps::load_mixed_from_source(&source, 0, "gate", 2).unwrap();
3357 assert!(!exps.is_uniform_layout());
3358 assert_eq!(exps.max_expert_bytes(), 1024);
3359 assert_eq!(exps.expert_layout(0).qtype, QT_BF16);
3360 assert_eq!(exps.expert_layout(0).row_bytes, 512);
3361 assert_eq!(exps.expert_layout(0).len, 1024);
3362 assert_eq!(exps.expert_layout(1).qtype, QT_Q4_K);
3363 assert_eq!(exps.expert_layout(1).row_bytes, 144);
3364 assert_eq!(exps.expert_layout(1).len, 288);
3365 assert_eq!(exps.expert_bytes(0), source.bf16);
3366 assert_eq!(exps.expert_bytes(1), source.q4k);
3367 match exps.expert_source(1) {
3368 ExpertSource::Memory { bytes, .. } => assert_eq!(bytes, source.q4k),
3369 ExpertSource::Disk { .. } => panic!("paged expert unexpectedly became disk-backed"),
3370 }
3371 }
3372
3373 #[test]
3374 fn mixed_expert_loader_omits_masked_expert_bytes() {
3375 let source = PrunedExpertSource {
3376 q2k: vec![0x22; 2 * 84],
3377 nvfp4: vec![0x44; 2 * 4 * 36],
3378 active: vec![true, false, true],
3379 };
3380 let exps = HostExps::load_mixed_from_source(&source, 0, "gate", 3).unwrap();
3381 assert_eq!(exps.expert_layout(0).qtype, QT_Q2_K);
3382 assert_eq!(exps.expert_layout(0).row_bytes, 84);
3383 assert_eq!(exps.expert_layout(1).len, 0);
3384 assert_eq!(exps.expert_bytes(1), &[]);
3385 assert_eq!(exps.expert_layout(2).qtype, QT_NVFP4);
3386 assert_eq!(exps.expert_layout(2).row_bytes, 4 * 36);
3387 }
3388
3389 #[test]
3390 fn mixed_expert_loader_keeps_mmap_backing_zero_copy() {
3391 let path = std::env::temp_dir().join(format!("memra-mixed-mmap-{}", std::process::id()));
3392 let base_offset = 3usize;
3393 let expert_len = 2 * 84;
3394 let mut bytes = vec![0xE1; base_offset];
3395 bytes.extend(vec![0x31; expert_len]);
3396 bytes.extend(vec![0x72; expert_len]);
3397 std::fs::write(&path, &bytes).unwrap();
3398 let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
3399 let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
3400 let source = MmapExpertSource {
3401 file: file.clone(),
3402 map,
3403 base_offset,
3404 expert_len,
3405 };
3406 let exps = HostExps::load_mixed_from_source(&source, 0, "gate", 2).unwrap();
3407 assert!(matches!(
3408 exps.tiers.as_ref().unwrap()[0],
3409 HostBuf::Mmap { .. }
3410 ));
3411 assert!(matches!(
3412 exps.tiers.as_ref().unwrap()[1],
3413 HostBuf::Mmap { .. }
3414 ));
3415 assert_eq!(
3416 exps.expert_bytes(0),
3417 &bytes[base_offset..base_offset + expert_len]
3418 );
3419 assert_eq!(exps.expert_bytes(1), &bytes[base_offset + expert_len..]);
3420 match exps.expert_source(1) {
3421 ExpertSource::Disk {
3422 file: got_file,
3423 offset,
3424 len,
3425 fallback,
3426 keepalive,
3427 } => {
3428 assert!(std::sync::Arc::ptr_eq(got_file, &file));
3429 assert_eq!(offset, (base_offset + expert_len) as u64);
3430 assert_eq!(len, expert_len);
3431 assert_eq!(fallback, &bytes[base_offset + expert_len..]);
3432 match keepalive {
3433 ExpertKeepalive::Mmap(owner) => {
3434 assert!(std::sync::Arc::ptr_eq(&owner, &source.map));
3435 }
3436 _ => panic!("mmap expert did not retain its mmap owner"),
3437 }
3438 }
3439 ExpertSource::Memory { .. } => panic!("mixed mmap tier lost its disk extent"),
3440 }
3441 #[cfg(unix)]
3442 assert!(exps.prefetch_expert_pages(1));
3443 std::fs::remove_file(path).ok();
3444 }
3445
3446 #[test]
3447 fn tiered_expert_source_does_not_double_apply_layout_offset() {
3448 let path =
3449 std::env::temp_dir().join(format!("memra-tiered-source-offset-{}", std::process::id()));
3450 let base_offset = 7usize;
3451 let expert_len = 2 * 84;
3452 let mut bytes = vec![0xE3; base_offset];
3453 bytes.extend(vec![0x41; expert_len]);
3454 bytes.extend(vec![0x82; expert_len]);
3455 std::fs::write(&path, &bytes).unwrap();
3456 let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
3457 let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
3458 let exps = HostExps {
3459 bytes: HostBuf::Paged(Vec::new()),
3460 tiers: Some(vec![
3461 HostBuf::Mmap {
3462 map: map.clone(),
3463 file: file.clone(),
3464 off: base_offset,
3465 len: expert_len,
3466 },
3467 HostBuf::Mmap {
3468 map,
3469 file: file.clone(),
3470 off: base_offset + expert_len,
3471 len: expert_len,
3472 },
3473 ]),
3474 qtype: QT_Q2_K,
3475 in_f: 256,
3476 out_f: 2,
3477 n_expert: 2,
3478 row_bytes: 84,
3479 expert_stride: expert_len,
3480 layouts: None,
3481 macros: None,
3482 fp8_blk: None,
3483 };
3484
3485 assert_eq!(exps.expert_layout(1).offset, expert_len);
3487 match exps.expert_source(1) {
3488 ExpertSource::Disk {
3489 offset,
3490 len,
3491 fallback,
3492 ..
3493 } => {
3494 assert_eq!(offset, (base_offset + expert_len) as u64);
3495 assert_eq!(len, expert_len);
3496 assert_eq!(fallback, &bytes[base_offset + expert_len..]);
3497 }
3498 ExpertSource::Memory { .. } => panic!("tiered mmap expert lost its disk extent"),
3499 }
3500 std::fs::remove_file(path).ok();
3501 }
3502
3503 #[test]
3504 fn legacy_mmap_source_requires_retained_file_extent() {
3505 let path =
3506 std::env::temp_dir().join(format!("memra-legacy-mmap-source-{}", std::process::id()));
3507 let expert_len = 2 * 84;
3508 std::fs::write(&path, vec![0x64; 2 * expert_len]).unwrap();
3509 let file = std::fs::File::open(&path).unwrap();
3510 let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(&file).unwrap() });
3511 let source = LegacyMmapExpertSource { map, expert_len };
3512
3513 let err = match HostExps::load_uniform_mmap_from_source(&source, 0, "gate", 2) {
3514 Ok(_) => panic!("legacy mmap-only source silently fell back instead of failing"),
3515 Err(err) => err,
3516 };
3517 let message = err.to_string();
3518 assert!(
3519 message.contains("legacy find_expert_mmap without find_expert_disk"),
3520 "{message}"
3521 );
3522 assert!(message.contains("retained Arc<File>"), "{message}");
3523 std::fs::remove_file(path).ok();
3524 }
3525
3526 #[test]
3527 fn uniform_expert_loader_coalesces_contiguous_mmap() {
3528 let path = std::env::temp_dir().join(format!("memra-uniform-mmap-{}", std::process::id()));
3529 let base_offset = 5usize;
3530 let expert_len = 2 * 84;
3531 let mut bytes = vec![0xE2; base_offset];
3532 bytes.extend(vec![0x19; expert_len]);
3533 bytes.extend(vec![0x91; expert_len]);
3534 std::fs::write(&path, &bytes).unwrap();
3535 let file = std::sync::Arc::new(std::fs::File::open(&path).unwrap());
3536 let map = std::sync::Arc::new(unsafe { memmap2::Mmap::map(file.as_ref()).unwrap() });
3537 let source = MmapExpertSource {
3538 file: file.clone(),
3539 map,
3540 base_offset,
3541 expert_len,
3542 };
3543 let exps = HostExps::load_uniform_mmap_from_source(&source, 0, "gate", 2)
3544 .unwrap()
3545 .expect("contiguous mmap should coalesce");
3546 assert!(exps.is_uniform_layout());
3547 assert!(matches!(&exps.bytes, HostBuf::Mmap { .. }));
3548 assert_eq!(exps.expert_stride, expert_len);
3549 assert_eq!(
3550 exps.expert_bytes(0),
3551 &bytes[base_offset..base_offset + expert_len]
3552 );
3553 assert_eq!(exps.expert_bytes(1), &bytes[base_offset + expert_len..]);
3554 match exps.expert_source(1) {
3555 ExpertSource::Disk {
3556 file: got_file,
3557 offset,
3558 len,
3559 fallback,
3560 ..
3561 } => {
3562 assert!(std::sync::Arc::ptr_eq(got_file, &file));
3563 assert_eq!(offset, (base_offset + expert_len) as u64);
3564 assert_eq!(len, expert_len);
3565 assert_eq!(fallback, &bytes[base_offset + expert_len..]);
3566 }
3567 ExpertSource::Memory { .. } => panic!("uniform mmap slab lost its disk extent"),
3568 }
3569 #[cfg(unix)]
3570 assert!(exps.prefetch_expert_pages(1));
3571 std::fs::remove_file(path).ok();
3572 }
3573}