@atolljs/core 0.1.7 → 0.1.8

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 (59) hide show
  1. package/README.md +1 -1
  2. package/dist/contract/memoryDevtools.d.ts +30 -0
  3. package/dist/contract/sharedMemory.d.ts +4 -2
  4. package/dist/contract/types.d.ts +11 -0
  5. package/dist/devtools.d.ts +127 -4
  6. package/dist/index.d.ts +8 -4
  7. package/dist/index.js +19 -17
  8. package/dist/index10.js +29 -14
  9. package/dist/index11.js +14 -307
  10. package/dist/index12.js +29 -50
  11. package/dist/index13.js +46 -60
  12. package/dist/index14.js +56 -22
  13. package/dist/index15.js +332 -55
  14. package/dist/index16.js +246 -45
  15. package/dist/index17.js +56 -51
  16. package/dist/index18.js +9 -39
  17. package/dist/index19.js +56 -80
  18. package/dist/index20.js +24 -53
  19. package/dist/index21.js +56 -52
  20. package/dist/index22.js +48 -0
  21. package/dist/index23.js +68 -0
  22. package/dist/index24.js +41 -0
  23. package/dist/index25.js +46 -0
  24. package/dist/index26.js +113 -0
  25. package/dist/index27.js +60 -0
  26. package/dist/index28.js +57 -0
  27. package/dist/index5.js +135 -64
  28. package/dist/index6.js +160 -35
  29. package/dist/index7.js +45 -503
  30. package/dist/index8.js +513 -19
  31. package/dist/index9.js +19 -33
  32. package/dist/pool/dedicatedWorker.d.ts +63 -0
  33. package/dist/pool/devtoolsCommands.d.ts +54 -0
  34. package/dist/pool/subWorkerClient.d.ts +50 -0
  35. package/dist/pool/workerChannel.d.ts +44 -0
  36. package/dist/pool/workerClient.d.ts +36 -8
  37. package/dist/pool/workerPool.d.ts +10 -1
  38. package/dist/reactive.d.ts +15 -0
  39. package/dist/reactiveGraph.d.ts +9 -0
  40. package/dist/userTiming.d.ts +27 -0
  41. package/package.json +2 -1
  42. package/src/contract/memoryDevtools.ts +249 -0
  43. package/src/contract/sharedMemory.ts +20 -6
  44. package/src/contract/types.ts +11 -0
  45. package/src/devtools.ts +251 -6
  46. package/src/index.ts +13 -1
  47. package/src/log.ts +22 -0
  48. package/src/observable.ts +16 -3
  49. package/src/pool/dedicatedWorker.ts +332 -0
  50. package/src/pool/devtoolsCommands.ts +165 -0
  51. package/src/pool/subWorkerClient.ts +70 -0
  52. package/src/pool/workerChannel.ts +99 -0
  53. package/src/pool/workerClient.ts +61 -15
  54. package/src/pool/workerPool.ts +75 -45
  55. package/src/reactive.ts +87 -12
  56. package/src/reactiveGraph.ts +91 -0
  57. package/src/testing/inProcessWorker.ts +4 -3
  58. package/src/userTiming.ts +71 -0
  59. package/src/worker/workerBootstrap.ts +27 -4
@@ -0,0 +1,71 @@
1
+ /**
2
+ * User Timing bridge: `performance.measure` entries for atoll work, so the
3
+ * browser's own Performance panel shows tasks next to the app's frames.
4
+ * Callers gate on `devtoolsEnabled()`; this module never checks it itself.
5
+ *
6
+ * `detail.devtools` is Chrome's extensibility payload: entries land on a
7
+ * custom track inside an 'atoll' track group. Other engines ignore the
8
+ * detail and record a plain measure.
9
+ */
10
+
11
+ /** Chrome's extensibility palette names. */
12
+ export type TimingColor = 'primary' | 'primary-light' | 'secondary' | 'tertiary' | 'error' | 'warning';
13
+
14
+ export interface TimingTrack {
15
+ /** Track label inside the 'atoll' group, e.g. a pool id. */
16
+ track: string;
17
+ color?: TimingColor;
18
+ properties?: [string, string | number][];
19
+ tooltipText?: string;
20
+ }
21
+
22
+ type MeasureFn = (name: string, options: { start: number; end: number; detail?: unknown }) => unknown;
23
+
24
+ /**
25
+ * Record `[start, end]` (performance.now() ms on this thread) as `name`.
26
+ * The entry is cleared from the timeline buffer right away: the Performance
27
+ * panel captures it at measure time, and per-task measures would otherwise
28
+ * grow the buffer without bound (and trip Node's buffer-size warning).
29
+ */
30
+ export const measureAtoll = (name: string, start: number, end: number, t: TimingTrack): void => {
31
+ const perf = globalThis.performance as
32
+ | (Performance & { measure?: MeasureFn; clearMeasures?: (name?: string) => void })
33
+ | undefined;
34
+ if (typeof perf?.measure !== 'function') return;
35
+ try {
36
+ perf.measure(name, {
37
+ start,
38
+ end: Math.max(end, start),
39
+ detail: {
40
+ devtools: {
41
+ dataType: 'track-entry',
42
+ track: t.track,
43
+ trackGroup: 'atoll',
44
+ color: t.color ?? 'primary',
45
+ properties: t.properties,
46
+ tooltipText: t.tooltipText,
47
+ },
48
+ },
49
+ });
50
+ perf.clearMeasures?.(name);
51
+ } catch {
52
+ /* engines without the options-object measure signature */
53
+ }
54
+ };
55
+
56
+ /** Main-thread span of one call, dispatch → settle, on the runner's track. */
57
+ export const measureTaskCall = (
58
+ runnerId: string,
59
+ taskId: string,
60
+ callId: number,
61
+ slot: number,
62
+ start: number,
63
+ end: number,
64
+ ok: boolean,
65
+ ): void =>
66
+ measureAtoll(`atoll task ${taskId}`, start, end, {
67
+ track: runnerId,
68
+ color: ok ? 'primary' : 'error',
69
+ properties: [['runner', runnerId], ['slot', slot], ['call', callId], ['outcome', ok ? 'ok' : 'error']],
70
+ tooltipText: `${taskId} on ${runnerId}#${slot}: ${(end - start).toFixed(1)}ms`,
71
+ });
@@ -1,10 +1,22 @@
1
1
  import { TaskRegistry } from './registry';
