overtake 0.1.1 → 1.0.0-rc.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.
Files changed (70) hide show
  1. package/README.md +72 -79
  2. package/bin/overtake.js +2 -0
  3. package/build/__tests__/runner.d.ts +1 -0
  4. package/build/benchmark.cjs +237 -0
  5. package/build/benchmark.cjs.map +1 -0
  6. package/build/benchmark.d.ts +64 -0
  7. package/build/benchmark.js +189 -0
  8. package/build/benchmark.js.map +1 -0
  9. package/build/cli.cjs +149 -0
  10. package/build/cli.cjs.map +1 -0
  11. package/build/cli.d.ts +1 -0
  12. package/build/cli.js +104 -0
  13. package/build/cli.js.map +1 -0
  14. package/build/executor.cjs +68 -0
  15. package/build/executor.cjs.map +1 -0
  16. package/build/executor.d.ts +10 -0
  17. package/build/executor.js +58 -0
  18. package/build/executor.js.map +1 -0
  19. package/build/index.cjs +20 -0
  20. package/build/index.cjs.map +1 -0
  21. package/build/index.d.ts +5 -0
  22. package/build/index.js +3 -0
  23. package/build/index.js.map +1 -0
  24. package/build/queue.cjs +48 -0
  25. package/build/queue.cjs.map +1 -0
  26. package/build/queue.d.ts +3 -0
  27. package/build/queue.js +38 -0
  28. package/build/queue.js.map +1 -0
  29. package/build/reporter.cjs +175 -0
  30. package/build/reporter.cjs.map +1 -0
  31. package/build/reporter.d.ts +11 -0
  32. package/build/reporter.js +157 -0
  33. package/build/reporter.js.map +1 -0
  34. package/build/runner.cjs +92 -0
  35. package/build/runner.cjs.map +1 -0
  36. package/build/runner.d.ts +2 -0
  37. package/build/runner.js +82 -0
  38. package/build/runner.js.map +1 -0
  39. package/build/types.cjs +48 -0
  40. package/build/types.cjs.map +1 -0
  41. package/build/types.d.ts +59 -0
  42. package/build/types.js +21 -0
  43. package/build/types.js.map +1 -0
  44. package/build/utils.cjs +100 -0
  45. package/build/utils.cjs.map +1 -0
  46. package/build/utils.d.ts +20 -0
  47. package/build/utils.js +67 -0
  48. package/build/utils.js.map +1 -0
  49. package/build/worker.cjs +29 -0
  50. package/build/worker.cjs.map +1 -0
  51. package/build/worker.d.ts +1 -0
  52. package/build/worker.js +25 -0
  53. package/build/worker.js.map +1 -0
  54. package/package.json +25 -16
  55. package/src/__tests__/runner.ts +34 -0
  56. package/src/benchmark.ts +231 -0
  57. package/src/cli.ts +114 -0
  58. package/src/executor.ts +73 -0
  59. package/src/index.ts +6 -0
  60. package/src/queue.ts +42 -0
  61. package/src/reporter.ts +139 -0
  62. package/src/runner.ts +111 -0
  63. package/src/types.ts +72 -0
  64. package/src/utils.ts +65 -0
  65. package/src/worker.ts +46 -0
  66. package/tsconfig.json +17 -0
  67. package/cli.js +0 -70
  68. package/index.d.ts +0 -56
  69. package/index.js +0 -302
  70. package/runner.js +0 -3
