nx_sum_bench_all.nx source
↩ module page · 119 lines · 4295 B
1// nx_sum_bench_all.nx -- comprehensive sum-of-N-i64 bench across
2// all NishiLang paths for cross-language comparison.
3//
4// Same workload as sum_c.c (N=1M i64 sum, 100 reps) but exercises
5// every parallelism axis NishiLang ships:
6//
7// 1. scalar single-thread, no SIMD
8// 2. parallel_reduce MIMD across pool workers
9// 3. SIMD-only i64x4 horizontal reduce in chunks of 4
10// 4. parallel + SIMD per-chunk SIMD reduce, parallel across chunks
11//
12// All paths produce bit-exact results vs the scalar reference.
13// Wall-time numbers are reported but qemu interpretive emulation
14// distorts both MIMD (single-CPU emulator) and SIMD (per-lane
15// interpretive cost), so the wall-time signal is noisy -- see
16// docs/PERF_NISHI_VS_C.md for the honest interpretation.
17
18// nx_safety_envelope:
19// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
20// sil_target: SIL1
21// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
22// verdict: NOT_YET_EVALUATED
23
24import "nx_kernel_v2.nx"
25import "nx_log.nx"
26import "nx_atom.nx"
27import "nx_clock.nx"
28import "nx_thread_pool.nx"
29import "nx_parallel.nx"
30import "nx_hw.nx"
31
32const N: i64 = 1000000
33const REPS: i64 = 10 // fewer reps than C bench --
34 // qemu interpretive overhead
35
36func scalar_sum(arr: *i64) -> i64 {
37 var s: i64 = 0
38 var i: i64 = 0
39 while i < N { s = s + arr[i]; i = i + 1 }
40 return s
41}
42
43func simd_sum(arr: *i64) -> i64 {
44 var s: i64 = 0
45 var i: i64 = 0
46 while i < N {
47 let p: *i64 = ((arr as i64) + i * 8) as *i64
48 let v: i64 = __simd_vload_i64_x4(p)
49 s = s + __simd_vreduce_sum_i64_x4(v)
50 i = i + 4
51 }
52 return s
53}
54
55func iadd(a: i64, b: i64) -> i64 { return a + b }
56
57func main() -> nx_exit {
58 var nw: i64 = nx_hw_worker_count()
59 if nw < 2 { nw = 2 }
60 let pool: *NxThreadPool = nx_pool_new(nw, 64)
61
62 let raw: *u8 = sys_mmap(N * 8)
63 let arr: *i64 = raw as *i64
64 var k: i64 = 0
65 while k < N { arr[k] = k; k = k + 1 }
66 let expected: i64 = (N - 1) * N / 2
67
68 println("=== nx_sum_bench_all -- all paths over N=1M, 10 reps ===" as *u8)
69 print_i64(nw); println(" pool workers" as *u8)
70
71 // ---- Path 1: scalar ----
72 let t0_s: i64 = nx_clock_monotonic_ns()
73 var sum_s: i64 = 0
74 var r1: i64 = 0
75 while r1 < REPS { sum_s = sum_s + scalar_sum(arr); r1 = r1 + 1 }
76 let t1_s: i64 = nx_clock_monotonic_ns()
77 if sum_s != expected * REPS { println("FAIL: scalar wrong" as *u8); return 1 }
78 println("scalar ns:" as *u8); print_i64(t1_s - t0_s); println("" as *u8)
79
80 // ---- Path 2: parallel_reduce ----
81 let t0_p: i64 = nx_clock_monotonic_ns()
82 var sum_p: i64 = 0
83 var r2: i64 = 0
84 while r2 < REPS {
85 sum_p = sum_p + nx_parallel_reduce_i64(pool, arr, N, 0, iadd)
86 r2 = r2 + 1
87 }
88 let t1_p: i64 = nx_clock_monotonic_ns()
89 if sum_p != expected * REPS { println("FAIL: parallel wrong" as *u8); return 2 }
90 println("parallel ns:" as *u8); print_i64(t1_p - t0_p); println("" as *u8)
91
92 // ---- Path 3: SIMD-only ----
93 let t0_v: i64 = nx_clock_monotonic_ns()
94 var sum_v: i64 = 0
95 var r3: i64 = 0
96 while r3 < REPS { sum_v = sum_v + simd_sum(arr); r3 = r3 + 1 }
97 let t1_v: i64 = nx_clock_monotonic_ns()
98 if sum_v != expected * REPS { println("FAIL: simd wrong" as *u8); return 3 }
99 println("simd ns:" as *u8); print_i64(t1_v - t0_v); println("" as *u8)
100
101 // ---- Path 4: parallel + SIMD (composed) ----
102 let t0_ps: i64 = nx_clock_monotonic_ns()
103 var sum_ps: i64 = 0
104 var r4: i64 = 0
105 while r4 < REPS {
106 sum_ps = sum_ps + nx_parallel_reduce_sum_simd_i64(pool, arr, N, 0)
107 r4 = r4 + 1
108 }
109 let t1_ps: i64 = nx_clock_monotonic_ns()
110 if sum_ps != expected * REPS { println("FAIL: parallel+simd wrong" as *u8); return 4 }
111 println("par+simd ns:" as *u8); print_i64(t1_ps - t0_ps); println("" as *u8)
112
113 nx_pool_shutdown(pool)
114 println("" as *u8)
115 println("All paths bit-exact (sum == (N-1)*N/2 = 499999500000)." as *u8)
116 println("Wall times under qemu interpretive emulation; see PERF_NISHI_VS_C.md" as *u8)
117 println("for honest interpretation + real-silicon projections." as *u8)
118 return 0
119}