knitting 0.1.60 → 0.1.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/BROWSER.md +134 -0
  2. package/README.md +93 -6
  3. package/knitting.browser.d.ts +6 -0
  4. package/knitting.browser.js +1 -0
  5. package/package.json +11 -2
  6. package/prebuilds/darwin-arm64-node-127/knitting_buffer_pointer.node +0 -0
  7. package/prebuilds/darwin-arm64-node-127/knitting_shared_memory.node +0 -0
  8. package/prebuilds/darwin-arm64-node-127/knitting_shm.node +0 -0
  9. package/prebuilds/darwin-arm64-node-137/knitting_buffer_pointer.node +0 -0
  10. package/prebuilds/darwin-arm64-node-137/knitting_shared_memory.node +0 -0
  11. package/prebuilds/darwin-arm64-node-137/knitting_shm.node +0 -0
  12. package/prebuilds/win32-x64/knitting_windows_shared_memory.dll +0 -0
  13. package/prebuilds/win32-x64-node-127/knitting_buffer_pointer.node +0 -0
  14. package/prebuilds/win32-x64-node-127/knitting_shared_memory.node +0 -0
  15. package/prebuilds/win32-x64-node-127/knitting_shm.node +0 -0
  16. package/prebuilds/win32-x64-node-137/knitting_buffer_pointer.node +0 -0
  17. package/prebuilds/win32-x64-node-137/knitting_shared_memory.node +0 -0
  18. package/prebuilds/win32-x64-node-137/knitting_shm.node +0 -0
  19. package/src/api.js +127 -22
  20. package/src/common/runtime.d.ts +2 -1
  21. package/src/common/runtime.js +8 -1
  22. package/src/memory/lock.d.ts +26 -1
  23. package/src/memory/lock.js +212 -4
  24. package/src/memory/payloadCodec.js +2 -6
  25. package/src/memory/regionRegistry.d.ts +1 -3
  26. package/src/memory/regionRegistry.js +16 -14
  27. package/src/permission/protocol.js +5 -1
  28. package/src/runtime/dispatcher.js +9 -0
  29. package/src/runtime/pool.d.ts +114 -3
  30. package/src/runtime/pool.js +209 -63
  31. package/src/runtime/process-worker.d.ts +2 -12
  32. package/src/runtime/process-worker.js +69 -113
  33. package/src/runtime/tx-queue.d.ts +15 -1
  34. package/src/runtime/tx-queue.js +52 -15
  35. package/src/runtime/worker-common.d.ts +13 -0
  36. package/src/runtime/worker-common.js +102 -0
  37. package/src/types.d.ts +41 -3
  38. package/src/worker/loop.js +27 -5
  39. package/src/worker/rx-queue.d.ts +11 -1
  40. package/src/worker/rx-queue.js +4 -1
  41. package/src/worker/timers.d.ts +8 -1
  42. package/src/worker/timers.js +20 -17
@@ -9,9 +9,19 @@ type ArgumentsForCreateWorkerQueue = {
9
9
  borrowReturnedBufferReferences?: boolean;
10
10
  hasAborted?: (signal: number) => boolean;
11
11
  now?: () => number;
12
+ /**
13
+ * Work-stealing discipline: only claim when this worker has nothing left to
14
+ * run. Without it a worker keeps claiming whole regions on top of a backlog
15
+ * it has not started, which is exactly the hoarding stealing exists to
16
+ * prevent — the queued tasks would be better taken by an idle peer.
17
+ *
18
+ * Off for the classic per-lane path, where the host has already assigned
19
+ * these tasks to this lane and batching them is a win.
20
+ */
21
+ stealing?: boolean;
12
22
  };
13
23
  export type CreateWorkerRxQueue = ReturnType<typeof createWorkerRxQueue>;
