nx_i8dot_ab.nx source
↩ module page · 50 lines · 1872 B
1// nx_i8dot_ab.nx -- same-process kernel A/B: SSE __f32_i8dot32 vs AVX2
2// __f32_i8dot32a. Tight loop, same data -> noise-immune ns/call ratio +
3// exact-int equality check (they differ in FP order for random data, but
4// exact-int inputs are order-independent -> must match). expect_exit: 0
5import "nx_syscalls.nx"
6import "nx_tier.nx"
7import "nx_f32.nx"
8import "nx_f32_cvt.nx"
9import "nx_fmt.nx"
10const K_MAGIC_20000000: i64 = 20000000
11
12func ab_nl() -> i64 { fmt_puts("\n" as *u8); return 0 }
13func st4(p: *u8, idx: i64, bits: i64) -> i64 {
14 p[idx*4+0]=bits as u8; p[idx*4+1]=(bits>>8) as u8; p[idx*4+2]=(bits>>16) as u8; p[idx*4+3]=(bits>>24) as u8; return 0
15}
16
17func main() -> i64 {
18 let a: *u8 = sys_mmap(32)
19 let b: *u8 = sys_mmap(32*4)
20 var j: i64 = 0
21 while j < 32 { a[j] = (j-16) as u8; st4(b, j, nx_i32_to_f32((j%5)+1)); j = j+1 }
22
23 // exact-int equality (order-independent)
24 if __f32_i8dot32(a, b) != __f32_i8dot32a(a, b) { fmt_puts("MISMATCH exact-int"); ab_nl(); return 77 }
25 fmt_puts("EQUAL exact-int OK"); ab_nl()
26
27 let N: i64 = K_MAGIC_20000000
28 // A: SSE
29 let t0: i64 = sys_now_us()
30 var s0: i64 = 0
31 var i0: i64 = 0
32 while i0 < N { s0 = s0 ^ __f32_i8dot32(a, b); i0 = i0 + 1 }
33 let usa: i64 = sys_now_us() - t0
34 // B: AVX2
35 let t1: i64 = sys_now_us()
36 var s1: i64 = 0
37 var i1: i64 = 0
38 while i1 < N { s1 = s1 ^ __f32_i8dot32a(a, b); i1 = i1 + 1 }
39 let usb: i64 = sys_now_us() - t1
40
41 fmt_puts("SSE(i8dot32) ns/call="); fmt_putn(usa * 1000 / N); ab_nl()
42 fmt_puts("AVX2(i8dot32a) ns/call="); fmt_putn(usb * 1000 / N); ab_nl()
43 var ub: i64 = usb
44 if ub < 1 { ub = 1 }
45 fmt_puts("SSE_over_AVX2_x100="); fmt_putn(usa * 100 / ub)
46 fmt_puts(" (>100 => AVX2 faster)"); ab_nl()
47 if s0 == s1 { fmt_puts("(guard)"); ab_nl() }
48 fmt_puts("I8DOT_AB DONE"); ab_nl()
49 return 0
50}