package/index.js DELETED
@@ -1,302 +0,0 @@
1
- import { createContext } from 'conode';
2
- import WorkerThreads from 'worker_threads';
3
-
4
- const overtakeContext = createContext();
5
- const suiteContext = createContext();
6
-
7
- export const NOOP = () => {};
8
-
9
- export const allowedFields = [
10
- 'mode',
11
- 'med',
12
- 'p1',
13
- 'p5',
14
- 'p10',
15
- 'p20',
16
- 'p33',
17
- 'p50',
18
- 'p66',
19
- 'p80',
20
- 'p90',
21
- 'p95',
22
- 'p99',
23
- 'min',
24
- 'max',
25
- 'avg',
26
- 'sum',
27
- 'count',
28
- 'setup',
29
- 'init',
30
- 'cycles',
31
- 'teardown',
32
- 'total',
33
- ];
34
-
35
- export const setup = (fn) => {
36
- suiteContext.getContext().setup = fn;
37
- };
38
-
39
- export const teardown = (fn) => {
40
- suiteContext.getContext().teardown = fn;
41
- };
42
-
43
- export const measure = (title, fn) => {
44
- suiteContext.getContext().measures.push({ title, init: fn });
45
- };
46
-
47
- export const perform = (title, count, args) => {
48
- suiteContext.getContext().performs.push({ title, count, args });
49
- };
50
-
51
- export const benchmark = (title, fn) => {
52
- const setup = NOOP;
53
- const teardown = NOOP;
54
- const measures = [];
55
- const performs = [];
56
-
57
- overtakeContext.getContext().suites.push({
58
- title,
59
- setup,
60
- teardown,
61
- measures,
62
- performs,
63
- init: fn,
64
- });
65
- };
66
-
67
- export const createScript = async (filename, fn) => {
68
- const suites = [];
69
- const script = { filename, suites };
70
- await overtakeContext.contextualize(script, fn);
71
-
72
- return script;
73
- };
74
-
75
- export const load = async (filename) => {
76
- return createScript(filename, () => import(filename));
77
- };
78
-
79
- const map = {
80
- script: '⭐ Script ',
81
- suite: '⇶ Suite ',
82
- perform: '➤ Perform ',
83
- measure: '✓ Measure',
84
- };
85
-
86
- export const defaultReporter = async (type, title, test, fields) => {
87
- console.group(`${map[type]} ${title}`);
88
- await test({
89
- test: (...args) => defaultReporter(...args, fields),
90
- output: (report) =>
91
- console.table(
92
- report.success
93
- ? {
94
- [formatFloat(report.mode)]: fields.reduce((data, field) => {
95
- const [key, alias = key] = field.split(':');
96
- data[alias] = formatFloat(report[key]);
97
- return data;
98
- }, {}),
99
- }
100
- : {
101
- error: {
102
- reason: report.error,
103
- },
104
- },
105
- ),
106
- });
107
- console.groupEnd();
108
- };
109
-
110
- const ACCURACY = 6;
111
- export function formatFloat(value, digits = ACCURACY) {
112
- return parseFloat(value.toFixed(digits));
113
- }
114
-
115
- export const run = async (scripts, reporter, fields) => {
116
- for (const script of scripts) {
117
- await reporter(
118
- 'script',
119
- script.filename,
120
- async (scriptTest) => {
121
- for (const suite of script.suites) {
122
- await scriptTest.test('suite', suite.title, async (suiteTest) => {
123
- await suiteContext.contextualize(suite, suite.init);
124
- for (const perform of suite.performs) {
125
- await suiteTest.test('perform', perform.title, async (performTest) => {
126
- for (const measure of suite.measures) {
127
- await performTest.test('measure', perform.count + ' ' + measure.title, async (measureTest) => {
128
- const result = await runWorker({
129
- setup: suite.setup,
130
- teardown: suite.teardown,
131
- init: measure.init,
132
- count: perform.count,
133
- args: perform.args,
134
- });
135
- measureTest.output(result);
136
- });
137
- }
138
- });
139
- }
140
- });
141
- }
142
- },
143
- fields,
144
- );
145
- }
146
- };
147
-
148
- export async function runWorker({ args, count, ...options }, onProgress = null) {
149
- const setupCode = options.setup.toString();
150
- const teardownCode = options.teardown.toString();
151
- const initCode = options.init.toString();
152
- const params = JSON.stringify({
153
- setupCode,
154
- teardownCode,
155
- initCode,
156
- count,
157
- args,
158
- });
159
-
160
- const worker = new WorkerThreads.Worker(new URL('runner.js', import.meta.url), { argv: [params] });
161
- return new Promise((resolve) => {
162
- worker.on('message', (data) => {
163
- if (onProgress && data.type === 'progress') {
164
- onProgress(data);
165
- } else if (data.type === 'report') {
166
- resolve(data);
167
- }
168
- });
169
- worker.on('error', (error) => resolve({ success: false, error: error.message }));
170
- });
171
- }
172
-
173
- const FALSE_START = () => {
174
- throw new Error('False start');
175
- };
176
-
177
- export async function start(input) {
178
- const { setupCode, teardownCode, initCode, count, reportInterval = 500, args = [[]] } = JSON.parse(input);
179
- const setup = Function(`return ${setupCode};`)();
180
- const teardown = Function(`return ${teardownCode};`)();
181
- const init = Function(`return ${initCode};`)();
182
- const initArgsSize = init.length;
183
- const send = WorkerThreads.parentPort ? (data) => WorkerThreads.parentPort.postMessage(data) : (data) => console.log(data);
184
- let i = count;
185
- let done = FALSE_START;
186
-
187
- const timings = [];
188
- const argSize = args.length;
189
-
190
- send({ type: 'progress', stage: 'setup' });
191
- const startMark = performance.now();
192
- const context = await setup();
193
- const setupMark = performance.now();
194
-
195
- const initArgs = [];
196
- if (initArgsSize !== 0) {
197
- initArgs.push(() => done());
198
- }
199
- if (initArgsSize > 2) {
200
- initArgs.unshift(args);
201
- }
202
- if (initArgsSize > 1) {
203
- initArgs.unshift(context);
204
- }
205
-
206
- send({ type: 'progress', stage: 'init' });
207
- const initMark = performance.now();
208
- const action = await init(...initArgs);
209
- const initDoneMark = performance.now();
210
-
211
- try {
212
- let lastCheck = performance.now();
213
- const loop = (resolve, reject) => {
214
- const idx = count - i;
215
- const argIdx = idx % argSize;
216
- const timerId = setTimeout(reject, 10000, new Error('Timeout'));
217
-
218
- done = () => {
219
- const doneTick = performance.now();
220
- const elapsed = doneTick - startTickTime;
221
- clearTimeout(timerId);
222
- done = FALSE_START;
223
- timings.push(elapsed);
224
- if (doneTick - lastCheck > reportInterval) {
225
- lastCheck = doneTick;
226
- send({ type: 'progress', stage: 'cycles', progress: idx / count });
227
- }
228
- resolve();
229
- };
230
-
231
- const startTickTime = performance.now();
232
- action(...args[argIdx], idx);
233
- if (!initArgsSize) {
234
- done();
235
- }
236
- };
237
- const cyclesMark = performance.now();
238
-
239
- send({ type: 'progress', stage: 'cycles', progress: 0 });
240
- while (i--) {
241
- await new Promise(loop);
242
- }
243
- send({ type: 'progress', stage: 'teardown' });
244
- const teardownMark = performance.now();
245
- await teardown(context);
246
- const completeMark = performance.now();
247
- send({ type: 'progress', stage: 'complete', progress: (count - i) / count });
248
-
249
- timings.sort((a, b) => a - b);
250
-
251
- const min = timings[0];
252
- const max = timings[timings.length - 1];
253
- const range = max - min || Number.MIN_VALUE;
254
- const sum = timings.reduce((a, b) => a + b, 0);
255
- const avg = sum / timings.length;
256
-
257
- const step = range / 99 || Number.MIN_VALUE;
258
- const buckets = Array(100)
259
- .fill(0)
260
- .map((_, idx) => [min + idx * step, 0]);
261
-
262
- // Calc mode O(n)
263
- timings.forEach((timing, idx) => {
264
- const index = Math.round((timing - min) / step);
265
- buckets[index][1] += 1;
266
- });
267
- buckets.sort((a, b) => a[1] - b[1]);
268
-
269
- const percentile = (p) => timings[Math.trunc((p * timings.length) / 100)];
270
- const mode = buckets[buckets.length - 1][0];
271
-
272
- send({
273
- type: 'report',
274
- success: true,
275
- count: timings.length,
276
- min,
277
- max,
278
- sum,
279
- avg,
280
- mode,
281
- p1: percentile(1),
282
- p5: percentile(5),
283
- p10: percentile(10),
284
- p20: percentile(20),
285
- p33: percentile(33),
286
- p50: percentile(50),
287
- med: percentile(50),
288
- p66: percentile(66),
289
- p80: percentile(80),
290
- p90: percentile(90),
291
- p95: percentile(95),
292
- p99: percentile(99),
293
- setup: setupMark - startMark,
294
- init: initDoneMark - initMark,
295
- cycles: teardownMark - cyclesMark,
296
- teardown: completeMark - teardownMark,
297
- total: completeMark - setupMark,
298
- });
299
- } catch (error) {
300
- send({ type: 'report', success: false, error: error.stack });
301
- }
302
- }
package/runner.js DELETED
@@ -1,3 +0,0 @@
1
- import { start } from './index.js';
2
-
3
- start(process.argv[2]);