From b55e8ce0846808868558f91285a8924c4f07a877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Fri, 15 Nov 2024 16:16:58 +0000 Subject: [PATCH] Bug 1931315: Rework Atomics.pause to avoid intermittent failures. r=iain - Perform a single call `setSharedObject`. - Reduce the number of iterations to further decrease the time needed to complete the test. - Simplify the critical section in the worker threads to a non-atomic load-and-store. This avoids interactions with the main-thread, which should help to make the test more reliable. - Check that `Atomics.notify` actually notified all worker threads. Differential Revision: https://phabricator.services.mozilla.com/D229117 --- js/src/jit-test/tests/atomics/pause-multi.js | 44 ++++++++------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/js/src/jit-test/tests/atomics/pause-multi.js b/js/src/jit-test/tests/atomics/pause-multi.js index e604ab3c9ea1..5a12a23791cc 100644 --- a/js/src/jit-test/tests/atomics/pause-multi.js +++ b/js/src/jit-test/tests/atomics/pause-multi.js @@ -1,25 +1,25 @@ // |jit-test| --enable-atomics-pause; skip-if: !Atomics.pause || helperThreadCount() === 0 || getBuildConfiguration("arm64-simulator") === true -function startWorker(worker, buffer) { - setSharedObject(buffer); - +function startWorker(worker) { evalInWorker(` (${worker})(getSharedObject()); `); } -// Index 0: Main Lock -// Index 1: Worker Lock +// Index 0: Worker Lock +// Index 1: Counter // Index 2: Sync // Index 3: Worker State let sab = new SharedArrayBuffer(4 * Int32Array.BYTES_PER_ELEMENT) let i32 = new Int32Array(sab); +setSharedObject(sab); + // Number of workers. const N = 4; // Number of iterations. -const K = 10_000; +const K = N * 1000; for (let i = 0; i < N; ++i) { startWorker(function(sab) { @@ -27,7 +27,7 @@ for (let i = 0; i < N; ++i) { const N = 4; // Number of iterations. - const K = 10_000; + const K = N * 1000; let i32 = new Int32Array(sab); @@ -40,21 +40,24 @@ for (let i = 0; i < N; ++i) { for (let i = 0; i < K / N; ++i) { // Spin-wait loop using a "test, test-and-set" technique. while (true) { - while (Atomics.load(i32, 1) !== 0) { + while (Atomics.load(i32, 0) !== 0) { Atomics.pause(); } - if (Atomics.exchange(i32, 1, 1) === 0) { + if (Atomics.exchange(i32, 0, 1) === 0) { break; } } - // "Critical section" - pass control to main thread. + // "Critical section" - non-atomic load-and-store. + i32[1] += 1; + + // Leave "Critical section". Atomics.store(i32, 0, 0); } // Mark worker as finished. Atomics.sub(i32, 3, 1); - }, sab); + }); } // Wait until all worker threads have started. @@ -63,24 +66,13 @@ while (Atomics.load(i32, 3) !== N) { } // Start work in all worker threads. -Atomics.notify(i32, 2, N); - -for (let i = 0; i < K; ++i) { - // Spin-wait loop using a "test, test-and-set" technique. - while (true) { - while (Atomics.load(i32, 0) !== 0) { - Atomics.pause(); - } - if (Atomics.exchange(i32, 0, 1) === 0) { - break; - } - } - - // "Critical section" - pass control to a worker thread. - Atomics.store(i32, 1, 0); +let woken = 0; +while ((woken += Atomics.notify(i32, 2, N)) !== N) { } // Wait until all worker threads have finished. while (Atomics.load(i32, 3) !== 0) { Atomics.pause(); } + +assertEq(i32[1], K);