Browse Source

A small test WASM module to demonstrate how to use shared memory and run multiple threads in WASM without Emscripten

ssao
A.Olokhtonov 8 months ago
parent
commit
2c01d315d6
  1. 66
      client/speed.js
  2. 1
      client/wasm/compile_command
  3. 10
      client/wasm/lod.c
  4. BIN
      client/wasm/lod.wasm
  5. 37
      client/wasm/multi.c
  6. BIN
      client/wasm/multi.wasm
  7. 40
      client/wasm_worker.js

66
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) { async function init_wasm(state) {
await init_test();
const results = await WebAssembly.instantiateStreaming(fetch('wasm/lod.wasm')); const results = await WebAssembly.instantiateStreaming(fetch('wasm/lod.wasm'));
state.wasm.exports = results.instance.exports; state.wasm.exports = results.instance.exports;

1
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

10
client/wasm/lod.c

@ -7,6 +7,16 @@ extern char __heap_base;
static int allocated_static; static int allocated_static;
static int allocated_dynamic; static int allocated_dynamic;
void
set_sp(void *sp)
{
__asm__ volatile(
"local.get 0\n"
"global.set __stack_pointer\n"
: : "r"(sp)
);
}
void void
free_static(void) free_static(void)
{ {

BIN
client/wasm/lod.wasm

Binary file not shown.

37
client/wasm/multi.c

@ -0,0 +1,37 @@
#include <wasm_simd128.h>
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);
}

BIN
client/wasm/multi.wasm

Binary file not shown.

40
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);
}
}
Loading…
Cancel
Save