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
This commit is contained in:
André Bargull 2024-11-15 16:16:58 +00:00
parent 2883978598
commit b55e8ce084

View File

@ -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);