From 0e3aa54dc8a33a65a2f0a44d8def14fcdb494ae6 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 29 Apr 2020 16:03:04 +0100 Subject: [PATCH] Add some comments --- codecs/oxipng/spawn.ts | 23 +++++++++++++++++++++++ codecs/oxipng/worker.ts | 4 ++++ 2 files changed, 27 insertions(+) diff --git a/codecs/oxipng/spawn.ts b/codecs/oxipng/spawn.ts index 75f5c0fc..ab6b8b53 100644 --- a/codecs/oxipng/spawn.ts +++ b/codecs/oxipng/spawn.ts @@ -15,11 +15,34 @@ function initWorker(worker: Worker, workerInit: WorkerInit) { async function startMainThread() { const num = navigator.hardwareConcurrency; + + // First, let browser fetch and spawn Workers for our pool in the background. + // This is fairly expensive, so we want to start it as early as possible. const workers = Array.from({ length: num }, () => new Worker('./worker', { type: 'module' })); + + // Meanwhile, asynchronously compile, instantiate and initialise Wasm on our main thread. await initOxiPNG(fetch(wasmUrl), undefined as any); + + // Get module+memory from the Wasm instance. + // + // Ideally we wouldn't go via Wasm bindings here, since both are just JS variables, but memory is + // currently not exposed on the Wasm instance correctly by wasm-bindgen. const workerInit: WorkerInit = worker_initializer(num); + + // Once done, we want to send module+memory to each Worker so that they instantiate Wasm too. + // While doing so, we need to wait for Workers to acknowledge that they have received our message. + // Ideally this shouldn't be necessary, but Chromium currently doesn't conform to the spec: + // https://bugs.chromium.org/p/chromium/issues/detail?id=1075645 + // + // If we didn't do this ping-pong game, the `start_main_thread` below would block the current + // thread on an atomic before even *sending* the `postMessage` containing memory, + // so Workers would never be able to unblock us back. await Promise.all(workers.map(worker => initWorker(worker, workerInit))); + + // Finally, instantiate rayon pool - this will use shared Wasm memory to send tasks to the + // Workers and then block until they're all ready. start_main_thread(); + return { optimise, }; diff --git a/codecs/oxipng/worker.ts b/codecs/oxipng/worker.ts index 9a08f4c9..69f60501 100644 --- a/codecs/oxipng/worker.ts +++ b/codecs/oxipng/worker.ts @@ -11,6 +11,10 @@ addEventListener( // // At this point, the "main" thread can run Wasm that // will synchronously block waiting on other atomics. + // + // Note that we don't need to wait for Wasm instantiation here - it's + // better to start main thread as early as possible, and then it blocks + // on a shared atomic anyway until Worker is fully ready. postMessage(null); await initOxiPNG(...(event.data as WorkerInit));