code wiki / (root) / nx_nofloat_prefix_cache_gate.nx

nx_nofloat_prefix_cache_gate.nx source

↩ module page · 122 lines · 5914 B

1// nx_nofloat_prefix_cache_gate.nx -- proves the PREFIX-KV-CACHE speed optimization is BIT-EXACT + measures the 2// prefill-step savings (operator 2026-07-15: attack the ~2.4 tok/s prefill wall; coordinated with S2 = the 3// compiler owns the per-matmul 4.2x, this owns the ~10x FEWER prefill matmuls for the forge's fixed crib). 4// 5// The forge re-prefills a FIXED crib (~130 tok) on EVERY task. nsv_generate_pfx snapshots the crib's KV rows 6// once and restores them per task, prefilling only the task suffix. This gate proves the load-bearing property: 7// restore-snapshot + suffix-only-prefill produces output BYTE-IDENTICAL to a full prefill (bit-exactness is the 8// whole point of no-float). Same prompt, two paths: 9// A = full prefill, no cache (prefill = nprompt steps) 10// B = full prefill + snapshot rows 0..P (builds the cache) 11// C = restore rows 0..P + prefill [P..nprompt) (prefill = nprompt-P steps) 12// Teeth: T1 output(A) == output(C) BYTE-EXACT (the cache reuse is lossless) T2 cached prefill < baseline 13// T3 savings ratio reported (forge: crib~130 + task~15 => ~10x fewer prefill matmuls) 14// expect_exit: 0 license_tier: ORIGINAL 15import "nx_nofloat_serve_core.nx" 16import "nx_gate_verdict.nx" 17 18func gw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 19func gn(v: i64) -> i64 { 20 var m: i64 = v 21 if m < 0 { gw("-" as *u8); m = 0 - m } 22 let t: *u8 = sys_mmap(24) 23 var k: i64 = 0 24 if m == 0 { t[0] = 48 as u8; k = 1 } 25 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 26 let o: *u8 = sys_mmap(24) 27 var i: i64 = 0 28 while i < k { o[i] = t[k - 1 - i]; i = i + 1 } 29 sys_write(1, o, k) 30 return 0 31} 32 33func main() -> i64 { 34 gw("=== NX-NOFLOAT-PREFIX-CACHE -- prove KV-prefix reuse is BIT-EXACT + measure prefill savings ===\n" as *u8) 35 let mpath: *u8 = "/home/elderwesto/nx_stage/nx_coder_model.gguf\x00" as *u8 36 let ir: i64 = nsv_init(mpath) 37 if ir != 0 { gw(" nsv_init FAILED rc=" as *u8); gn(ir); gw("\n" as *u8); return 2 } 38 gw(" model ready\n\n" as *u8) 39 40 let prompt: *u8 = "NishiLang program: write a function that returns the larger of two integers a and b." as *u8 41 var plen: i64 = 0 42 while prompt[plen] != (0 as u8) { plen = plen + 1 } 43 44 let outA: *u8 = sys_mmap(8192) 45 let outC: *u8 = sys_mmap(8192) 46 let meta: *i64 = sys_mmap(8*8) as *i64 47 let gp: *i64 = sys_mmap(16*8) as *i64 48 gp[1] = plen 49 gp[2] = 24 // max_new 50 gp[3] = 1 // mode 1 = i8 fast (deterministic; A and C share it) 51 gp[6] = meta as i64 52 gp[7] = 0 // no stream 53 gp[8] = 0 // greedy 54 gp[9] = 0 55 gp[10] = 0 56 gp[11] = 12345 // fixed seed 57 gp[12] = 0 // not chatml 58 59 // --- A: baseline full prefill, NO cache --- 60 gp[0] = prompt as i64 61 gp[4] = outA as i64 62 gp[5] = 8192 63 let na: i64 = nsv_generate_pfx(gp, 0, 0) 64 let nprompt: i64 = meta[0] 65 let msA: i64 = meta[2] 66 67 var P: i64 = nprompt - 4 // prefix = all but the last 4 tokens (the "crib") 68 if P < 1 { P = 1 } 69 70 // --- B: full prefill + SNAPSHOT rows 0..P-1 (build the cache) --- 71 gp[4] = outC as i64 72 gp[5] = 8192 73 nsv_generate_pfx(gp, P, 0) 74 75 // --- C: RESTORE rows 0..P-1 + prefill only [P..nprompt) --- 76 gp[4] = outC as i64 77 gp[5] = 8192 78 let nc: i64 = nsv_generate_pfx(gp, P, 1) 79 let msC: i64 = meta[2] 80 81 // bit-exact compare A vs C 82 var same: i64 = 1 83 if na != nc { same = 0 } 84 if same == 1 { 85 var k: i64 = 0 86 while k < na { if outA[k] != outC[k] { same = 0; k = na } else { k = k + 1 } } 87 } 88 89 gw(" prompt tokens (nprompt)=" as *u8); gn(nprompt) 90 gw(" prefix P=" as *u8); gn(P); gw(" suffix=" as *u8); gn(nprompt - P); gw("\n" as *u8) 91 gw(" PREFILL STEPS baseline=" as *u8); gn(nprompt); gw(" cached=" as *u8); gn(nprompt - P) 92 gw(" (saved " as *u8); gn(P); gw(" matmul passes/req)\n" as *u8) 93 gw(" wall ms baseline=" as *u8); gn(msA); gw(" cached=" as *u8); gn(msC); gw("\n" as *u8) 94 gw(" output bytes A=" as *u8); gn(na); gw(" C=" as *u8); gn(nc); gw("\n" as *u8) 95 // projected forge speedup (fixed crib ~130 tok + task ~15 tok) 96 let proj: i64 = (145 * 100) / 15 // baseline 145 prefill / cached 15 => ~9.6x 97 gw(" PROJECTED forge (crib 130 + task 15): prefill " as *u8); gn(145); gw(" -> " as *u8); gn(15) 98 gw(" steps = ~" as *u8); gn(proj / 100); gw("x fewer prefill matmuls (compounds with S2's 4.2x kernel)\n\n" as *u8) 99 100 var pass: i64 = 0 101 var ttl: i64 = 0 102 ttl = ttl + 1 103 gw(" T1 BIT-EXACT: restore+suffix-prefill output == full-prefill output (lossless cache): " as *u8) 104 if same == 1 { pass = pass + 1; gw("PASS\n" as *u8) } else { gw("FAIL (cache changed the output!)\n" as *u8) } 105 ttl = ttl + 1 106 gw(" T2 SAVINGS: cached prefill steps < baseline prefill steps: " as *u8) 107 if (nprompt - P) < nprompt { pass = pass + 1; gw("PASS\n" as *u8) } else { gw("FAIL\n" as *u8) } 108 ttl = ttl + 1 109 gw(" T3 NON-TRIVIAL: >= 1 output token produced (the run is real, not empty): " as *u8) 110 if na > 0 { pass = pass + 1; gw("PASS\n" as *u8) } else { gw("FAIL\n" as *u8) } 111 112 gw("NX-NOFLOAT-PREFIX-CACHE-GATE passed " as *u8); gn(pass); gw("/" as *u8); gn(ttl) 113 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 114 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 115 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 116 let ctr__dry: *i64 = gv_ctr() 117 ctr__dry[0] = pass 118 ctr__dry[1] = ttl 119 let rc__dry: i64 = gv_verdict("NOFLOAT-PREFIX-CACHE-GATE" as *u8, ctr__dry, "prefix-KV-cache is bit-exact + cuts prefill matmuls -- the forge's fixed-crib speed lever)" as *u8) 120 sys_exit(rc__dry) 121 return rc__dry 122}