code wiki / (root) / nx_i8dot_ab.nx

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}