From 7b368872437b7313cc627c32a76aaef586c2f93b Mon Sep 17 00:00:00 2001 From: jackryanservia <90076280+jackryanservia@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:58:43 -0700 Subject: [PATCH 1/3] Update to spawn workers for all logical cores and expose global function to allow developer override --- js/node/node-backend.js | 24 ++---------------------- js/web/num-workers.js | 24 ------------------------ js/web/web-backend.js | 4 ++-- 3 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 js/web/num-workers.js diff --git a/js/node/node-backend.js b/js/node/node-backend.js index bb6f6a25..f09a7c6b 100644 --- a/js/node/node-backend.js +++ b/js/node/node-backend.js @@ -2,6 +2,7 @@ import { isMainThread, parentPort, workerData, Worker } from 'worker_threads'; import os from 'os'; import wasm_ from '../../compiled/_node_bindings/plonk_wasm.cjs'; import { fileURLToPath } from 'url'; +import { workers } from '../../../lib/proof-system/workers.js'; let url = import.meta.url; let filename = url !== undefined ? fileURLToPath(url) : __filename; @@ -82,7 +83,7 @@ async function withThreadPool(run) { async function initThreadPool() { if (!isMainThread) return; workersReady = new Promise((resolve) => (workersReadyResolve = resolve)); - await wasm.initThreadPool(getEfficientNumWorkers(), filename); + await wasm.initThreadPool(workers.numWorkers ?? os.cpus().length, filename); await workersReady; workersReady = undefined; } @@ -126,24 +127,3 @@ async function terminateWorkers() { () => (wasmWorkers = undefined) ); } - -// Return the most efficient number of workers for the platform we're running -// on. This is required because of an issue with Apple silicon that's outlined -// here: https://bugs.chromium.org/p/chromium/issues/detail?id=1228686 -function getEfficientNumWorkers() { - let cpus = os.cpus(); - let numCpus = cpus.length; - let cpuModel = cpus[0].model; - - let numWorkers = - { - 'Apple M1': 2, - 'Apple M1 Pro': numCpus === 10 ? 3 : 2, - 'Apple M1 Max': 3, - 'Apple M1 Ultra': 7, - 'Apple M2': 2, - 'Apple M2 Pro': 2, - }[cpuModel] || numCpus - 1; - - return numWorkers; -} diff --git a/js/web/num-workers.js b/js/web/num-workers.js deleted file mode 100644 index 9667a35c..00000000 --- a/js/web/num-workers.js +++ /dev/null @@ -1,24 +0,0 @@ -import { getGPUTier } from 'detect-gpu'; - -export { getEfficientNumWorkers }; - -// Return the most efficient number of workers for the platform we're running -// on. This is required because of an issue with Apple silicon that's outlined -// here: https://bugs.chromium.org/p/chromium/issues/detail?id=1228686 -async function getEfficientNumWorkers() { - let gpuTier = await getGPUTier(); - let numCpus = navigator.hardwareConcurrency; - // gpuTier.gpu is undefined if page was rendered server side - let gpuModel = gpuTier.gpu; - - let numWorkers = - { - 'apple m1': 2, - 'apple m1 pro': numCpus === 10 ? 3 : 2, - 'apple m1 max': 3, - 'apple m1 ultra': 7, - 'apple m2': 2, - }[gpuModel] || numCpus - 1; - - return numWorkers; -} diff --git a/js/web/web-backend.js b/js/web/web-backend.js index a964fb47..141b365b 100644 --- a/js/web/web-backend.js +++ b/js/web/web-backend.js @@ -1,12 +1,12 @@ import plonkWasm from '../../../web_bindings/plonk_wasm.js'; import { workerSpec } from './worker-spec.js'; -import { getEfficientNumWorkers } from './num-workers.js'; import { srcFromFunctionModule, inlineWorker, waitForMessage, } from './worker-helpers.js'; import o1jsWebSrc from 'string:../../../web_bindings/o1js_web.bc.js'; +import { workers } from '../../../lib/proof-system/workers.js'; export { initO1, withThreadPool }; @@ -55,7 +55,7 @@ async function withThreadPool(run) { if (workerPromise === undefined) throw Error('need to initialize worker first'); let worker = await workerPromise; - numWorkers ??= await getEfficientNumWorkers(); + numWorkers ??= workers.numWorkers ?? navigator.hardwareConcurrency; await workerCall(worker, 'initThreadPool', numWorkers); let result; try { From 2baae6c47d76964d2ca1eeb5684152aeaec91ae4 Mon Sep 17 00:00:00 2001 From: jackryanservia <90076280+jackryanservia@users.noreply.github.com> Date: Thu, 22 Feb 2024 01:32:09 -0700 Subject: [PATCH 2/3] Changed default workers to cpus - 1 (bc 1 core is occupied by main thread) and switched to os.availableParallelism() in node. --- js/node/node-backend.js | 5 ++++- js/web/web-backend.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/js/node/node-backend.js b/js/node/node-backend.js index f09a7c6b..d6ee7462 100644 --- a/js/node/node-backend.js +++ b/js/node/node-backend.js @@ -83,7 +83,10 @@ async function withThreadPool(run) { async function initThreadPool() { if (!isMainThread) return; workersReady = new Promise((resolve) => (workersReadyResolve = resolve)); - await wasm.initThreadPool(workers.numWorkers ?? os.cpus().length, filename); + await wasm.initThreadPool( + workers.numWorkers ?? os.availableParallelism() - 1, + filename + ); await workersReady; workersReady = undefined; } diff --git a/js/web/web-backend.js b/js/web/web-backend.js index 141b365b..a67d16a1 100644 --- a/js/web/web-backend.js +++ b/js/web/web-backend.js @@ -55,7 +55,7 @@ async function withThreadPool(run) { if (workerPromise === undefined) throw Error('need to initialize worker first'); let worker = await workerPromise; - numWorkers ??= workers.numWorkers ?? navigator.hardwareConcurrency; + numWorkers ??= workers.numWorkers ?? navigator.hardwareConcurrency - 1; await workerCall(worker, 'initThreadPool', numWorkers); let result; try { From b33a7eab09f6fda33b982a6cde67a51507b6b72e Mon Sep 17 00:00:00 2001 From: jackryanservia <90076280+jackryanservia@users.noreply.github.com> Date: Thu, 22 Feb 2024 15:17:04 -0700 Subject: [PATCH 3/3] Handle null values and default to cpus - 1 workers to not contend with main thread --- js/node/node-backend.js | 2 +- js/web/web-backend.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/node/node-backend.js b/js/node/node-backend.js index d6ee7462..7c76dceb 100644 --- a/js/node/node-backend.js +++ b/js/node/node-backend.js @@ -84,7 +84,7 @@ async function initThreadPool() { if (!isMainThread) return; workersReady = new Promise((resolve) => (workersReadyResolve = resolve)); await wasm.initThreadPool( - workers.numWorkers ?? os.availableParallelism() - 1, + Math.max(1, workers.numWorkers ?? (os.availableParallelism() ?? 1) - 1), filename ); await workersReady; diff --git a/js/web/web-backend.js b/js/web/web-backend.js index a67d16a1..2d9ee11f 100644 --- a/js/web/web-backend.js +++ b/js/web/web-backend.js @@ -55,7 +55,7 @@ async function withThreadPool(run) { if (workerPromise === undefined) throw Error('need to initialize worker first'); let worker = await workerPromise; - numWorkers ??= workers.numWorkers ?? navigator.hardwareConcurrency - 1; + numWorkers ??= Math.max(1, workers.numWorkers ?? (navigator.hardwareConcurrency ?? 1) - 1); await workerCall(worker, 'initThreadPool', numWorkers); let result; try {