[6a3a178] | 1 | import Piscina from '..';
|
---|
| 2 | import { test } from 'tap';
|
---|
| 3 | import { resolve } from 'path';
|
---|
| 4 |
|
---|
| 5 | test('coverage test for Atomics optimization', async ({ equal }) => {
|
---|
| 6 | const pool = new Piscina({
|
---|
| 7 | filename: resolve(__dirname, 'fixtures/notify-then-sleep-or.ts'),
|
---|
| 8 | minThreads: 2,
|
---|
| 9 | maxThreads: 2,
|
---|
| 10 | concurrentTasksPerWorker: 2
|
---|
| 11 | });
|
---|
| 12 |
|
---|
| 13 | const tasks = [];
|
---|
| 14 | let v : number;
|
---|
| 15 |
|
---|
| 16 | // Post 4 tasks, and wait for all of them to be ready.
|
---|
| 17 | const i32array = new Int32Array(new SharedArrayBuffer(4));
|
---|
| 18 | for (let index = 0; index < 4; index++) {
|
---|
| 19 | tasks.push(pool.runTask({ i32array, index }));
|
---|
| 20 | }
|
---|
| 21 |
|
---|
| 22 | // Wait for 2 tasks to enter 'wait' state.
|
---|
| 23 | do {
|
---|
| 24 | v = Atomics.load(i32array, 0);
|
---|
| 25 | if (popcount8(v) >= 2) break;
|
---|
| 26 | Atomics.wait(i32array, 0, v);
|
---|
| 27 | } while (true);
|
---|
| 28 |
|
---|
| 29 | // The check above could also be !== 2 but it's hard to get things right
|
---|
| 30 | // sometimes and this gives us a nice assertion. Basically, at this point
|
---|
| 31 | // exactly 2 tasks should be in Atomics.wait() state.
|
---|
| 32 | equal(popcount8(v), 2);
|
---|
| 33 | // Wake both tasks up as simultaneously as possible. The other 2 tasks should
|
---|
| 34 | // then start executing.
|
---|
| 35 | Atomics.store(i32array, 0, 0);
|
---|
| 36 | Atomics.notify(i32array, 0, Infinity);
|
---|
| 37 |
|
---|
| 38 | // Wait for the other 2 tasks to enter 'wait' state.
|
---|
| 39 | do {
|
---|
| 40 | v = Atomics.load(i32array, 0);
|
---|
| 41 | if (popcount8(v) >= 2) break;
|
---|
| 42 | Atomics.wait(i32array, 0, v);
|
---|
| 43 | } while (true);
|
---|
| 44 |
|
---|
| 45 | // At this point, the first two tasks are definitely finished and have
|
---|
| 46 | // definitely posted results back to the main thread, and the main thread
|
---|
| 47 | // has definitely not received them yet, meaning that the Atomics check will
|
---|
| 48 | // be used. Making sure that that works is the point of this test.
|
---|
| 49 |
|
---|
| 50 | // Wake up the remaining 2 tasks in order to make sure that the test finishes.
|
---|
| 51 | // Do the same consistency check beforehand as above.
|
---|
| 52 | equal(popcount8(v), 2);
|
---|
| 53 | Atomics.store(i32array, 0, 0);
|
---|
| 54 | Atomics.notify(i32array, 0, Infinity);
|
---|
| 55 |
|
---|
| 56 | await Promise.all(tasks);
|
---|
| 57 | });
|
---|
| 58 |
|
---|
| 59 | // Inefficient but straightforward 8-bit popcount
|
---|
| 60 | function popcount8 (v : number) : number {
|
---|
| 61 | v &= 0xff;
|
---|
| 62 | if (v & 0b11110000) return popcount8(v >>> 4) + popcount8(v & 0xb00001111);
|
---|
| 63 | if (v & 0b00001100) return popcount8(v >>> 2) + popcount8(v & 0xb00000011);
|
---|
| 64 | if (v & 0b00000010) return popcount8(v >>> 1) + popcount8(v & 0xb00000001);
|
---|
| 65 | return v;
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | test('avoids unbounded recursion', async () => {
|
---|
| 69 | const pool = new Piscina({
|
---|
| 70 | filename: resolve(__dirname, 'fixtures/simple-isworkerthread.ts'),
|
---|
| 71 | minThreads: 2,
|
---|
| 72 | maxThreads: 2
|
---|
| 73 | });
|
---|
| 74 |
|
---|
| 75 | const tasks = [];
|
---|
| 76 | for (let i = 1; i <= 10000; i++) {
|
---|
| 77 | tasks.push(pool.runTask(null));
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | await Promise.all(tasks);
|
---|
| 81 | });
|
---|