code wiki / (root) / nx_conv_speedup.nx

nx_conv_speedup.nx source

↩ module page · 97 lines · 3181 B

1// THE PAYOFF: a real 2D convolution (1024x1024, 15x15 kernel), run SERIAL then THREADED (nx_thread_pool, 8 2// workers on disjoint output-row bands -- no shared writes, no atomics), with a measured wall-time speedup. 3// Pointers travel via a ctx struct (NOT module statics -- the compiler has a PRE-EXISTING multi-static bug, 4// proven pre-dating all recent compiler work), which is the same pattern nx_parallel uses. 5import "nx_thread_pool.nx" 6import "nx_fmt.nx" 7 8const IMG_W: i64 = 1024 9const IMG_H: i64 = 1024 10const K: i64 = 15 11const NWORK: i64 = 8 12 13struct ConvCtx { 14 in_ptr: i64, 15 out_ptr: i64, 16 ker_ptr: i64, 17 y0: i64, 18 y1: i64, 19} 20const CONVCTX_BYTES: i64 = 40 21 22func conv_range(in_p: *i64, out_p: *i64, ker_p: *i64, y0: i64, y1: i64) -> i64 { 23 let half: i64 = K / 2 24 var y: i64 = y0 25 while y < y1 { 26 var x: i64 = 0 27 while x < IMG_W { 28 var acc: i64 = 0 29 var ky: i64 = 0 30 while ky < K { 31 var kx: i64 = 0 32 while kx < K { 33 let iy: i64 = y + ky - half 34 let ix: i64 = x + kx - half 35 if iy >= 0 { if iy < IMG_H { if ix >= 0 { if ix < IMG_W { 36 acc = acc + in_p[iy * IMG_W + ix] * ker_p[ky * K + kx] 37 } } } } 38 kx = kx + 1 39 } 40 ky = ky + 1 41 } 42 out_p[y * IMG_W + x] = acc 43 x = x + 1 44 } 45 y = y + 1 46 } 47 return 0 48} 49 50func conv_task(ctx_i: i64) -> i64 { 51 let c: *ConvCtx = ctx_i as *ConvCtx 52 conv_range(c.in_ptr as *i64, c.out_ptr as *i64, c.ker_ptr as *i64, c.y0, c.y1) 53 return 0 54} 55 56func main() -> i64 { 57 let g_in: *i64 = sys_mmap(IMG_W * IMG_H * 8) as *i64 58 let g_out: *i64 = sys_mmap(IMG_W * IMG_H * 8) as *i64 59 let g_ker: *i64 = sys_mmap(K * K * 8) as *i64 60 var i: i64 = 0 61 while i < IMG_W * IMG_H { g_in[i] = i & 255; i = i + 1 } 62 i = 0 63 while i < K * K { g_ker[i] = (i % 7) - 3; i = i + 1 } 64 65 // SERIAL 66 let t0: i64 = sys_now_us() 67 conv_range(g_in, g_out, g_ker, 0, IMG_H) 68 let serial_us: i64 = sys_now_us() - t0 69 70 // THREADED: NWORK workers, disjoint row bands 71 let pool: *NxThreadPool = nx_pool_new(NWORK, 64) 72 let ctxs: *u8 = sys_mmap(NWORK * CONVCTX_BYTES) 73 let rp: i64 = (IMG_H + NWORK - 1) / NWORK 74 let t2: i64 = sys_now_us() 75 var w: i64 = 0 76 while w < NWORK { 77 let c: *ConvCtx = ((ctxs as i64) + w * CONVCTX_BYTES) as *ConvCtx 78 c.in_ptr = g_in as i64 79 c.out_ptr = g_out as i64 80 c.ker_ptr = g_ker as i64 81 c.y0 = w * rp 82 var yy: i64 = (w + 1) * rp 83 if yy > IMG_H { yy = IMG_H } 84 c.y1 = yy 85 nx_pool_submit(pool, conv_task, c as i64) 86 w = w + 1 87 } 88 nx_pool_wait(pool, NWORK) 89 let par_us: i64 = sys_now_us() - t2 90 nx_pool_shutdown(pool) 91 92 fmt_puts("serial_us="); fmt_putn(serial_us); fmt_puts("\n" as *u8) 93 fmt_puts("threaded_us="); fmt_putn(par_us); fmt_puts("\n" as *u8) 94 if par_us > 0 { fmt_puts("speedup_x100="); fmt_putn(serial_us * 100 / par_us); fmt_puts("\n" as *u8) } 95 sys_exit(0) 96 return 0 97}