code wiki / (root) / nx_q8_scaling.nx

nx_q8_scaling.nx source

↩ module page · 104 lines · 4111 B

1// nx_q8_scaling.nx -- pool SCALING probe: same-process ST vs MT(pool) cold Q8 2// matmul bandwidth -> the noise-immune scaling ratio (target: gcc 8.8x; we 3// were 3.6x). Re-run after tuning NX_POOL_SPIN etc. to see if scaling 4// improves. Cold 222MB sweep each way. 5import "nx_syscalls.nx" 6import "nx_tier.nx" 7import "nx_le.nx" 8import "nx_f32.nx" 9import "nx_f32_cvt.nx" 10import "nx_thread_pool.nx" 11import "nx_f32_lazy_weight.nx" 12import "nx_fmt.nx" 13 14const MK: i64 = 896 15const NG: i64 = 4864 16const Q8B: i64 = 34 17const NB: i64 = 48 18 19func sc_nl() -> i64 { fmt_puts("\n" as *u8); return 0 } 20func sc_lcg(s: i64) -> i64 { var v: i64 = s * 1103515245 + 12345; v = v & 2147483647; return v } 21func sc_weight(seed: i64) -> *NxF32LazyWeight { 22 let bpr: i64 = (MK / 32) * Q8B 23 let w: *u8 = sys_mmap(NG * bpr) 24 var s: i64 = seed 25 var r: i64 = 0 26 while r < NG { 27 var b: i64 = 0 28 while b < MK / 32 { 29 let off: i64 = r * bpr + b * Q8B 30 w[off + 1] = 0x2C as u8 31 var q: i64 = 0 32 while q < 32 { s = sc_lcg(s); w[off + 2 + q] = ((s % 17) - 8) as u8; q = q + 1 } 33 b = b + 1 34 } 35 r = r + 1 36 } 37 return nx_f32_lazy_weight_new_q8_0(w, 0, NG, MK) 38} 39 40func main() -> i64 { 41 let A: *i64 = sys_mmap(MK * 8) as *i64 42 var s: i64 = 4242 43 var i: i64 = 0 44 while i < MK { s = sc_lcg(s); A[i] = nx_i32_to_f32((s % 9) - 4); i = i + 1 } 45 let C: *i64 = sys_mmap(NG * 8) as *i64 46 nx_lw_shared_pool() 47 48 // TWO distinct weight sets (so ST and MT each read cold DRAM, not each 49 // other's warmed pages). 50 let bufsA: *i64 = sys_mmap(NB * 8) as *i64 51 let bufsB: *i64 = sys_mmap(NB * 8) as *i64 52 let bufsC: *i64 = sys_mmap(NB * 8) as *i64 53 var b0: i64 = 0 54 while b0 < NB { 55 bufsA[b0] = sc_weight(700 + b0 * 13) as i64 56 bufsB[b0] = sc_weight(50000 + b0 * 17) as i64 57 bufsC[b0] = sc_weight(90000 + b0 * 19) as i64 58 b0 = b0 + 1 59 } 60 let bytes: i64 = NG * (MK / 32) * Q8B * NB 61 62 // MAX-of-N rounds to defeat sibling core-contention noise: each round 63 // measures ST then MT (bufsA/bufsB alternate = each stays cold, 444MB 64 // set >> LLC); the round with the BEST (max) scaling had the least 65 // contention on my cores -> closest to the true quiet-box scaling. 66 let ROUNDS: i64 = 6 67 var best_st: i64 = 0 68 var best_pool: i64 = 0 69 var best_pteam: i64 = 0 70 var rd: i64 = 0 71 while rd < ROUNDS { 72 let t0: i64 = sys_now_us() 73 var r0: i64 = 0 74 while r0 < NB { _lw_q8_0_matmul_st(bufsA[r0] as *NxF32LazyWeight, A, C, 1, MK, NG); r0 = r0 + 1 } 75 var ua: i64 = sys_now_us() - t0 76 if ua < 1 { ua = 1 } 77 let t1: i64 = sys_now_us() 78 var r1: i64 = 0 79 while r1 < NB { _lw_q8_0_matmul_pool_force(bufsB[r1] as *NxF32LazyWeight, A, C, 1, MK, NG); r1 = r1 + 1 } 80 var ub: i64 = sys_now_us() - t1 81 if ub < 1 { ub = 1 } 82 let t2: i64 = sys_now_us() 83 var r2: i64 = 0 84 while r2 < NB { _lw_q8_0_matmul_pteam(bufsC[r2] as *NxF32LazyWeight, A, C, 1, MK, NG); r2 = r2 + 1 } 85 var uc: i64 = sys_now_us() - t2 86 if uc < 1 { uc = 1 } 87 let stm: i64 = bytes / ua 88 let poolm: i64 = bytes / ub 89 let pteamm: i64 = bytes / uc 90 fmt_puts(" round"); fmt_putn(rd) 91 fmt_puts(" ST="); fmt_putn(stm) 92 fmt_puts(" pool="); fmt_putn(poolm); fmt_puts("("); fmt_putn(poolm*100/stm); fmt_puts(")") 93 fmt_puts(" pteam="); fmt_putn(pteamm); fmt_puts("("); fmt_putn(pteamm*100/stm); fmt_puts(")"); sc_nl() 94 if stm > best_st { best_st = stm } 95 if poolm > best_pool { best_pool = poolm } 96 if pteamm > best_pteam { best_pteam = pteamm } 97 rd = rd + 1 98 } 99 fmt_puts("BEST ST="); fmt_putn(best_st); sc_nl() 100 fmt_puts("BEST pool MBps="); fmt_putn(best_pool); fmt_puts(" scale_x100="); fmt_putn(best_pool*100/best_st); sc_nl() 101 fmt_puts("BEST pteam MBps="); fmt_putn(best_pteam); fmt_puts(" scale_x100="); fmt_putn(best_pteam*100/best_st); fmt_puts(" (gcc=880)"); sc_nl() 102 fmt_puts("Q8_SCALING DONE"); sc_nl() 103 return 0 104}