code wiki / (root) / nx_nofloat_q4k.nx

nx_nofloat_q4k.nx

buildroot/runtime/nx_nofloat_q4k.nx

22824 B406 linesdepth 8pulls 21 transitivereach 45 importersview sourcekind librarytopic nofloat
docsdependenciesstructsconstsfunctions

about

nx_nofloat_q4k.nx -- LM4 RESIDENT-QUANT DECODE (2026-09-02): the 7B fits because the weights STAY Q4_K. MEASURED (nx_nofloat_llm.nx nf_alloc_layer_wb_i8): the "i8" layer cache stores 2 B/weight (i16 lanes for __i16x16_madd), so Qwen2.5-Coder-7B = 6.5e9 layer params = 13 GB of anonymous memory before the i32 head (2.2 GB), the copied model buffer (4.7 GB via sys_read_file) and the MAXT scratch -- it cannot fit a 16 GB WSL VM and no cache hygiene changes that. This lib keeps every Q4_K projection IN THE FILE MAP (0.5625 B/weight, file-backed, evictable) and dots it with the estate's fused SIMD kernel (nx_q4k_dot_simd_lib, bit-exact vs nx_q4k_dot_row_col), so a Q4_K layer costs 0 anonymous bytes. A tensor of any other quant type (Q4_K_M puts Q6_K on some attn_v/ffn_down rows) falls back PER TENSOR to the incumbent i16 cache (nf_quant_w_i8 + mm_pool_i8) -- counted and announced, never silent. NUMERIC CONTRACT (why the shift arithmetic is what it is): the serve keeps activations in Q16; its i8 path computes dst = (sx*sw*sum(xq*wq)) >> shift with W in Q16 (shift 24 for a Q24 rmsnorm input, 16 for a Q16 input). nx_q4k_dot_simd returns sum over the row of W_Q24 * col_i16 -- the weight carries 8 more fractional bits -- so dst = ((dot >> NQ_PRE_SHIFT) * sx) >> (shift + NQ_W_EXTRA_BITS - NQ_PRE_SHIFT). The activation is packed to i16 under a dynamic per-call scale sx = ceil(max|x| / 32767) (15 significant bits) where the i8 path packs to 7 bits: this route is STRICTLY MORE EXACT on the activation side and lossless on the weight side (the Q4_K bytes ARE the model). The pre-shift is overflow headroom: |dot| reaches ~1e16 on an 18944-wide ffn_down row and sx reaches ~2^19, so the product is taken after >>16. Duplicates deliberately NOT created: attention/softmax/residual come from nf_attn_kv_core (shared with the i8 decoder), the fallback matvec IS mm_pool_i8, the per-row quantiser IS nf_quant_w_i8. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 11 imports · 3 importers

nx_syscalls.nx nx_tier.nx nx_le.nx nx_tensor.nx nx_gguf.nx nx_gguf_load.nx nx_thread_pool.nx nx_nofloat_llm.nx nx_q4k_dot_simd_lib.nx nx_q4k_dot_simd2_lib.nx nx_nofloat_q4k.nx nx_nofloat_q4k_gate.nx nx_nofloat_serve_core.nx nx_q4k_simd2_gate.nx

diagram shows first 10 each side; +1 more imports, +0 more importers in the complete lists below.

imports: nx_syscalls.nxnx_tier.nxnx_le.nxnx_tensor.nxnx_gguf.nxnx_gguf_load.nxnx_thread_pool.nxnx_nofloat_llm.nxnx_q4k_dot_simd_lib.nxnx_q4k_dot_simd2_lib.nxnx_clock.nx

imported by: nx_nofloat_q4k_gate.nxnx_nofloat_serve_core.nxnx_q4k_simd2_gate.nx

structs

none

consts

