code wiki / (root) / nx_natbw_mt.nx

nx_natbw_mt.nx source

↩ module page · 95 lines · 3235 B

1// nx_natbw_mt.nx -- MULTI-THREAD memory-bandwidth probe (native-vs-WSL2). 2// 3// N threads each stream their OWN 64MB buffer (4-acc, BW_PASSES times) and set a 4// done-flag; main spins until all set (no join syscall -> works identically on 5// Linux clone AND native CreateThread). Aggregate traffic = N*PASSES*64MB. 6// Timing is EXTERNAL (Measure-Command / date). Threads spawn via sys_thread_create, 7// a NAMED shim the native-PE emitter PATCHES to a CreateThread thunk (Linux path = 8// nx_thread_spawn/clone). This is the decisive test: does native MT bandwidth scale 9// past WSL2's ~9.5 GB/s pool plateau toward gcc's ~39 GB/s? 10// 11// license_tier: ORIGINAL expect_exit: 0 12import "nx_syscalls.nx" 13import "nx_thread.nx" 14const BW_MAGIC_1048576: i64 = 1048576 15 16const BW_PER: i64 = 67108864 // 64MB per thread (> L3 slice -> DRAM-bound) 17const BW_PASSES: i64 = 24 18const BW_NT: i64 = 16 // threads (box has 20 logical cores) 19 20// worker ctx -> i64[3] = [buf_ptr, n8, done_addr]. Sets *done = nonzero when finished. 21func bw_worker(ctx: i64) -> i64 { 22 let c: *i64 = ctx as *i64 23 let p: *i64 = c[0] as *i64 24 let n8: i64 = c[1] 25 let done: *i64 = c[2] as *i64 26 var s0: i64 = 0 27 var s1: i64 = 0 28 var s2: i64 = 0 29 var s3: i64 = 0 30 var pass: i64 = 0 31 while pass < BW_PASSES { 32 var j: i64 = 0 33 while j + 3 < n8 { 34 s0 = s0 + p[j] 35 s1 = s1 + p[j + 1] 36 s2 = s2 + p[j + 2] 37 s3 = s3 + p[j + 3] 38 j = j + 4 39 } 40 pass = pass + 1 41 } 42 var r: i64 = s0 + s1 + s2 + s3 43 if r == 0 { r = 1 } // ensure nonzero so the done-spin sees completion 44 done[0] = r 45 return 0 46} 47 48// sys_thread_create(argptr): argptr -> i64[2] = [fn_addr, ctx_addr]. 49// Linux: real clone via nx_thread_spawn. Native: emitter overwrites this entry 50// with `jmp -> CreateThread thunk` (the body below is then dead code). 51func sys_thread_create(argptr: i64) -> i64 { 52 let a: *i64 = argptr as *i64 53 return nx_thread_spawn(a[0], a[1], BW_MAGIC_1048576) 54} 55 56func main() -> i64 { 57 let n8: i64 = BW_PER / 8 58 let dones: *i64 = sys_mmap(BW_NT * 8) as *i64 59 var i: i64 = 0 60 while i < BW_NT { 61 let buf: *i64 = sys_mmap(BW_PER) as *i64 62 var f: i64 = 0 63 while f < n8 { buf[f] = f + 1; f = f + 1 } 64 let ctx: *i64 = sys_mmap(24) as *i64 65 ctx[0] = buf as i64 66 ctx[1] = n8 67 ctx[2] = (dones as i64) + i * 8 68 dones[i] = 0 69 let argp: *i64 = sys_mmap(16) as *i64 70 argp[0] = bw_worker as i64 71 argp[1] = ctx as i64 72 sys_thread_create(argp as i64) 73 i = i + 1 74 } 75 // spin until every worker's done-flag is nonzero (x86 aligned load = atomic). 76 var alldone: i64 = 0 77 while alldone == 0 { 78 alldone = 1 79 var k: i64 = 0 80 while k < BW_NT { 81 if dones[k] == 0 { alldone = 0 } 82 k = k + 1 83 } 84 } 85 var agg: i64 = 0 86 var m: i64 = 0 87 while m < BW_NT { agg = agg + dones[m]; m = m + 1 } 88 if agg < 0 { agg = 0 - agg } 89 let obuf: *u8 = sys_mmap(16) 90 obuf[0] = (48 + (agg - (agg / 10) * 10)) as u8 91 obuf[1] = 10 as u8 92 sys_write(1, obuf, 2) 93 sys_exit(0) 94 return 0 95}