14
- export declare const createWorkerRxQueue: ({ listOfFunctions, workerOptions, lock, returnLock, borrowReturnedBufferReferences, hasAborted, now, }: ArgumentsForCreateWorkerQueue) => {
24
+ export declare const createWorkerRxQueue: ({ listOfFunctions, workerOptions, lock, returnLock, borrowReturnedBufferReferences, hasAborted, now, stealing, }: ArgumentsForCreateWorkerQueue) => {
15
25
  hasCompleted: () => boolean;
16
26
  hasPending: () => boolean;
17
27
  writeBatch: (max: number) => number;
@@ -2,7 +2,7 @@ import RingQueue from "../ipc/tools/ring-queue.js";
2
2
  import { attachPayloadTransportFinalizer, runTaskFinalizers, TaskFlag, TaskIndex, } from "../memory/lock.js";
3
3
  import { composeWorkerRunner } from "./composable-runners.js";
4
4
  import { BUFFER_REFERENCE_RETURN_RELEASE_TOKEN } from "../connections/buffer-reference.js";
5
- export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, returnLock, borrowReturnedBufferReferences, hasAborted, now, }) => {
5
+ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, returnLock, borrowReturnedBufferReferences, hasAborted, now, stealing, }) => {
6
6
  const PLACE_HOLDER = (_) => {
7
7
  throw ("UNREACHABLE FROM PLACE HOLDER (thread)");
8
8
  };
@@ -71,6 +71,9 @@ export const createWorkerRxQueue = ({ listOfFunctions, workerOptions, lock, retu
71
71
  const { decode, resolved } = lock;
72
72
  const resolvedShift = () => resolved.shiftNoClear();
73
73
  const enqueueLock = () => {
74
+ // Steal only when idle: leaving work unclaimed lets a free peer take it.
75
+ if (stealing && toWork.size !== 0)
76
+ return false;
74
77
  if (!decode())
75
78
  return false;
76
79
  let task = resolvedShift();
@@ -4,7 +4,7 @@ type PauseOptions = {
4
4
  export type NativeWaitU32 = (buffer: ArrayBuffer | SharedArrayBuffer, byteOffset: number, expected: number, timeoutMs?: number) => unknown;
5
5
  export declare const whilePausing: ({ pauseInNanoseconds }: PauseOptions) => () => void;
6
6
  export declare const pauseGeneric: () => void;
7
- export declare const sleepUntilChanged: ({ at, opView, pauseInNanoseconds, rxStatus, txStatus, enqueueLock, write, nativeWaitU32, useSharedMemoryWait, }: {
7
+ export declare const sleepUntilChanged: ({ at, opView, pauseInNanoseconds, rxStatus, txStatus, enqueueLock, write, nativeWaitU32, useSharedMemoryWait, flushBeforeClaim, }: {
8
8
  opView: Int32Array;
9
9
  rxStatus: Int32Array;
10
10
  txStatus: Int32Array;
@@ -14,5 +14,12 @@ export declare const sleepUntilChanged: ({ at, opView, pauseInNanoseconds, rxSta
14
14
  write?: () => number | boolean;
15
15
  nativeWaitU32?: NativeWaitU32;
16
16
  useSharedMemoryWait?: boolean;
17
+ /**
18
+ * Stealing only: write results back before attempting to claim more work.
19
+ * A claim can spin waiting for a peer to withdraw its intent, so claiming
20
+ * first puts arbitration latency in front of a finished response. Measured
21
+ * to hurt the per-lane path, so it stays off by default.
22
+ */
23
+ flushBeforeClaim?: boolean;
17
24
  }) => (value: number, spinMicroseconds: number, parkMs?: number) => void;
18
25
  export {};
@@ -30,7 +30,9 @@ const a_load = Atomics.load;
30
30
  const a_store = Atomics.store;
31
31
  const a_wait = typeof Atomics.wait === "function" ? Atomics.wait : undefined;
32
32
  const p_now = performance.now.bind(performance);
33
- const waitFallbackView = a_wait === undefined
33
+ // `SharedArrayBuffer` is undeclared on pages that are not cross-origin
34
+ // isolated, and this module has to load anyway so the pool can report why.
35
+ const waitFallbackView = a_wait === undefined || typeof SharedArrayBuffer !== "function"
34
36
  ? undefined
35
37
  : new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
36
38
  const a_pause = "pause" in Atomics
@@ -59,26 +61,27 @@ export const whilePausing = ({ pauseInNanoseconds }) => {
59
61
  return () => a_pause(forNanoseconds);
60
62
  };
61
63
  export const pauseGeneric = whilePausing({});
62
- export const sleepUntilChanged = ({ at, opView, pauseInNanoseconds, rxStatus, txStatus, enqueueLock, write, nativeWaitU32, useSharedMemoryWait = true, }) => {
64
+ export const sleepUntilChanged = ({ at, opView, pauseInNanoseconds, rxStatus, txStatus, enqueueLock, write, nativeWaitU32, useSharedMemoryWait = true, flushBeforeClaim = false, }) => {
63
65
  const pause = pauseInNanoseconds === undefined
64
66
  ? pauseGeneric
65
67
  : whilePausing({ pauseInNanoseconds });
66
- const tryProgress = () => {
67
- let progressed = false;
68
- if (enqueueLock())
69
- progressed = true;
70
- if (write) {
71
- const wrote = write();
72
- if (typeof wrote === "number") {
73
- if (wrote > 0)
74
- progressed = true;
75
- }
76
- else if (wrote === true) {
77
- progressed = true;
78
- }
79
- }
80
- return progressed;
68
+ const flushWrite = () => {
69
+ if (!write)
70
+ return false;
71
+ const wrote = write();
72
+ if (typeof wrote === "number")
73
+ return wrote > 0;
74
+ return wrote === true;
81
75
  };
76
+ const tryProgress = flushBeforeClaim
77
+ ? () => {
78
+ const wrote = flushWrite();
79
+ return enqueueLock() || wrote;
80
+ }
81
+ : () => {
82
+ const claimed = enqueueLock();
83
+ return flushWrite() || claimed;
84
+ };
82
85
  return (value, spinMicroseconds, parkMs) => {
83
86
  const until = p_now() + (spinMicroseconds / 1000);
84
87
  maybeGc();