2
2
  import { bindSharedMemories, getDefinedSharedMemoryCount } from '../contract/sharedMemory';
3
- import { enableWorkerDevtoolsForwarding } from '../devtools';
3
+ import { devtoolsEnabled, enableWorkerDevtoolsForwarding } from '../devtools';
4
4
  import { fmtBytes, scoped } from '../log';
5
+ import { measureAtoll } from '../userTiming';
5
6
 
6
7
  const workerLog = scoped('worker');
7
8
 
9
+ /** Worker-side span of one task execution, on this worker thread's 'tasks' track. */
10
+ const measureRun = (taskId: string, messageId: number, t0: number, ok: boolean): void => {
11
+ const t1 = performance.now();
12
+ measureAtoll(`atoll run ${taskId}`, t0, t1, {
13
+ track: 'tasks',
14
+ color: ok ? 'secondary' : 'error',
15
+ properties: [['message', messageId], ['outcome', ok ? 'ok' : 'error']],
16
+ tooltipText: `${taskId}: ${(t1 - t0).toFixed(1)}ms in worker`,
17
+ });
18
+ };
19
+
8
20
  let memoryInitialized = false;
9
21
  let wired = false;
10
22
 
@@ -42,11 +54,20 @@ export function installWorkerListener(): void {
42
54
  }
43
55
 
44
56
  if (data.type === 'INIT_MEMORY') {
45
- const memory = data.memory as WebAssembly.Memory;
46
- bindSharedMemories(memory.buffer as unknown as SharedArrayBuffer);
57
+ // `memory` is the pool-allocated WebAssembly.Memory; `buffer` is an
58
+ // existing SharedArrayBuffer the caller ships directly (sub-worker
59
+ // shell, second pool sharing a buffer).
60
+ const buffer =
61
+ (data.memory as WebAssembly.Memory | undefined)?.buffer ??
62
+ (data.buffer as SharedArrayBuffer | undefined);
63
+ if (!buffer) {
64
+ workerLog.warn('INIT_MEMORY arrived without a buffer — contracts stay unbound');
65
+ return;
66
+ }
67
+ bindSharedMemories(buffer as unknown as SharedArrayBuffer);
47
68
  memoryInitialized = true;
48
69
  if (data.devtools) enableWorkerDevtoolsForwarding();
49
- workerLog.info(`shared memory initialized (${fmtBytes(memory.buffer.byteLength)})`);
70
+ workerLog.info(`shared memory initialized (${fmtBytes(buffer.byteLength)})`);
50
71
  return;
51
72
  }
52
73
 
@@ -62,9 +83,11 @@ export function installWorkerListener(): void {
62
83
  const t0 = performance.now();
63
84
  try {
64
85
  const result = await TaskRegistry.execute(taskId, ...(args || []));
86
+ if (devtoolsEnabled()) measureRun(taskId, messageId, t0, true);
65
87
  workerLog.debug(`task ${taskId} → ${(performance.now() - t0).toFixed(1)}ms`);
66
88
  self.postMessage({ messageId, success: true, result });
67
89
  } catch (err: any) {
90
+ if (devtoolsEnabled()) measureRun(taskId, messageId, t0, false);
68
91
  workerLog.warn(`task ${taskId} failed: ${err.message || String(err)}`);
69
92
  self.postMessage({ messageId, success: false, error: err.message || String(err) });
70
93
  }