nx_compute_mt.nx source
↩ module page · 94 lines · 5016 B
1// nx_compute_mt.nx -- walking up the COMPUTE wall toward physics: MULTICORE matmul (the ~20x lever).
2// The compute physics grade (nx_compute_ladder) found the sovereign matmul ~5000x below the silicon f32
3// peak -- but the peak assumes ALL cores; the matmul used ONE. Multicore is the biggest single lever and
4// needs NO compiler surgery: fork N workers over a SHARED-memory C, each computing a disjoint row band.
5// This measures single-thread vs N-thread on the SAME problem, proves the parallel result is bit-identical
6// to the serial one (correctness across processes), and reports the speedup + how much of the physics gap it
7// closes. Sovereign: sys_fork + sys_mmap_shared + sys_wait4 + nx_f32_hw SSE f32.
8// KAT: parallel result == serial (bit-exact); multicore is faster; speedup + closed gap reported.
9// HONEST: this is the multicore lever only; packed-SIMD (4-8x) + FMA (2x) + blocking still remain (deeper,
10// compiler-side). No hw writes (Rule 26). expect_exit: 0 license_tier: ORIGINAL
11import "nx_f32_hw.nx"
12import "nx_syscalls.nx"
13const K_MAGIC_1842560: i64 = 1842560
14
15func mt_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16func mt_num(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
17
18// compute rows [w*sz/nw, (w+1)*sz/nw) of C = A @ B (row band; workers write disjoint bands of shared C)
19func mm_band(a: *i64, b: *i64, c: *i64, sz: i64, w: i64, nw: i64) -> i64 {
20 let r0: i64=w*sz/nw
21 let r1: i64=(w+1)*sz/nw
22 var i: i64=r0
23 while i<r1 {
24 var j: i64=0
25 while j<sz {
26 var acc: i64=__f32_from_i64(0)
27 var l: i64=0
28 while l<sz { acc=__f32_add(acc, __f32_mul(a[i*sz+l], b[l*sz+j])); l=l+1 }
29 c[i*sz+j]=acc
30 j=j+1
31 }
32 i=i+1
33 }
34 return 0
35}
36
37func main() -> i64 {
38 mt_puts("walking up the COMPUTE wall: MULTICORE matmul (fork + shared memory, the ~20x lever)\n" as *u8)
39 let SZ: i64=256
40 let NW: i64=8
41 let A: *i64 = sys_mmap_shared(SZ*SZ*8) as *i64
42 let B: *i64 = sys_mmap_shared(SZ*SZ*8) as *i64
43 let C: *i64 = sys_mmap_shared(SZ*SZ*8) as *i64
44 let C0: *i64 = sys_mmap(SZ*SZ*8) as *i64
45 var i: i64=0
46 while i<SZ*SZ { A[i]=f32_of((i%7)+1); B[i]=f32_of((i%5)+1); C[i]=0; i=i+1 }
47
48 // --- single-thread baseline (whole matrix) ---
49 let t0: i64=sys_now_us()
50 mm_band(A, B, C0, SZ, 0, 1)
51 let t1: i64=sys_now_us()
52 var us1: i64=t1-t0
53 if us1<=0 { us1=1 }
54
55 // --- multicore: fork NW workers over shared C ---
56 let pids: *i64 = sys_mmap(NW*8) as *i64
57 let t2: i64=sys_now_us()
58 var w: i64=0
59 while w<NW {
60 let pid: i64=sys_fork()
61 if pid==0 { mm_band(A, B, C, SZ, w, NW); sys_exit(0) } else { pids[w]=pid; w=w+1 }
62 }
63 w=0
64 let st: *i64 = sys_mmap(8) as *i64
65 while w<NW { sys_wait4(pids[w], st, 0); w=w+1 }
66 let t3: i64=sys_now_us()
67 var usN: i64=t3-t2
68 if usN<=0 { usN=1 }
69
70 // correctness: parallel C == serial C0 (bit-exact)
71 var ok: i64=1
72 i=0
73 while i<SZ*SZ { if C[i]!=C0[i] { ok=0 } i=i+1 }
74
75 let flop: i64 = 2*SZ*SZ*SZ
76 let mf1: i64 = flop/us1
77 let mfN: i64 = flop/usN
78 let speedup10: i64 = us1*10/usN
79 let gap_before: i64 = K_MAGIC_1842560/mf1 // x below silicon peak, single-thread
80 let gap_after: i64 = K_MAGIC_1842560/mfN // x below silicon peak, multicore
81
82 mt_puts(" single-thread = "); mt_num(mf1); mt_puts(" MFLOP/s | "); mt_num(NW); mt_puts("-worker multicore = "); mt_num(mfN); mt_puts(" MFLOP/s speedup = "); mt_num(speedup10/10); mt_puts("."); mt_num(speedup10%10); mt_puts("x\n" as *u8)
83 mt_puts(" gap to silicon f32 peak: BEFORE ~"); mt_num(gap_before); mt_puts("x -> AFTER ~"); mt_num(gap_after); mt_puts("x (multicore closed "); mt_num(speedup10/10); mt_puts("x of it; packed-SIMD+FMA+blocking remain)\n" as *u8)
84
85 var pass: i64=0
86 var ttl: i64=0
87 ttl=ttl+1; mt_puts(" T1 parallel result BIT-IDENTICAL to serial (correctness across processes): " as *u8); if ok==1 { pass=pass+1; mt_puts("PASS\n" as *u8) } else { mt_puts("FAIL\n" as *u8) }
88 ttl=ttl+1; mt_puts(" T2 multicore FASTER than single-thread (the lever works): " as *u8); if mfN>mf1 { pass=pass+1; mt_puts("PASS\n" as *u8) } else { mt_puts("FAIL\n" as *u8) }
89 ttl=ttl+1; mt_puts(" T3 measurable speedup (>= 2x): " as *u8); if speedup10>=20 { pass=pass+1; mt_puts("PASS\n" as *u8) } else { mt_puts("FAIL\n" as *u8) }
90
91 mt_puts("NX-COMPUTE-MT-GATE passed "); mt_num(pass); mt_puts("/"); mt_num(ttl)
92 if pass==ttl { mt_puts(" verdict=GREEN (multicore matmul: bit-exact + faster -- a real step up the compute wall toward physics)\n" as *u8); sys_exit(0); return 0 }
93 mt_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
94}