nx_gguf_load_lazy.nx source
↩ module page · 119 lines · 4698 B
1// nx_gguf_load_lazy.nx -- Phase B of conductor arc.
2//
3// L4.5 brick. Composes nx_placement.nx (Phase A) with nx_gguf_load.nx
4// to provide a ZERO-RAM-FOOTPRINT tensor handle: load a GGUF tensor
5// by name and get back an NxPlacedTensor in lazy (MMAP) placement.
6// The dequantized Q10 i64 storage is NOT allocated until the caller
7// invokes nx_placed_tensor_get / nx_placed_tensor_materialize.
8//
9// Honest architectural property (NOT a perf claim):
10// Each lazy handle is 88 bytes regardless of underlying tensor
11// size. At LOAD time the substrate holds the model as 88 *
12// n_tensors bytes of typed handles (e.g. ~25 KB for a Llama-7B
13// shape) without dequantizing anything. Materialization happens
14// per-tensor at first compute access; demote releases the
15// dequantized buffer back to the lazy state.
16//
17// This is semantically similar to llama.cpp's mmap + per-block
18// dequant-on-demand pattern. The structural difference: our handle
19// is a typed primitive a future conductor (Phase C dispatcher / Phase
20// D arbiter) can route, evict, and tier-promote. llama.cpp's lazy
21// dequant is in the matmul kernel internals, not exposed.
22//
23// NOT a claim:
24// - "lazy = smaller VRAM than CUDA" -- depends on working-set
25// and dispatcher; lazy alone proves nothing about peak RAM
26// - "lazy = faster than llama.cpp" -- llama.cpp's mmap path
27// achieves the same architectural property by a different name
28// - Any "Nx less RAM" ratio without measurement against a real
29// workload on real hardware
30//
31// Composition:
32// nx_placement.nx -- NxPlacedTensor + lifecycle
33// nx_gguf.nx -- header + tensor_info walker
34// nx_gguf_load.nx -- existing per-tensor canonical loader
35// (composed for materialization path)
36//
37// genealogy_id: numpy_memmap_pattern + huggingface_safetensors_lazy
38// lineage_id: substrate_gguf_lazy_loader_v1_conductor_phase_b
39
40// nx_safety_envelope:
41// intended_use: "Load a named GGUF tensor as a zero-RAM
42// lazy NxPlacedTensor; caller materializes
43// on demand"
44// sil_target: SIL2
45// asil_target: QM
46// dal_target: DAL C
47// evidence: [conductor_cardinal_2026-05-19,
48// composes_phase_a_proven, composes_existing_loaders]
49// hazard_register: [bug-tape-buf-freed-while-lazy-ref-held]
50// residual_risk: "Caller must keep gguf_buf alive as long
51// as any lazy ref exists"
52// verdict: NOT_YET_EVALUATED
53
54import "nx_syscalls.nx"
55import "nx_tier.nx"
56import "nx_tensor.nx"
57import "nx_gguf.nx"
58import "nx_gguf_load.nx"
59import "nx_placement.nx"
60
61// ===== Public: lazy load by name ==================================
62//
63// Same lookup semantics as nx_gguf_load_tensor; returns a lazy
64// NxPlacedTensor instead of materialized NxTensor.
65//
66// out_err verdicts:
67// NX_GL_OK on success
68// NX_GL_ERR_NOT_FOUND on miss
69// NX_GL_ERR_BAD_SHAPE on zero-element tensor
70
71func nx_gguf_load_tensor_lazy(buf: *u8, hdr: *NxGgufHeader,
72 name: *u8, name_len: nx_int,
73 out_err: *i64) -> *NxPlacedTensor {
74 let idx: nx_int = nx_gguf_find_tensor(hdr, name, name_len)
75 if idx < 0 {
76 out_err[0] = NX_GL_ERR_NOT_FOUND
77 return 0 as *NxPlacedTensor
78 }
79 let ti: *NxGgufTensorInfo = nx_gguf_tensor_at(hdr, idx)
80
81 let nv: i64 = nx_gguf_tensor_n_values(ti)
82 if nv <= 0 {
83 out_err[0] = NX_GL_ERR_BAD_SHAPE
84 return 0 as *NxPlacedTensor
85 }
86
87 // Shape buffer for the placement struct.
88 let shape: *i64 = sys_mmap(4 * 8) as *i64
89 shape[0] = ti.dim_0
90 shape[1] = ti.dim_1
91 shape[2] = ti.dim_2
92 shape[3] = ti.dim_3
93
94 let data_off: i64 = hdr.data_off + ti.offset
95
96 let p: *NxPlacedTensor = nx_placed_tensor_new_lazy(
97 buf, data_off,
98 ti.ggml_type, nv,
99 shape, ti.n_dims)
100
101 out_err[0] = NX_GL_OK
102 return p
103}
104
105// ===== Convenience: report lazy-handle footprint =================
106//
107// Returns the total bytes the lazy handles consume. Each
108// NxPlacedTensor is NX_PT_STRUCT_BYTES = 88 bytes regardless of the
109// underlying tensor size.
110//
111// This is a STRUCTURAL FACT about the handle representation, NOT a
112// perf claim against any other framework. Comparisons to CUDA /
113// PyTorch / llama.cpp peak RAM require running both on the same
114// model + workload + hardware and measuring -- the lazy-handle size
115// alone proves nothing about end-to-end resource use.
116
117func nx_gguf_lazy_handle_bytes(n_tensors: nx_int) -> i64 {
118 return n_tensors * NX_PT_STRUCT_BYTES
119}