33const NQ_KIND_Q4K: i64 = 0
34const NQ_KIND_I16: i64 = 1
35const NQ_KIND_Q8_0: i64 = 2 // search R0s (2026-09-17): Q8_0 blocks dotted in place from the file map (block-native)
36const NQ_Q8_BLOCK_VALS: i64 = 32 // Q8_0 block width
37const NQ_Q8_BLOCK_BYTES: i64 = 34 // one f16 scale (2 bytes) + 32 int8 codes
38const NQ_Q8_SCALE_BYTES: i64 = 2
39const NQ_SLOT_WORDS: i64 = 8 // kind, base_off, in_dim, out_dim, row_stride, w16, sw, n_blocks
40const NQ_S_KIND: i64 = 0
41const NQ_S_OFF: i64 = 1
42const NQ_S_IN: i64 = 2
43const NQ_S_OUT: i64 = 3
44const NQ_S_RSTRIDE: i64 = 4
45const NQ_S_W16: i64 = 5
46const NQ_S_SW: i64 = 6
47const NQ_S_NBLK: i64 = 7
48const NQ_NPROJ: i64 = 7 // q k v o gate up down
49const NQ_P_Q: i64 = 0
50const NQ_P_K: i64 = 1
51const NQ_P_V: i64 = 2
52const NQ_P_O: i64 = 3
53const NQ_P_GATE: i64 = 4
54const NQ_P_UP: i64 = 5
55const NQ_P_DOWN: i64 = 6
56const NQ_L_GA: i64 = 56 // NQ_NPROJ * NQ_SLOT_WORDS: attn_norm gamma (Q16 i64, ne)
57const NQ_L_GF: i64 = 57 // ffn_norm gamma
58const NQ_L_BQ: i64 = 58 // q/k/v biases (Q16 i64)
59const NQ_L_BK: i64 = 59
60const NQ_L_BV: i64 = 60
61const NQ_LAYER_WORDS: i64 = 64
62const NQ_SUPER_VALS: i64 = 256 // Q4_K super-block width
63const NQ_SUPER_BYTES: i64 = 144 // Q4_K super-block bytes
64const NQ_SUBBLOCKS: i64 = 8 // sub-blocks per super-block (sc_pre rows)
65const NQ_ACT_I16_MAX: i64 = 32767
66const NQ_W_EXTRA_BITS: i64 = 8 // W_Q24 vs the serve's Q16 weight convention
67const NQ_PRE_SHIFT: i64 = 16 // overflow headroom before multiplying by sx
68const NQ_SHIFT_Q24: i64 = 24 // input in Q24 (post-rmsnorm) -> Q16 out
69const NQ_SHIFT_Q16: i64 = 16 // input in Q16 (attention concat, silu*up) -> Q16 out
70const NQ_BANDS_MAX: i64 = 32
71const NQ_BAND_BYTES: i64 = 320 // ctx 128 + qpk 64 + qhi 64 + acc 32 + spare 32
72const NQ_CTX_BYTES: i64 = 128
73const NQ_QPK_BYTES: i64 = 64
74const NQ_ACC_OFF: i64 = 256
75const NQ_ST_WORDS: i64 = 8 // stats: [0]=inplace tensors [1]=fallback tensors [2]=fallback anon bytes [3]=layers [4]=inplace file bytes
87const NQ_PROF_WORDS: i64 = 6
88const NQ_PROF_Q4K_NS: i64 = 0
89const NQ_PROF_Q4K_CALLS: i64 = 1
90const NQ_PROF_I16_NS: i64 = 2
91const NQ_PROF_I16_CALLS: i64 = 3
92const NQ_PROF_Q8_NS: i64 = 4
93const NQ_PROF_Q8_CALLS: i64 = 5

functions

94func nq_prof() -> *i64 { if (g_nq_prof as i64) == 0 { g_nq_prof = sys_mmap(NQ_PROF_WORDS*8) as *i64 } return g_nq_prof }
called by 2: nq_prof_getnq_mm calls 1: sys_mmap
95func nq_prof_get(k: i64) -> i64 { let p: *i64 = nq_prof(); return p[k] }
called by 1: nsv_handle calls 1: nq_prof
99func nq_kind_for(ggml_type: i64, in_dim: i64) -> i64
called by 2: nq_slot_fillmain
104func nq_post_shift(shift: i64) -> i64 { return shift + NQ_W_EXTRA_BITS - NQ_PRE_SHIFT }
105func nq_scale_out(dot: i64, sx: i64, post: i64) -> i64 { return ((dot >> NQ_PRE_SHIFT) * sx) >> post }
108func nq_act_scale(xmx: i64) -> i64 { var sx: i64 = (xmx + NQ_ACT_I16_MAX - 1) / NQ_ACT_I16_MAX; if sx < 1 { sx = 1 } return sx }
109func nq_slot(lay: *i64, p: i64) -> *i64 { return ((lay as i64) + p*NQ_SLOT_WORDS*8) as *i64 }
111func nq_bind_buf(buf: *u8) -> i64 { g_nq_buf = buf; return 0 }
113func nq_arena(maxin: i64) -> i64
called by 2: nq_build_layersmain calls 1: sys_mmap
124func nq_slot_from_q16(Wq16: *i64, slot: *i64, in_dim: i64, out_dim: i64) -> i64
135func nq_slot_fill(buf: *u8, hdr: *NxGgufHeader, nm: *u8, L: i64, sfx: *u8, slot: *i64, in_dim: i64, out_dim: i64, tmp: *i64, st: *i64) -> i64
167func nq_load_vec(buf: *u8, hdr: *NxGgufHeader, nm: *u8, L: i64, sfx: *u8, n: i64) -> i64
called by 1: nq_build_layers calls 2: sys_mmapload_blk
174func nq_build_layers(buf: *u8, hdr: *NxGgufHeader, wq: *i64, N: i64, ne: i64, qd: i64, kvd: i64, fd: i64, nm: *u8, st: *i64) -> i64
205func _nq_mm_task(ctx_i: i64) -> i64
232func nq8_dot_row_scalar(buf: *u8, off: i64, nblk: i64, col16: *u8, w16: *u8) -> i64
257func nq8_dot_row(buf: *u8, off: i64, nblk: i64, col16: *u8, w16: *u8) -> i64
271func _nq8_mm_task(ctx_i: i64) -> i64
288func mq8_gemm(x: *i64, slot: *i64, dst: *i64, shift: i64) -> i64
320func nq_mm(x: *i64, slot: *i64, dst: *i64, shift: i64) -> i64
341func mq_fused_dequant_gemm(x: *i64, slot: *i64, dst: *i64, shift: i64) -> i64
374func decode_step_kv_q4k(x1: *i64, out1: *i64, wq: *i64, sb: *i64, freqs: *i64, kvc: *i64, pos: i64, cfgA: *i64, cfgF: *i64, N: i64) -> i64