// Classic worker (NOT a module worker) that runs the pthread-capable WASM // matmul modules off the main thread. Threaded builds spawn their pthread // workers from here as nested workers — which is why this is a plain // importScripts worker served from public/, kept out of Vite's module graph. // (Mirrors the proven approach in libflame2wasm/web/bench_worker.js.) 'use strict'; // Modules and this worker all live in public/matmul/; resolve siblings // relative to it so each module and its pthread workers load from here. const DIR = self.location.href.replace(/[^/]*$/, ''); // kind -> { script, factory export name, exported C function }. Every func has // signature (aPtr, bPtr, cPtr, n, nthreads) — single-threaded builds ignore // nthreads, so the call is uniform. const REGISTRY = { 'matmul-mt': { file: 'matmul_mt.js', name: 'createMatmulMT', fn: '_matmul_blocked_mt' }, 'blis-st': { file: 'matmul_blis_st.js', name: 'createMatmulBlisST', fn: '_matmul_blis' }, 'blis-mt': { file: 'matmul_blis_mt.js', name: 'createMatmulBlisMT', fn: '_matmul_blis' }, }; // Same deterministic PRNG as src/methods/random.ts, inlined so this worker is // self-contained and every method multiplies bit-identical inputs per size. function mulberry32(seed) { let a = seed; return () => { a |= 0; a = (a + 0x6d2b79f5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; } function generateMatrix(n, seed) { const rand = mulberry32(seed); const m = new Float64Array(n * n); for (let i = 0; i < m.length; i++) m[i] = rand() - 0.5; return m; } const instances = {}; // kind -> { module, fn } async function getInstance(kind) { if (!instances[kind]) { const reg = REGISTRY[kind]; if (!reg) throw new Error(`Unknown kind: ${kind}`); importScripts(DIR + reg.file); const factory = self[reg.name]; const module = await factory({ locateFile: (path) => DIR + path, mainScriptUrlOrBlob: DIR + reg.file, }); instances[kind] = { module, fn: reg.fn }; } return instances[kind]; } onmessage = async (e) => { const { id, kind, n, seedA, seedB, threads } = e.data; try { const { module, fn } = await getInstance(kind); const a = generateMatrix(n, seedA); const b = generateMatrix(n, seedB); const bytes = n * n * 8; const aPtr = module._malloc(bytes); const bPtr = module._malloc(bytes); const cPtr = module._malloc(bytes); try { new Float64Array(module.HEAPF64.buffer, aPtr, n * n).set(a); new Float64Array(module.HEAPF64.buffer, bPtr, n * n).set(b); const t0 = performance.now(); module[fn](aPtr, bPtr, cPtr, n, threads); const ms = performance.now() - t0; // st builds allow memory growth (buffer may be replaced) — re-view. const sample = new Float64Array(module.HEAPF64.buffer, cPtr, n * n)[0]; postMessage({ id, ms, sample }); } finally { module._free(aPtr); module._free(bPtr); module._free(cPtr); } } catch (err) { postMessage({ id, error: err && err.message ? err.message : String(err) }); } };