@nadrif/thread 0.1.0

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.
package/src/metrix.js ADDED
@@ -0,0 +1,222 @@
1
+ /**
2
+ * @file Lightweight performance counter for threads and pools.
3
+ *
4
+ * `Metrics` tracks cumulative statistics about task execution – counts,
5
+ * error rates, duration distributions, and throughput. Every thread and
6
+ * pool maintain an internal `Metrics` instance that is updated
7
+ * automatically after each task.
8
+ *
9
+ * **Design note:** Error recordings (where `success = false`) increment
10
+ * the counter and error tally but do **not** affect `avg`, `min`, `max`,
11
+ * or `throughput`. This keeps the timing statistics meaningful – a
12
+ * crashed task that took 0 ms should not pull the average down.
13
+ *
14
+ * @example
15
+ * ```js
16
+ * import { Metrics } from './metrix.js';
17
+ *
18
+ * const m = new Metrics();
19
+ *
20
+ * m.record(120, true); // successful task, 120ms
21
+ * m.record(85, true); // successful task, 85ms
22
+ * m.record(0, false); // failed task
23
+ *
24
+ * const snap = m.snapshot();
25
+ * console.log(snap);
26
+ * // {
27
+ * // count: 3, ← total tasks (success + error)
28
+ * // errors: 1, ← failed tasks
29
+ * // avg: 102.5, ← (120+85)/2 – only successes
30
+ * // min: 85, ← fastest success
31
+ * // max: 120, ← slowest success
32
+ * // throughput: 9.76 ← ~9.76 tasks/sec (only successes)
33
+ * // errorRate: 0.33 ← 33% error rate
34
+ * // }
35
+ * ```
36
+ *
37
+ * @module metrix
38
+ */
39
+
40
+ /**
41
+ * Tracks performance metrics for a thread or pool.
42
+ *
43
+ * Instances are lightweight – no timers, no async work. They simply
44
+ * accumulate data that you can query at any time via getters or
45
+ * {@link Metrics.snapshot}.
46
+ */
47
+ export class Metrics {
48
+ /** Create an empty metrics tracker. */
49
+ constructor() {
50
+ /** @type {number} Total tasks recorded (success + error). */
51
+ this._count = 0;
52
+ /** @type {number} Successful tasks recorded. */
53
+ this._successCount = 0;
54
+ /** @type {number} Failed tasks recorded. */
55
+ this._errors = 0;
56
+ /** @type {number} Cumulative duration of successful tasks (ms). */
57
+ this._totalTime = 0;
58
+ /** @type {number} Shortest successful task (ms). */
59
+ this._min = Infinity;
60
+ /** @type {number} Longest successful task (ms). */
61
+ this._max = -Infinity;
62
+ }
63
+
64
+ // -----------------------------------------------------------------------
65
+ // Recording
66
+ // -----------------------------------------------------------------------
67
+
68
+ /**
69
+ * Record a single task execution.
70
+ *
71
+ * Call this once per completed (or failed) task. Successful tasks
72
+ * update duration stats (`avg`, `min`, `max`, `throughput`); failed
73
+ * tasks only increment the error counter.
74
+ *
75
+ * @param {number} duration - Wall-clock duration in **milliseconds**.
76
+ * For failed tasks this is typically `0` since no meaningful timing
77
+ * is available.
78
+ * @param {boolean} [success=true] - Pass `false` for failed tasks.
79
+ *
80
+ * @example
81
+ * ```js
82
+ * const m = new Metrics();
83
+ * const start = performance.now();
84
+ * await doWork();
85
+ * m.record(performance.now() - start, true);
86
+ * ```
87
+ *
88
+ * @example
89
+ * ```js
90
+ * // Recording a failure
91
+ * m.record(0, false);
92
+ * ```
93
+ */
94
+ record(duration, success = true) {
95
+ this._count++;
96
+ if (!success) {
97
+ this._errors++;
98
+ return;
99
+ }
100
+ this._successCount++;
101
+ this._totalTime += duration;
102
+ if (duration < this._min) this._min = duration;
103
+ if (duration > this._max) this._max = duration;
104
+ }
105
+
106
+ // -----------------------------------------------------------------------
107
+ // Getters
108
+ // -----------------------------------------------------------------------
109
+
110
+ /**
111
+ * Average duration of **successful** tasks in milliseconds.
112
+ *
113
+ * Returns `0` when no successful tasks have been recorded.
114
+ *
115
+ * @type {number}
116
+ *
117
+ * @example
118
+ * ```js
119
+ * m.record(100, true);
120
+ * m.record(200, true);
121
+ * console.log(m.avg); // 150
122
+ * ```
123
+ */
124
+ get avg() {
125
+ return this._successCount > 0 ? this._totalTime / this._successCount : 0;
126
+ }
127
+
128
+ /**
129
+ * Throughput of **successful** tasks per second.
130
+ *
131
+ * Computed as `successCount / (totalTimeMs / 1000)`. Returns `0`
132
+ * when no successful tasks have been recorded.
133
+ *
134
+ * @type {number}
135
+ *
136
+ * @example
137
+ * ```js
138
+ * m.record(500, true); // 500ms
139
+ * m.record(500, true); // 500ms → total 1s
140
+ * console.log(m.throughput); // 2 (tasks per second)
141
+ * ```
142
+ */
143
+ get throughput() {
144
+ return this._successCount > 0 ? this._successCount / (this._totalTime / 1000) : 0;
145
+ }
146
+
147
+ /**
148
+ * Error rate as a fraction between 0 and 1.
149
+ *
150
+ * Computed as `errors / totalCount`. Returns `0` when no tasks have
151
+ * been recorded.
152
+ *
153
+ * @type {number}
154
+ *
155
+ * @example
156
+ * ```js
157
+ * m.record(0, false);
158
+ * m.record(0, false);
159
+ * m.record(100, true);
160
+ * console.log(m.errorRate); // 0.666… (2 errors out of 3 tasks)
161
+ * ```
162
+ */
163
+ get errorRate() {
164
+ return this._count > 0 ? this._errors / this._count : 0;
165
+ }
166
+
167
+ // -----------------------------------------------------------------------
168
+ // Snapshot & reset
169
+ // -----------------------------------------------------------------------
170
+
171
+ /**
172
+ * Return an immutable snapshot of all metrics as a plain object.
173
+ *
174
+ * The snapshot is a **copy** – mutating it has no effect on the
175
+ * tracker. `min` and `max` are `0` when no successful tasks exist
176
+ * (instead of `Infinity` / `-Infinity`).
177
+ *
178
+ * @returns {import('./types.js').MetricsSnapshot} Current metrics state.
179
+ *
180
+ * @example
181
+ * ```js
182
+ * const snap = thread.metrics; // calls snapshot() internally
183
+ * console.log(`Tasks: ${snap.count}, Avg: ${snap.avg.toFixed(1)}ms`);
184
+ * console.log(`Error rate: ${(snap.errorRate * 100).toFixed(1)}%`);
185
+ * ```
186
+ */
187
+ snapshot() {
188
+ return {
189
+ count: this._count,
190
+ errors: this._errors,
191
+ avg: this.avg,
192
+ min: this._min === Infinity ? 0 : this._min,
193
+ max: this._max === -Infinity ? 0 : this._max,
194
+ throughput: this.throughput,
195
+ errorRate: this.errorRate,
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Reset all counters to their initial values.
201
+ *
202
+ * After calling `reset()`, the tracker is indistinguishable from a
203
+ * freshly constructed one.
204
+ *
205
+ * @example
206
+ * ```js
207
+ * // Reset metrics at the start of each minute
208
+ * setInterval(() => {
209
+ * console.log('Last minute:', thread.metrics);
210
+ * thread._metrics.reset(); // internal, but illustrates the idea
211
+ * }, 60_000);
212
+ * ```
213
+ */
214
+ reset() {
215
+ this._count = 0;
216
+ this._successCount = 0;
217
+ this._errors = 0;
218
+ this._totalTime = 0;
219
+ this._min = Infinity;
220
+ this._max = -Infinity;
221
+ }
222
+ }
package/src/node.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @file Node.js-specific entry point for the thread library.
3
+ *
4
+ * This entry point is optimised for Node.js and Bun runtimes. It:
5
+ *
6
+ * 1. Uses `worker_threads` for Worker creation (not Blob URLs)
7
+ * 2. Loads config from the filesystem (`fs.readFileSync`)
8
+ * 3. Supports dynamic `import()` for GPU bindings
9
+ *
10
+ * **Usage:**
11
+ *
12
+ * ```js
13
+ * // In your Node.js project
14
+ * import { Thread, ThreadPool, GPUCompute } from 'thread/node';
15
+ * ```
16
+ *
17
+ * Or in `package.json`:
18
+ * ```json
19
+ * {
20
+ * "imports": {
21
+ * "#thread": "thread/node"
22
+ * }
23
+ * }
24
+ * ```
25
+ *
26
+ * @module thread/node
27
+ */
28
+
29
+ // Re-export everything from the main entry point
30
+ export * from './index.js';
31
+ export { default } from './index.js';
32
+
33
+ // Re-export environment-specific utilities
34
+ export { env } from './env.js';
35
+ export { createWorker, terminateWorker, supportsWorkers, workerInfo } from './worker-factory.js';
36
+ export { gpuEnv, isGPUAvailable, requestGPUAdapter, requestGPUDevice } from './gpu/env.js';