From 2c01d315d68842c655c05b313a3bcaa9e82ce1de Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Sun, 24 Mar 2024 23:30:35 +0300 Subject: [PATCH] A small test WASM module to demonstrate how to use shared memory and run multiple threads in WASM without Emscripten --- client/speed.js | 66 ++++++++++++++++++++++++++++++++++++ client/wasm/compile_command | 1 + client/wasm/lod.c | 10 ++++++ client/wasm/lod.wasm | Bin 2279 -> 2192 bytes client/wasm/multi.c | 37 ++++++++++++++++++++ client/wasm/multi.wasm | Bin 0 -> 680 bytes client/wasm_worker.js | 40 ++++++++++++++++++++++ 7 files changed, 154 insertions(+) create mode 100644 client/wasm/compile_command create mode 100644 client/wasm/multi.c create mode 100755 client/wasm/multi.wasm create mode 100644 client/wasm_worker.js diff --git a/client/speed.js b/client/speed.js index fbf801a..bc91a27 100644 --- a/client/speed.js +++ b/client/speed.js @@ -1,4 +1,70 @@ +async function init_test() { + const memory = new WebAssembly.Memory({ + initial: 32, + maximum: 100, + shared: true, + }); + + const results = await WebAssembly.instantiateStreaming(fetch('wasm/multi.wasm'), { + env: { 'memory': memory } + }); + + const nworkers = navigator.hardwareConcurrency; + const heap_base = results.instance.exports.alloc(0); + const buf_offset = results.instance.exports.alloc(1024); + const workers = []; + const sab = new SharedArrayBuffer(nworkers * 4); + const flags = new Int32Array(sab); + let done = 0; + + for (let i = 0; i < nworkers; ++i) { + const w = new Worker('wasm_worker.js'); + workers.push(w); + } + + for (let i = 0; i < nworkers; ++i) { + workers[i].onmessage = () => { + ++done; + if (done % nworkers === 0) { + console.log('init done'); + + for (let j = 0; j < nworkers; ++j) { + workers[j].onmessage = () => { + ++done; + + if (done % nworkers === 0) { + console.log('work done'); + console.log(new Int32Array(memory.buffer, buf_offset, nworkers)); + } + } + + workers[j].postMessage({ + 'type': 1, + 'num': 10, + }); + } + } + } + + workers[i].postMessage({ + 'type': 0, + 'thread_id': i, + 'memory': memory, + 'stack_base': heap_base, + 'buffer_offset': buf_offset, + 'flags': flags + }); + } + +// const results = await WebAssembly.instantiateStreaming(fetch('wasm/multi.wasm')); + +// state.wasm.exports = results.instance.exports; +// state.wasm.exports.memory.grow(4096); +} + async function init_wasm(state) { + await init_test(); + const results = await WebAssembly.instantiateStreaming(fetch('wasm/lod.wasm')); state.wasm.exports = results.instance.exports; diff --git a/client/wasm/compile_command b/client/wasm/compile_command new file mode 100644 index 0000000..b496251 --- /dev/null +++ b/client/wasm/compile_command @@ -0,0 +1 @@ +clang -Oz --target=wasm32 -nostdlib -msimd128 -mbulk-memory -matomics -Wl,--no-entry,--import-memory,--shared-memory,--max-memory=$((1024 * 1024 * 1024)) -z stack-size=$((1024 * 1024)) multi.c -o multi.wasm diff --git a/client/wasm/lod.c b/client/wasm/lod.c index e63d270..bed8a70 100644 --- a/client/wasm/lod.c +++ b/client/wasm/lod.c @@ -7,6 +7,16 @@ extern char __heap_base; static int allocated_static; static int allocated_dynamic; +void +set_sp(void *sp) +{ + __asm__ volatile( + "local.get 0\n" + "global.set __stack_pointer\n" + : : "r"(sp) + ); +} + void free_static(void) { diff --git a/client/wasm/lod.wasm b/client/wasm/lod.wasm index 63161d4d181a80173dbb4207c15489f85bf3bc27..7f218d765d942c5377cdfb9635a0b7eb309750e0 100755 GIT binary patch delta 1323 zcmZ8hOK%%h6ux(6GWK{Lv7Hb?q9kW-lQd0g=k28F^C}c15M5MANI)~0*iPx#j=^?? ziUgAdNJy|qGGW7yU_loM#Fjl0e}F}S4g7==eAlKCVyrvoeeQQ2<39=~g$fJ1EzTI@ z6UIJc`#k0`UToirc#EMPuw$G^;Wy{ zL}P^@_z-D>YS?TB)n2>PWz6i>dqMYo#_hvSy&iOXVee6uX-;3NJvjgJ!$NOeY9x-FEO^cvNfFbu9-m?1e%7sHW>~5Ik(Q55i_}5O(Xj0eOIC zAP*t77alb01JTTV?PYXeF&VL0mIVAw<9k=1O}^taM)K3_g2u#)ku)Ol5@n^<6Mpg+ z7knm}*2adH(-HrgWPVP+1Mit+S9>twM?{f4`P_*7F_;QC9?S)pf6!hZa^dJDIsGH< zCZFl+ldj~E?~*Nf!?(%6MZQ6v)FR(Ye$hiyECRqvvSZA}mnvG8GBh0dvr_ZNX^4gu zpj_n7kx3x)$||*%n2P+%Qt!jc2_SgQ008B?K>0{mGTRVWP?+yg9(uhYaxg|>5jx3V zf%6MAqBP`HGzJzBM;uSH$&yAxbz~GZ{ArBG9?+<~P9&xk(A7kgzN8YB&Vk5^paO-_ zQpPnHVL3Y$<*#-bi+9h(IvThG{|m(i6xV4KnEWN0BQGtaj#^4A9n*0Pob($mw$e!^ z>{#9HM!rKX&8s$AsfDs`&~%^PL_bDpDvC;siRq_EeG3}zx#p_U+)kap|M&RYbj`0| zW;QL|Lo@QUo!Z99F$Y%xcYMrc>{}?|9%Ft91Gbg3%%gMK9gL-jTRjOgDsusX%8%WI-p&w7jP}`rw0pek%W)oE)`V=#(OE^0T>W!?btTWmLx1PG-Dt zg)BAiMadM&(?YVDnde^eZe}LFPELy6)6MiZp8n2hhupq=V<4x`c={^`*vruZCR7lc z=@>(Q36wugi7Q3}qbWuQql-<|$L-Hf?H#iXfL~1JeUXM+Yj7r^a>$iOG^^B->x1|t5j=2wocqsd_|IqLE zU-a!G`|ePlwbIGCQaJe=L0=}XUwL6)9BhLEGq3FWI$JY+rWjbpo)pUai{Lsk`g~u{N5peCm3z z%(%x}n~&XGT&-@l+UvDe79o$5HXffGf-5wqXqgs0131YX}mzr+u1)6w$HTGAC_h z@{JmyagtOpnKFr5CfNf5YLpIJ8zeSPWax;=*fBV+;2$Gw1z}?sVJlo%$uNwCq~Em? zX*7$iP#P6c0dWxNiz$t@seloAhAHecYE%(r#C$^eG(w)GJQ9@oEhPgy&pK+H4p|_L zDv(R1{Sayb`GmkAhd5IllqLW0?Vy0i~6UI-WRcf|P|#2S%O1Y-yuTvNmzH^^8%c64%aDfcA-d zaBrJ?n#x9_>ZU%!DaUYKN!+HkS?XD?Nb(3CJ5^AWd3FTB4y+I3D*V5>p|2=AzE~{mXrBC6PfTm2VY3RKkNKnh51_PP&mCx5&sCitekViNv z14eW?N5e=U#%;pOqpic{$NchyG>b_ee&^}@H+pz#-w9aI^Eeh_9N8I-eg(7vKShk- z!dtquM;EEc%;MX<8gUTr8!3OT9$b`TRRcOLQ%x*wcH~EJL=O-quU$*J_zoXqA{+#Y>=^A&89;WB_O- zjXcEt^q>AF)e4YdaKn!m4tHGO)o|g#9Tew$-T|0L?TanMTL;CCWw$Y~JpuUmW|?Ea zE)RokJBR&8f9Tv(bvKfgq$7B8L_mrA`_ uXS30(K5Eo@yPZbYoh@ze+E4FX_OkEr3vxV-~=FVK>S?^yPiqrT2 diff --git a/client/wasm/multi.c b/client/wasm/multi.c new file mode 100644 index 0000000..20765cb --- /dev/null +++ b/client/wasm/multi.c @@ -0,0 +1,37 @@ +#include + +extern char __heap_base; + +static int allocated; + +void +set_sp(char *sp) +{ + __asm__ __volatile__( + ".globaltype __stack_pointer, i32\n" + "local.get %0\n" + "global.set __stack_pointer\n" + : : "r"(sp) + ); +} + +void * +alloc(int size) +{ + void *result = &__heap_base + allocated; + allocated += size; + return(result); +} + +static void +impl(int *buffer, int index, int number) +{ + buffer[index] = number; +} + +void +write_a_number(int *buffer, int index, int number) +{ + int n = number * 2; + impl(buffer, index, n); +} diff --git a/client/wasm/multi.wasm b/client/wasm/multi.wasm new file mode 100755 index 0000000000000000000000000000000000000000..01e32fb06a0a4121abffd3cfbb8dc2db83326539 GIT binary patch literal 680 zcmZWmv2NQi5WOQ~*)i1^afblyB6Lb2IB1N*=ol3l3gjbbN@8R=lw^oh-E@%(WXPDQ z-_xPrWt5asv_(PiaPRKDBk>M|E)W3l<7QrF3XfUsWu|H0Mb2M(S{^^CG=meh69IsJq4BOgPbY*9-Z@`~p72xtjn0 literal 0 HcmV?d00001 diff --git a/client/wasm_worker.js b/client/wasm_worker.js new file mode 100644 index 0000000..0e0ff7c --- /dev/null +++ b/client/wasm_worker.js @@ -0,0 +1,40 @@ +let thread_id = null; +let buf_offset = null; +let exports = null; +let flags = null; + +function done() { + postMessage('done'); +} + +async function init_wasm(tid, memory, offset, notify_flags, stack_base) { + thread_id = tid; + buf_offset = offset; + + const result = await WebAssembly.instantiateStreaming(fetch('wasm/multi.wasm'), { + env: { 'memory': memory } + }); + + exports = result.instance.exports; + //console.log(tid, 'init'); + exports.set_sp(stack_base - thread_id * 4096); + + flags = notify_flags; + done(); +} + +function do_work(num, callback) { + //console.log(thread_id, 'work'); + exports.write_a_number(buf_offset, thread_id, thread_id * num); + done(); +} + +onmessage = (e) => { + if (e.data.type === 0) { + init_wasm(e.data.thread_id, e.data.memory, e.data.buffer_offset, e.data.flags, e.data.stack_base); + } else if (e.data.type === 1) { + do_work(e.data.num); + } +} + +