Skip to main content

qualia_core_db/gguf_bridge/
load.rs

1//! Model load + residency: GGUF load, ternary-FFN resident build, resident mmap adoption,
2//! resident logits upload, KV-cache sizing, decode-profiler hooks. Split from mod.rs (structural).
3use super::*;
4
5impl QTensorEngine {
6    pub fn kv_cache_bytes(&self) -> u64 {
7        self.kv_layout
8            .as_ref()
9            .map(|layout| (layout.total_f32_elems * std::mem::size_of::<f32>()) as u64)
10            .unwrap_or(0)
11    }
12
13    #[cfg(not(target_arch = "wasm32"))]
14    pub fn load_gguf_checked(&mut self, path: &str) -> Result<GgufLoadReport, String> {
15        use std::fs::File;
16
17        log::info!("LLM_LOAD|gguf-open|0.52|Opening GGUF file {}", path);
18        let file = File::open(path).map_err(|e| {
19            log::error!("GGUF mmap open failed for {}: {}", path, e);
20            log::error!("LLM_LOAD|failed|1.00|Could not open GGUF: {}", e);
21            e.to_string()
22        })?;
23        log::info!("LLM_LOAD|mmap-start|0.64|Memory-mapping GGUF into virtual memory");
24        let mmap = unsafe { MmapOptions::new().map(&file) }.map_err(|e| {
25            log::error!("GGUF mmap failed for {}: {}", path, e);
26            log::error!("LLM_LOAD|failed|1.00|Memory map failed: {}", e);
27            e.to_string()
28        })?;
29        let file_size = mmap.len();
30        log::info!(
31            "LLM_LOAD|ram-map|0.70|Mapped {:.2} GiB GGUF into system memory",
32            bytes_to_gib(file_size as u64)
33        );
34        // H2 CONSUMPTION wiring (default-OFF via QUALIA_LLM_ROUTE): compute + record + store
35        // the residency EmploymentPlan for this model, using the honest mapped weight-byte count
36        // (`file_size`) and the already-probed hardware passport. This makes the residency planner
37        // OBSERVABLE and CONSUMED without changing weight placement or the decode path.
38        // TODO(H3-exec): actually running overflow layers on the auxiliary circuit is the remaining
39        // (out-of-scope) H3 step; the recorded plan is advisory until an execution stage consults it.
40        let _ = crate::residency_planner::route_employment_from_passport(file_size as u64);
41        let index = crate::gguf_sharder::GgufTensorIndex::from_gguf(&mmap);
42        if index.tensor_data_start == 0
43            && index.max_tensor_bytes == 0
44            && index.hyperparams.n_layer == 0
45        {
46            let msg = "GGUF header parse failed or yielded no tensor metadata".to_string();
47            log::error!("LLM_LOAD|failed|1.00|{}", msg);
48            return Err(msg);
49        }
50        if let Err(msg) = index.hyperparams.decode_supported() {
51            log::error!("LLM_LOAD|failed|1.00|{}", msg);
52            return Err(msg);
53        }
54
55        self.tensor_data_offset = index.tensor_data_start;
56        self.hyperparams = index.hyperparams;
57        let staging = index
58            .max_layer_tensor_bytes
59            .max(4096)
60            .min(MAX_WGPU_WEIGHT_STAGING);
61        self.ensure_gemm_buffers(staging, MAX_STACK_GEMM_OUT as u32);
62        self.ensure_kv_cache(&index.hyperparams);
63        self.gguf_mmap = Some(Arc::new(mmap));
64        self.p64_index = None;
65        self.tensor_index_cache = Some(index.clone());
66
67        let kv_cache_bytes = self.kv_cache_bytes();
68        log::info!(
69            "LLM_LOAD|gguf-index|0.78|Parsed {} layers, {} attention heads",
70            self.hyperparams.n_layer,
71            self.hyperparams.n_head
72        );
73        log::info!(
74            "LLM_LOAD|gguf-ready|0.92|GGUF indexed and cache arena reserved ({} MiB)",
75            kv_cache_bytes / (1024 * 1024)
76        );
77
78        Ok(GgufLoadReport {
79            mapped_bytes: file_size as u64,
80            tensor_data_offset: self.tensor_data_offset,
81            n_layer: self.hyperparams.n_layer,
82            n_head: self.hyperparams.n_head,
83            n_kv_head: self.hyperparams.effective_n_kv_head(),
84            max_tensor_bytes: index.max_tensor_bytes,
85            kv_cache_bytes,
86            directml_enabled: {
87                #[cfg(target_os = "windows")]
88                {
89                    self.dml.is_some()
90                }
91                #[cfg(not(target_os = "windows"))]
92                {
93                    false
94                }
95            },
96        })
97    }
98
99    /// Memory-map a GGUF file so tensor bytes are accessible without heap allocation.
100    /// Call this once after `new()`, before the first `dispatch_fused_transformer_block`.
101    #[cfg(not(target_arch = "wasm32"))]
102    pub fn load_gguf(&mut self, path: &str) {
103        if let Err(e) = self.load_gguf_checked(path) {
104            eprintln!("[gguf_bridge] Could not load {path}: {e}");
105        }
106    }
107
108    /// Memory-map and auto-detect a supported local model container.
109    ///
110    /// Canonical P64 is detected by its exact `p64\0` magic and adopted through
111    /// the P64 validation path. All other inputs are passed to the GGUF parser,
112    /// which rejects malformed or unsupported data.
113    #[cfg(not(target_arch = "wasm32"))]
114    pub fn load_model_checked(&mut self, path: &str) -> Result<GgufLoadReport, String> {
115        let file = std::fs::File::open(path).map_err(|e| format!("open {path}: {e}"))?;
116        let mmap = std::sync::Arc::new(
117            unsafe { memmap2::MmapOptions::new().map(&file) }.map_err(|e| e.to_string())?,
118        );
119        if crate::p64_weight::has_p64_magic(&mmap[..]) {
120            self.adopt_resident_p64_mmap(mmap)
121        } else {
122            self.adopt_resident_mmap(mmap)
123        }
124    }
125
126    /// Fail-soft wrapper retained for the agent decode path.
127    #[cfg(not(target_arch = "wasm32"))]
128    pub fn load_model(&mut self, path: &str) {
129        if let Err(e) = self.load_model_checked(path) {
130            eprintln!("[gguf_bridge] Could not load model {path}: {e}");
131        }
132    }
133
134    /// Build the resident 2-bit ternary-FFN dispatcher from a P64 container's base-3 FFN
135    /// blobs (rebaked to 2-bit + uploaded once). Returns false if there are no ternary FFN tensors
136    /// or the GPU build fails — the FFN then runs the CPU oracle (`dispatch_ternary_ffn` fallback).
137    #[cfg(not(target_arch = "wasm32"))]
138    pub(crate) fn build_ternary_ffn_resident(
139        &mut self,
140        q: &crate::p64_weight::P64TensorIndex,
141    ) -> bool {
142        let mmap_arc = match self.gguf_mmap.clone() {
143            Some(a) => a,
144            None => return false,
145        };
146        let data: &[u8] = &mmap_arc;
147        let mut tensors: Vec<(u64, usize, usize, &[u8])> = Vec::new();
148        for e in &q.entries {
149            if e.dtype as u32 != crate::ternary::GGML_TYPE_TERNARY_158 {
150                continue;
151            }
152            let (n_in, n_out) = (e.dimensions[0] as usize, e.dimensions[1] as usize);
153            let (off, len) = (e.blob_offset as usize, e.blob_size as usize);
154            if n_in == 0 || n_out == 0 || off + len > data.len() {
155                continue;
156            }
157            // key = the P64 blob offset == the synthetic index's GgufTensorInfo::byte_offset.
158            tensors.push((e.blob_offset as u64, n_in, n_out, &data[off..off + len]));
159        }
160        if tensors.is_empty() {
161            return false;
162        }
163        match crate::ternary_gpu::TernaryFfnResident::build(
164            self.gpu_device(),
165            self.gpu_queue(),
166            &tensors,
167        ) {
168            Some(r) => {
169                log::info!(
170                    "LLM_LOAD|ternary-ffn|0.71|resident 2-bit FFN: {} tensors, {:.1} MB",
171                    r.len(),
172                    r.resident_bytes() as f64 / (1024.0 * 1024.0)
173                );
174                self.ternary_ffn = Some(r);
175                true
176            }
177            None => false,
178        }
179    }
180
181    /// Boot from an already-mapped P64 weight container (native). Mirrors the GGUF
182    /// `adopt_resident_mmap` but for the `P64` format: validates + builds a synthetic GGUF index
183    /// from the manifest, points the byte source at the P64 bytes (`tensor_data_start = 0`,
184    /// absolute blob offsets), reserves the GEMM/KV arenas, makes the (verbatim) output projection
185    /// resident, and builds the resident 2-bit ternary-FFN dispatcher from the FFN blobs. The
186    /// attention/norm/embed tensors stay at source precision and run the standard GGUF hot path.
187    #[cfg(not(target_arch = "wasm32"))]
188    pub fn adopt_resident_p64_mmap(
189        &mut self,
190        mmap: Arc<memmap2::Mmap>,
191    ) -> Result<GgufLoadReport, String> {
192        let file_size = mmap.len();
193        if file_size == 0 {
194            return Err("Empty P64 mmap".to_string());
195        }
196        let q = crate::p64_weight::P64TensorIndex::from_p64(&mmap[..])?;
197        let index = q.to_gguf_index();
198        let hp = index.hyperparams;
199        if hp.n_layer == 0 || hp.n_embd == 0 {
200            return Err("P64: missing hyperparameters in header".to_string());
201        }
202        if let Err(msg) = hp.decode_supported() {
203            log::error!("LLM_LOAD|failed|1.00|{}", msg);
204            return Err(msg);
205        }
206        self.hyperparams = hp;
207        self.tensor_data_offset = 0; // P64 blob offsets are absolute
208        let staging = index
209            .max_layer_tensor_bytes
210            .max(4096)
211            .min(MAX_WGPU_WEIGHT_STAGING);
212        self.ensure_gemm_buffers(staging, MAX_STACK_GEMM_OUT as u32);
213        self.ensure_kv_cache(&hp);
214        if self.kv_layout.is_none() || self.kv_cache_cpu.is_none() {
215            return Err("P64: KV cache allocation failed".to_string());
216        }
217        self.gguf_mmap = Some(mmap);
218        // Cache index so decode never re-validates hundreds of MB of tensor CRCs.
219        self.p64_index = Some(q.clone());
220        self.tensor_index_cache = Some(index.clone());
221        if !self.mc8_upload_resident_logits(&index) {
222            log::info!("LLM_LOAD|p64-logits|0.70|skipped — per-token upload fallback");
223        }
224        if !self.build_ternary_ffn_resident(&q) {
225            log::info!(
226                "LLM_LOAD|ternary-ffn|0.71|no resident set (no ternary FFN or build failed) — CPU oracle path"
227            );
228        }
229        let kv_cache_bytes = self.kv_cache_bytes();
230        Ok(GgufLoadReport {
231            mapped_bytes: file_size as u64,
232            tensor_data_offset: 0,
233            n_layer: hp.n_layer,
234            n_head: hp.n_head,
235            n_kv_head: hp.effective_n_kv_head(),
236            max_tensor_bytes: index.max_tensor_bytes,
237            kv_cache_bytes,
238            directml_enabled: {
239                #[cfg(target_os = "windows")]
240                {
241                    self.dml.is_some()
242                }
243                #[cfg(not(target_os = "windows"))]
244                {
245                    false
246                }
247            },
248        })
249    }
250
251    /// Compatibility alias for the historical pre-P64 API name.
252    #[deprecated(note = "use adopt_resident_p64_mmap")]
253    #[cfg(not(target_arch = "wasm32"))]
254    pub fn adopt_resident_q42_mmap(
255        &mut self,
256        mmap: Arc<memmap2::Mmap>,
257    ) -> Result<GgufLoadReport, String> {
258        self.adopt_resident_p64_mmap(mmap)
259    }
260
261    /// A1b: number of resident ternary FFN tensors (0 unless a ternary P64 was adopted). Lets a
262    /// test confirm the GPU resident path is actually populated (not a silent CPU-only fallback).
263    #[cfg(not(target_arch = "wasm32"))]
264    pub fn ternary_ffn_resident_len(&self) -> usize {
265        self.ternary_ffn.as_ref().map_or(0, |r| r.len())
266    }
267
268    /// Attach an already-mapped resident GGUF (shared with orchestrator slot).
269    #[cfg(not(target_arch = "wasm32"))]
270    pub fn adopt_resident_mmap(
271        &mut self,
272        mmap: Arc<memmap2::Mmap>,
273    ) -> Result<GgufLoadReport, String> {
274        let file_size = mmap.len();
275        if file_size == 0 {
276            return Err("Empty GGUF mmap".to_string());
277        }
278        log::info!(
279            "LLM_LOAD|resident-mmap|0.68|Reusing resident GGUF mapping ({:.2} GiB)",
280            bytes_to_gib(file_size as u64)
281        );
282        let index = crate::gguf_sharder::GgufTensorIndex::from_gguf(mmap.as_ref());
283        if index.tensor_data_start == 0
284            && index.max_tensor_bytes == 0
285            && index.hyperparams.n_layer == 0
286        {
287            return Err("GGUF header parse failed or yielded no tensor metadata".to_string());
288        }
289        self.tensor_data_offset = index.tensor_data_start;
290        self.hyperparams = index.hyperparams;
291        let staging = index
292            .max_layer_tensor_bytes
293            .max(4096)
294            .min(MAX_WGPU_WEIGHT_STAGING);
295        self.ensure_gemm_buffers(staging, MAX_STACK_GEMM_OUT as u32);
296        self.ensure_kv_cache(&index.hyperparams);
297        self.gguf_mmap = Some(mmap);
298        self.p64_index = None;
299        self.tensor_index_cache = Some(index.clone());
300        // A1a step-2: make the output/logits projection resident (upload once) so the per-token
301        // top-k decode binds per-chunk 256-aligned sub-ranges instead of re-uploading the whole
302        // ~47 MB matrix every token (the documented decode throughput killer). Fail-soft: a false
303        // return leaves `mc8_logits_resident_buf=None` and the decode keeps its per-token upload.
304        if !self.mc8_upload_resident_logits(&index) {
305            log::info!("LLM_LOAD|resident-logits|0.70|skipped — per-token upload fallback");
306        }
307        let kv_cache_bytes = self.kv_cache_bytes();
308        Ok(GgufLoadReport {
309            mapped_bytes: file_size as u64,
310            tensor_data_offset: self.tensor_data_offset,
311            n_layer: self.hyperparams.n_layer,
312            n_head: self.hyperparams.n_head,
313            n_kv_head: self.hyperparams.effective_n_kv_head(),
314            max_tensor_bytes: index.max_tensor_bytes,
315            kv_cache_bytes,
316            directml_enabled: {
317                #[cfg(target_os = "windows")]
318                {
319                    self.dml.is_some()
320                }
321                #[cfg(not(target_os = "windows"))]
322                {
323                    false
324                }
325            },
326        })
327    }
328
329    /// A1a step-2 (native port of Phase 5.3): upload the output/logits projection (tied
330    /// `token_embd`) to a resident `STORAGE` buffer **once**, so the per-token top-k decode binds
331    /// per-chunk 256-aligned sub-ranges instead of re-uploading the whole ~47 MB matrix every
332    /// token (the decode throughput killer). Idempotent. Returns false (→ per-token upload
333    /// fallback) if the projection is missing or its bytes don't divide evenly into rows.
334    #[cfg(not(target_arch = "wasm32"))]
335    pub(crate) fn mc8_upload_resident_logits(
336        &mut self,
337        index: &crate::gguf_sharder::GgufTensorIndex,
338    ) -> bool {
339        if self.mc8_logits_resident_buf.is_some() {
340            return true;
341        }
342        let info = match index.logits_projection_info() {
343            Some(i) => i,
344            None => return false,
345        };
346        let (_, vocab) = Self::matmul_dims(info);
347        if vocab == 0 {
348            return false;
349        }
350        // Clone the Arc so the mmap borrow does not block mutating `self` below.
351        let mmap_arc = match self.gguf_mmap.clone() {
352            Some(a) => a,
353            None => return false,
354        };
355        let mmap: &[u8] = &mmap_arc;
356        let raw = match crate::ggml_quants::fetch_tensor_bytes(mmap, index.tensor_data_start, info)
357        {
358            Ok(s) => s,
359            Err(_) => return false,
360        };
361        let total = raw.len();
362        if total == 0 || total % vocab != 0 {
363            return false;
364        }
365        let row_bytes = total / vocab;
366        // VOCAB_CHUNK_ROWS is a multiple of 256, so every chunk's byte offset
367        // (chunk_idx * VOCAB_CHUNK_ROWS * row_bytes) is 256-aligned for the storage binding.
368        let buf = self.gpu_device().create_buffer(&wgpu::BufferDescriptor {
369            label: Some("ResidentLogits"),
370            size: total as u64,
371            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
372            mapped_at_creation: false,
373        });
374        self.gpu_queue().write_buffer(&buf, 0, raw);
375        self.mc8_logits_resident_buf = Some(buf);
376        self.mc8_logits_row_bytes = row_bytes as u32;
377        log::info!(
378            "LLM_LOAD|resident-logits|0.70|output projection resident once: {:.1} MB ({} rows x {} B)",
379            total as f64 / (1024.0 * 1024.0),
380            vocab,
381            row_bytes
382        );
383        true
384    }
385
386    /// Decode-profiler: blocking GPU fence wait + round-trip counter. Every native sync point routes
387    /// through this (via the `self.gpu_device().poll(Maintain::Wait)` → `self.poll_wait()` rewrite),
388    /// so the bench can count submit→wait round-trips per token and separate synchronization stall
389    /// from real kernel time. Behaviourally identical to a bare blocking poll.
390    #[inline]
391    #[cfg(not(target_arch = "wasm32"))]
392    pub(crate) fn poll_wait(&self) {
393        let _ = self.gpu_device().poll(wgpu::PollType::wait_indefinitely());
394        GPU_WAIT_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
395    }
396
397    /// Decode-profiler: wall-clock for `n` EMPTY `submit → poll(Maintain::Wait)` round-trips (no
398    /// compute dispatched). Isolates the fixed CPU↔GPU fence latency: if a token's forward time ≈
399    /// (its round-trip count × this per-round-trip cost), the bottleneck is synchronization, not
400    /// math; if forward ≫ that, the kernels themselves are slow. Does NOT touch `GPU_WAIT_COUNT`.
401    #[cfg(not(target_arch = "wasm32"))]
402    pub fn bench_empty_submit_roundtrip(&self, n: u32) -> u64 {
403        let t = std::time::Instant::now();
404        for _ in 0..n {
405            let enc = self
406                .device()
407                .create_command_encoder(&wgpu::CommandEncoderDescriptor {
408                    label: Some("EmptyRT"),
409                });
410            self.gpu_queue().submit(Some(enc.finish()));
411            let _ = self.gpu_device().poll(wgpu::PollType::wait_indefinitely());
412        }
413        t.elapsed().as_nanos() as u64
414    }
415    #[cfg(target_arch = "wasm32")]
416    pub fn adopt_resident_mmap(&mut self, mmap: Arc<[u8]>) -> Result<GgufLoadReport, String> {
417        let file_size = mmap.len();
418        if file_size == 0 {
419            return Err("Empty GGUF mmap".to_string());
420        }
421        log::info!(
422            "LLM_LOAD|resident-mmap|0.68|Reusing resident GGUF mapping ({:.2} GiB)",
423            bytes_to_gib(file_size as u64)
424        );
425        let index = crate::gguf_sharder::GgufTensorIndex::from_gguf(mmap.as_ref());
426        if index.tensor_data_start == 0
427            && index.max_tensor_bytes == 0
428            && index.hyperparams.n_layer == 0
429        {
430            return Err("GGUF header parse failed or yielded no tensor metadata".to_string());
431        }
432        self.tensor_data_offset = index.tensor_data_start;
433        self.hyperparams = index.hyperparams;
434        let staging = index
435            .max_layer_tensor_bytes
436            .max(4096)
437            .min(MAX_WGPU_WEIGHT_STAGING);
438        self.ensure_gemm_buffers(staging, MAX_STACK_GEMM_OUT as u32);
439        self.ensure_kv_cache(&index.hyperparams);
440        if self.kv_layout.is_none() || self.kv_cache_cpu.is_none() {
441            return Err("KV cache allocation failed (layout or CPU mirror missing)".to_string());
442        }
443        self.gguf_mmap = Some(mmap);
444        // Full eager upload — required for coherent decode (do not defer).
445        // REVIEW(wasm-mobile-2026-08-02 F6): accelerated/benchmark mode needs a
446        // fail-closed residency contract and receipt. Continuing here can silently
447        // demote the engine into the historical per-forward upload performance floor.
448        if !self.mc8_upload_all_resident_weights(&index) {
449            wlog("[MC8] eager resident weight upload skipped at init — will retry lazily");
450        }
451        if !self.mc8_upload_resident_logits(&index) {
452            wlog("[MC8] resident logits projection skipped at init — per-token upload fallback");
453        }
454        if !self.mc8_upload_resident_norms(&index) {
455            wlog("[MC8] resident norm weights skipped at init — per-layer upload fallback");
456        }
457        let kv_cache_bytes = self.kv_cache_bytes();
458        Ok(GgufLoadReport {
459            mapped_bytes: file_size as u64,
460            tensor_data_offset: self.tensor_data_offset,
461            n_layer: self.hyperparams.n_layer,
462            n_head: self.hyperparams.n_head,
463            n_kv_head: self.hyperparams.effective_n_kv_head(),
464            max_tensor_bytes: index.max_tensor_bytes,
465            kv_cache_bytes,
466            directml_enabled: false,
467        })
468    }
469}