code wiki / (root) / nx_q4k_matmul_x4_gate.nx

nx_q4k_matmul_x4_gate.nx source

↩ module page · 314 lines · 11851 B

1// nx_q4k_matmul_x4_gate.nx -- adversarial gate for the PACKED-SIMD 2// Q4_K matmul paths (nx_f32_q4k_matmul_x4 / _pool_x4) against the 3// scalar serial oracle nx_f32_q4k_matmul. 4// 5// NUMERIC REGIME: the x4 path sums each output cell as left-to-right 6// 4-lane dot chunks -- a different f32 rounding order than scalar. 7// This gate therefore constructs data where EVERY intermediate sum is 8// an integer with |sum| < 2^24, so f32 addition is EXACT regardless 9// of order and bit-exact comparison across ALL paths is legitimate: 10// * weights: dense synthetic Q4_K blocks with d=1.0 (f16 0x3C00), 11// dmin=0, all 6-bit scales=1, mins=0, LCG nibble bytes -> every 12// dequantized value is an exact integer 0..15; 13// * A: exact small-int f32 (nx_i32_to_f32 of LCG ints). 14// k=512 lanes, |A|<=512, w<=15 -> |cell| <= 512*15*512 = 3.9M < 2^24. 15// Big shape k=1024, |A|<=512 -> <= 7.9M < 2^24. Exact. 16// (ULP-divergent real-model fidelity is witnessed separately by the 17// argmax probe -- " Paris" -- after the dispatcher flip.) 18// 19// pool-x4 vs serial-x4 equality holds on ANY data (identical per-cell 20// order; column banding never splits a cell) -- asserted here too. 21// 22// Checks (10): 23// 1 scalar serial oracle OK (m=3, k=512, n=37 -- prime n) 24// 2 serial-x4 == scalar bit-exact 25// 3 pool-x4 (auto pool) == serial-x4 bit-exact 26// 4 pool-x4 (3-worker pool, odd banding) == serial-x4 27// 5 pool reuse: second call, new A, same pool == fresh serial-x4 28// 6 m=1 decode shape: serial-x4 == scalar 29// 7 wide-A (+-512 ints): serial-x4 == scalar (exact-regime bound) 30// 8 n=1 single-column edge via pool (band clamp) == scalar 31// 9 SPEEDUP ladder on decode shape m=1 k=1024 n=4864: serial-scalar 32// vs pool-scalar vs pool-x4 (all bit-exact vs each other in this 33// regime); floor: pool-x4 >= 2.5x serial-scalar (measured printed) 34// 10 all three big-shape outputs bit-identical 35// 36// genealogy_id: nx_f32x4_mt_matmul (5.0x packed lever) + q4k_matmul_mt_gate 37// lineage_id: q4k_matmul_x4_gate_v1 38 39import "nx_f32_q4k_matmul.nx" 40import "nx_fmt.nx" 41import "nx_gate_verdict.nx" 42 43const XG_M: i64 = 3 44const XG_K: i64 = 512 45const XG_N: i64 = 37 46 47const XB_K: i64 = 1024 48const XB_N: i64 = 4864 49const XB_REPS: i64 = 3 50 51const XG_SPEEDUP_FLOOR_X100: i64 = 250 52 53func x_lcg(s: i64) -> i64 { 54 var v: i64 = s * 1103515245 + 12345 55 v = v & 2147483647 56 return v 57} 58 59// Dense exact-regime Q4_K super-block: d=1.0, dmin=0, sc[0..7]=1, 60// m[0..7]=0, LCG nibble bytes -> dequant values = exact ints 0..15. 61func x_block_dense(buf: *u8, off: i64, seed: i64) -> i64 { 62 buf[off + 0] = 0x00 as u8 63 buf[off + 1] = 0x3C as u8 // d = f16 1.0 (LE) 64 buf[off + 2] = 0 as u8 65 buf[off + 3] = 0 as u8 // dmin = 0 66 var i: i64 = 0 67 while i < 4 { 68 buf[off + 4 + i] = 0x01 as u8 // sc0..3 = 1 (high bits 0) 69 buf[off + 8 + i] = 0x00 as u8 // m0..3 = 0 (high bits 0) 70 buf[off + 12 + i] = 0x01 as u8 // sc4..7 = 1 (low nib), m4..7 = 0 (high nib) 71 i = i + 1 72 } 73 var s: i64 = seed 74 var z: i64 = 0 75 while z < 128 { 76 s = x_lcg(s) 77 buf[off + 16 + z] = (s & 255) as u8 78 z = z + 1 79 } 80 return off + 144 81} 82 83// n_rows weight rows, each (k/256) dense blocks. 84func x_fill_weights(buf: *u8, n_rows: i64, k: i64, seed: i64) -> i64 { 85 let bpr: i64 = (k / 256) * 144 86 var s: i64 = seed 87 var r: i64 = 0 88 while r < n_rows { 89 var b: i64 = 0 90 while b < k / 256 { 91 s = x_lcg(s) 92 x_block_dense(buf, r * bpr + b * 144, s) 93 b = b + 1 94 } 95 r = r + 1 96 } 97 return 0 98} 99 100// A fill: exact ints in [-half, half-1] as f32. 101func x_fill_a(p: *i64, count: i64, seed: i64, half: i64) -> i64 { 102 var s: i64 = seed 103 var i: i64 = 0 104 while i < count { 105 s = x_lcg(s) 106 let v: i64 = (s % (half + half)) - half 107 p[i] = nx_i32_to_f32(v) 108 i = i + 1 109 } 110 return 0 111} 112 113func x_poison(p: *i64, count: i64) -> i64 { 114 let pv: i64 = 0 - 777777 115 var i: i64 = 0 116 while i < count { 117 p[i] = pv 118 i = i + 1 119 } 120 return 0 121} 122 123func x_same(a: *i64, b: *i64, count: i64) -> i64 { 124 var i: i64 = 0 125 while i < count { 126 if a[i] != b[i] { return 0 } 127 i = i + 1 128 } 129 return 1 130} 131 132func x_nl() -> i64 { 133 fmt_puts("\n" as *u8) 134 return 0 135} 136 137func main() -> i64 { 138 let a_n: i64 = XG_M * XG_K 139 let b_n: i64 = XG_N * (XG_K / 256) * 144 140 let c_n: i64 = XG_M * XG_N 141 let A: *i64 = sys_mmap(a_n * 8) as *i64 142 let B: *u8 = sys_mmap(b_n) 143 let Cs: *i64 = sys_mmap(c_n * 8) as *i64 144 let Cx: *i64 = sys_mmap(c_n * 8) as *i64 145 let Cp: *i64 = sys_mmap(c_n * 8) as *i64 146 x_fill_a(A, a_n, 20260708, 5) 147 x_fill_weights(B, XG_N, XG_K, 424242) 148 149 var pass: i64 = 0 150 151 // ---- 1: scalar oracle ---- 152 let v1: nx_int = nx_f32_q4k_matmul(A, B, 0, Cs, XG_M, XG_K, XG_N) 153 if v1 != NX_FQ4M_OK { fmt_puts("X4G 1 SCALAR FAIL"); x_nl(); return 11 } 154 fmt_puts("X4G 1 SCALAR OK"); x_nl() 155 pass = pass + 1 156 157 // ---- 2: serial-x4 == scalar ---- 158 x_poison(Cx, c_n) 159 let v2: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, Cx, XG_M, XG_K, XG_N) 160 var ok2: i64 = 0 161 if v2 == NX_FQ4M_OK { ok2 = x_same(Cx, Cs, c_n) } 162 if ok2 != 1 { fmt_puts("X4G 2 X4-SERIAL FAIL"); x_nl(); return 12 } 163 fmt_puts("X4G 2 X4-SERIAL EXACT OK"); x_nl() 164 pass = pass + 1 165 166 // ---- 3: pool-x4 (auto) == serial-x4 ---- 167 let poolA: *NxThreadPool = nx_pool_new(0, 0) 168 x_poison(Cp, c_n) 169 let v3: nx_int = nx_f32_q4k_matmul_pool_x4(poolA, A, B, 0, Cp, XG_M, XG_K, XG_N) 170 var ok3: i64 = 0 171 if v3 == NX_FQ4M_OK { ok3 = x_same(Cp, Cx, c_n) } 172 if ok3 != 1 { fmt_puts("X4G 3 POOL-AUTO FAIL"); x_nl(); return 13 } 173 fmt_puts("X4G 3 POOL-AUTO EXACT OK"); x_nl() 174 pass = pass + 1 175 176 // ---- 4: pool-x4 (3 workers, odd banding over prime n) ---- 177 let pool3: *NxThreadPool = nx_pool_new(3, 0) 178 x_poison(Cp, c_n) 179 let v4: nx_int = nx_f32_q4k_matmul_pool_x4(pool3, A, B, 0, Cp, XG_M, XG_K, XG_N) 180 var ok4: i64 = 0 181 if v4 == NX_FQ4M_OK { ok4 = x_same(Cp, Cx, c_n) } 182 if ok4 != 1 { fmt_puts("X4G 4 POOL-3 FAIL"); x_nl(); return 14 } 183 fmt_puts("X4G 4 POOL-3 EXACT OK"); x_nl() 184 pass = pass + 1 185 186 // ---- 5: pool reuse, new A contents, same pools ---- 187 x_fill_a(A, a_n, 555008, 5) 188 let v5s: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, Cx, XG_M, XG_K, XG_N) 189 if v5s != NX_FQ4M_OK { return 15 } 190 x_poison(Cp, c_n) 191 let v5: nx_int = nx_f32_q4k_matmul_pool_x4(pool3, A, B, 0, Cp, XG_M, XG_K, XG_N) 192 var ok5: i64 = 0 193 if v5 == NX_FQ4M_OK { ok5 = x_same(Cp, Cx, c_n) } 194 nx_pool_shutdown(pool3) 195 if ok5 != 1 { fmt_puts("X4G 5 POOL-REUSE FAIL"); x_nl(); return 15 } 196 fmt_puts("X4G 5 POOL-REUSE EXACT OK"); x_nl() 197 pass = pass + 1 198 199 // ---- 6: m=1 decode shape ---- 200 let c1: *i64 = sys_mmap(XG_N * 8) as *i64 201 let c1x: *i64 = sys_mmap(XG_N * 8) as *i64 202 let v6s: nx_int = nx_f32_q4k_matmul(A, B, 0, c1, 1, XG_K, XG_N) 203 x_poison(c1x, XG_N) 204 let v6x: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, c1x, 1, XG_K, XG_N) 205 var ok6: i64 = 0 206 if v6s == NX_FQ4M_OK { if v6x == NX_FQ4M_OK { ok6 = x_same(c1x, c1, XG_N) } } 207 if ok6 != 1 { fmt_puts("X4G 6 M1 FAIL"); x_nl(); return 16 } 208 fmt_puts("X4G 6 M1 EXACT OK"); x_nl() 209 pass = pass + 1 210 211 // ---- 7: wide-A ints (+-512), still exact regime ---- 212 x_fill_a(A, a_n, 909008, 512) 213 let v7s: nx_int = nx_f32_q4k_matmul(A, B, 0, Cs, XG_M, XG_K, XG_N) 214 x_poison(Cx, c_n) 215 let v7x: nx_int = nx_f32_q4k_matmul_x4(A, B, 0, Cx, XG_M, XG_K, XG_N) 216 var ok7: i64 = 0 217 if v7s == NX_FQ4M_OK { if v7x == NX_FQ4M_OK { ok7 = x_same(Cx, Cs, c_n) } } 218 if ok7 != 1 { fmt_puts("X4G 7 WIDE-A FAIL"); x_nl(); return 17 } 219 fmt_puts("X4G 7 WIDE-A EXACT OK"); x_nl() 220 pass = pass + 1 221 222 // ---- 8: n=1 single column via pool (band clamp 16 -> 1) ---- 223 let cs1: *i64 = sys_mmap(XG_M * 8) as *i64 224 let cp1: *i64 = sys_mmap(XG_M * 8) as *i64 225 let v8s: nx_int = nx_f32_q4k_matmul(A, B, 0, cs1, XG_M, XG_K, 1) 226 x_poison(cp1, XG_M) 227 let v8p: nx_int = nx_f32_q4k_matmul_pool_x4(poolA, A, B, 0, cp1, XG_M, XG_K, 1) 228 var ok8: i64 = 0 229 if v8s == NX_FQ4M_OK { if v8p == NX_FQ4M_OK { ok8 = x_same(cp1, cs1, XG_M) } } 230 if ok8 != 1 { fmt_puts("X4G 8 N1-CLAMP FAIL"); x_nl(); return 18 } 231 fmt_puts("X4G 8 N1-CLAMP EXACT OK"); x_nl() 232 pass = pass + 1 233 234 // ---- 9+10: speedup ladder on the decode shape ---- 235 let ba_n: i64 = XB_K 236 let bb_n: i64 = XB_N * (XB_K / 256) * 144 237 let bc_n: i64 = XB_N 238 let BA: *i64 = sys_mmap(ba_n * 8) as *i64 239 let BB: *u8 = sys_mmap(bb_n) 240 let BC0: *i64 = sys_mmap(bc_n * 8) as *i64 241 let BC1: *i64 = sys_mmap(bc_n * 8) as *i64 242 let BC2: *i64 = sys_mmap(bc_n * 8) as *i64 243 x_fill_a(BA, ba_n, 7788, 512) 244 x_fill_weights(BB, XB_N, XB_K, 313373) 245 246 let t0: i64 = sys_now_us() 247 let vb0: nx_int = nx_f32_q4k_matmul(BA, BB, 0, BC0, 1, XB_K, XB_N) 248 let us_scalar: i64 = sys_now_us() - t0 249 if vb0 != NX_FQ4M_OK { return 21 } 250 251 x_poison(BC1, bc_n) 252 let t1: i64 = sys_now_us() 253 var r1: i64 = 0 254 while r1 < XB_REPS { 255 let vb1: nx_int = nx_f32_q4k_matmul_pool(poolA, BA, BB, 0, BC1, 1, XB_K, XB_N) 256 if vb1 != NX_FQ4M_OK { return 22 } 257 r1 = r1 + 1 258 } 259 let us_ps: i64 = (sys_now_us() - t1) / XB_REPS 260 261 x_poison(BC2, bc_n) 262 let t2: i64 = sys_now_us() 263 var r2: i64 = 0 264 while r2 < XB_REPS { 265 let vb2: nx_int = nx_f32_q4k_matmul_pool_x4(poolA, BA, BB, 0, BC2, 1, XB_K, XB_N) 266 if vb2 != NX_FQ4M_OK { return 23 } 267 r2 = r2 + 1 268 } 269 let us_px: i64 = (sys_now_us() - t2) / XB_REPS 270 nx_pool_shutdown(poolA) 271 272 let macs: i64 = XB_K * XB_N 273 var us_a: i64 = us_scalar 274 if us_a < 1 { us_a = 1 } 275 var us_b: i64 = us_ps 276 if us_b < 1 { us_b = 1 } 277 var us_c: i64 = us_px 278 if us_c < 1 { us_c = 1 } 279 fmt_puts("serial_scalar_us="); fmt_putn(us_a); fmt_puts(" mflops="); fmt_putn(2 * macs / us_a); x_nl() 280 fmt_puts("pool_scalar_us="); fmt_putn(us_b); fmt_puts(" mflops="); fmt_putn(2 * macs / us_b); x_nl() 281 fmt_puts("pool_x4_us="); fmt_putn(us_c); fmt_puts(" mflops="); fmt_putn(2 * macs / us_c); x_nl() 282 let sx100: i64 = us_a * 100 / us_c 283 fmt_puts("x4_vs_scalar_x100="); fmt_putn(sx100); x_nl() 284 285 if sx100 < XG_SPEEDUP_FLOOR_X100 { 286 fmt_puts("X4G 9 SPEEDUP FAIL"); x_nl() 287 return 24 288 } 289 fmt_puts("X4G 9 SPEEDUP OK"); x_nl() 290 pass = pass + 1 291 292 var okb: i64 = x_same(BC1, BC0, bc_n) 293 if okb == 1 { okb = x_same(BC2, BC0, bc_n) } 294 if okb != 1 { 295 fmt_puts("X4G 10 BIG-TRIPLE-EXACT FAIL"); x_nl() 296 return 25 297 } 298 fmt_puts("X4G 10 BIG-TRIPLE-EXACT OK"); x_nl() 299 pass = pass + 1 300 301 fmt_puts("Q4K_MATMUL_X4_GATE "); fmt_putn(pass); fmt_puts("/10 GREEN"); x_nl() 302 // MIGRATED onto nx_gate_verdict (D001, minimal form). Every check row above is UNTOUCHED, so the 303 // PASS/FAIL vector cannot change; only the hand-rolled verdict emission is replaced by the one 304 // shared base class. WHY IT MATTERS BEYOND HYGIENE: all three Q4_K gates rolled their own verdict, 305 // so /api/promote refused all three, so /api/gate_run could never find <name>.elf -- which left the 306 // Q4_K matmul with NO PROMOTABLE ORACLE AT ALL and effectively FROZE the kernel. Not by anyone 307 // deciding it should be frozen, but because a verdict-hygiene rule was never counted against the 308 // gates it disqualifies. Migrating ONE gate restores the ability to verify the whole subsystem. 309 let ctr__dry: *i64 = gv_ctr() 310 ctr__dry[0] = pass 311 ctr__dry[1] = 10 312 let rc__dry: i64 = gv_verdict("Q4K-MATMUL-X4-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto nx_gate_verdict so the evidence plane can read it" as *u8) 313 return rc__dry 314}