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}