overtake 0.0.1-rc1 → 0.0.2
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/README.md +15 -9
- package/cli.js +15 -20
- package/index.d.ts +50 -9
- package/index.js +171 -137
- package/package.json +4 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Overtake
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Performance benchmark for NodeJS
|
|
4
4
|
|
|
5
5
|
[![Build Status][github-image]][github-url]
|
|
6
6
|
[![NPM version][npm-image]][npm-url]
|
|
@@ -55,7 +55,7 @@ benchmark('mongodb vs postgres', () => {
|
|
|
55
55
|
return { postgres, mongo };
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
measure('mongodb inserts', ({ mongo }/* context */, next) => {
|
|
58
|
+
measure('mongodb inserts', ({ mongo } /* context */, next) => {
|
|
59
59
|
// prepare a collection
|
|
60
60
|
const database = mongo.db('overtake');
|
|
61
61
|
const test = database.collection('test');
|
|
@@ -63,28 +63,34 @@ benchmark('mongodb vs postgres', () => {
|
|
|
63
63
|
return (data) => test.insertOne(data).then(next);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
measure('postgres inserts', ({ postgres }/* context */, next) => {
|
|
66
|
+
measure('postgres inserts', ({ postgres } /* context */, next) => {
|
|
67
67
|
// prepare a query
|
|
68
68
|
const query = 'INSERT INTO overtake(value) VALUES($1) RETURNING *';
|
|
69
69
|
|
|
70
70
|
return (data) => postgres.query(query, [data.value]).then(next);
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
teardown(({ mongo, postgres }) => {
|
|
74
|
-
await postgres.end()
|
|
75
|
-
await mongo.end()
|
|
73
|
+
teardown(async ({ mongo, postgres }) => {
|
|
74
|
+
await postgres.end();
|
|
75
|
+
await mongo.end();
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
perform('simple test', 100000, [
|
|
79
|
-
{ value: 'test' },
|
|
80
|
-
]);
|
|
78
|
+
perform('simple test', 100000, [[{ value: 'test' }]]);
|
|
81
79
|
});
|
|
82
80
|
```
|
|
83
81
|
|
|
82
|
+
Make sure you have installed used modules and run
|
|
83
|
+
|
|
84
84
|
```bash
|
|
85
85
|
yarn overtake
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
or
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx overtake
|
|
92
|
+
```
|
|
93
|
+
|
|
88
94
|
Please take a look at [benchmarks](__benchmarks__) to see more examples
|
|
89
95
|
|
|
90
96
|
## License
|
package/cli.js
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { promisify } from 'util';
|
|
2
4
|
import Path from 'path';
|
|
3
5
|
import glob from 'glob';
|
|
4
|
-
import { benchmark, setup, teardown, measure, perform,
|
|
6
|
+
import { load, benchmark, setup, teardown, measure, perform, run, defaultReporter } from './index.js';
|
|
5
7
|
|
|
8
|
+
const globAsync = promisify(glob);
|
|
6
9
|
const pattern = process.argv[2] || '**/__benchmarks__/**/*.js';
|
|
7
10
|
|
|
8
|
-
Object.assign(globalThis, {
|
|
9
|
-
benchmark,
|
|
10
|
-
setup,
|
|
11
|
-
teardown,
|
|
12
|
-
measure,
|
|
13
|
-
perform,
|
|
14
|
-
});
|
|
11
|
+
Object.assign(globalThis, { benchmark, setup, teardown, measure, perform });
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.error(e.stack);
|
|
24
|
-
}
|
|
25
|
-
for (const suite of suites) {
|
|
26
|
-
await runner(suite);
|
|
13
|
+
(async () => {
|
|
14
|
+
const files = await globAsync(pattern);
|
|
15
|
+
const scripts = [];
|
|
16
|
+
for (const file of files) {
|
|
17
|
+
const filename = Path.resolve(file);
|
|
18
|
+
const script = await load(filename);
|
|
19
|
+
scripts.push(script);
|
|
27
20
|
}
|
|
28
|
-
|
|
21
|
+
|
|
22
|
+
await run(scripts, defaultReporter);
|
|
23
|
+
})().catch((e) => console.error(e));
|
package/index.d.ts
CHANGED
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
declare global {
|
|
2
|
-
|
|
2
|
+
type CanBePromise<T> = Promise<T> | T;
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
interface Report {
|
|
5
|
+
type: string;
|
|
6
|
+
success: boolean;
|
|
7
|
+
count: number;
|
|
8
|
+
min: number;
|
|
9
|
+
max: number;
|
|
10
|
+
sum: number;
|
|
11
|
+
avg: number;
|
|
12
|
+
mode: number;
|
|
13
|
+
p1: number;
|
|
14
|
+
p5: number;
|
|
15
|
+
p20: number;
|
|
16
|
+
p33: number;
|
|
17
|
+
p50: number;
|
|
18
|
+
med: number;
|
|
19
|
+
p66: number;
|
|
20
|
+
p80: number;
|
|
21
|
+
p90: number;
|
|
22
|
+
p95: number;
|
|
23
|
+
p99: number;
|
|
24
|
+
setup: number;
|
|
25
|
+
init: number;
|
|
26
|
+
cycles: number;
|
|
27
|
+
teardown: number;
|
|
28
|
+
total: number;
|
|
29
|
+
}
|
|
5
30
|
|
|
6
|
-
|
|
31
|
+
type MeasureInitResult = CanBePromise<() => void>;
|
|
7
32
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
33
|
+
function measure(title: string, init: () => MeasureInitResult): void;
|
|
34
|
+
function measure(title: string, init: (next: () => void) => MeasureInitResult): void;
|
|
35
|
+
function measure<C>(title: string, init: (context: C, next: () => void) => MeasureInitResult): void;
|
|
36
|
+
function measure<C, A>(title: string, init: (context: C, args: A, next: () => void) => MeasureInitResult): void;
|
|
11
37
|
|
|
12
|
-
|
|
13
|
-
|
|
38
|
+
function perform<A>(title: string, counter: number, args: A): void;
|
|
39
|
+
|
|
40
|
+
function setup<C>(init: () => CanBePromise<C>): void;
|
|
41
|
+
|
|
42
|
+
function teardown<C>(teardown: (context: C) => CanBePromise<void>): void;
|
|
14
43
|
|
|
15
|
-
|
|
44
|
+
interface Suite {
|
|
45
|
+
title: string;
|
|
46
|
+
setup: typeof setup;
|
|
47
|
+
teardown: typeof teardown;
|
|
48
|
+
measures: typeof measure[];
|
|
49
|
+
performs: typeof perform[];
|
|
50
|
+
init: () => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function benchmark(title: string, init: () => void): void;
|
|
54
|
+
|
|
55
|
+
function script(filename): Promise<Suite[]>;
|
|
56
|
+
}
|
package/index.js
CHANGED
|
@@ -1,67 +1,112 @@
|
|
|
1
|
+
import { createContext } from 'conode';
|
|
1
2
|
import WorkerThreads from 'worker_threads';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const overtakeContext = createContext();
|
|
5
|
+
const suiteContext = createContext();
|
|
4
6
|
|
|
5
|
-
const NOOP = () => {};
|
|
7
|
+
export const NOOP = () => {};
|
|
6
8
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
+
export const setup = (fn) => {
|
|
10
|
+
suiteContext.getContext().setup = fn;
|
|
11
|
+
};
|
|
9
12
|
|
|
10
|
-
const
|
|
13
|
+
export const teardown = (fn) => {
|
|
14
|
+
suiteContext.getContext().teardown = fn;
|
|
15
|
+
};
|
|
11
16
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
process.stdout.write(SPINNER[index]);
|
|
15
|
-
process.stdout.moveCursor(-3, 1);
|
|
17
|
+
export const measure = (title, fn) => {
|
|
18
|
+
suiteContext.getContext().measures.push({ title, init: fn });
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
current: true,
|
|
22
|
-
measures: [],
|
|
23
|
-
performs: [],
|
|
24
|
-
setup: NOOP,
|
|
25
|
-
teardown: NOOP,
|
|
26
|
-
};
|
|
27
|
-
suites.push(suite);
|
|
28
|
-
init();
|
|
29
|
-
suite.current = false;
|
|
30
|
-
}
|
|
21
|
+
export const perform = (title, count, args) => {
|
|
22
|
+
suiteContext.getContext().performs.push({ title, count, args });
|
|
23
|
+
};
|
|
31
24
|
|
|
32
|
-
export
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return suite;
|
|
38
|
-
}
|
|
25
|
+
export const benchmark = (title, fn) => {
|
|
26
|
+
const setup = NOOP;
|
|
27
|
+
const teardown = NOOP;
|
|
28
|
+
const measures = [];
|
|
29
|
+
const performs = [];
|
|
39
30
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
overtakeContext.getContext().suites.push({
|
|
32
|
+
title,
|
|
33
|
+
setup,
|
|
34
|
+
teardown,
|
|
35
|
+
measures,
|
|
36
|
+
performs,
|
|
37
|
+
init: fn,
|
|
38
|
+
});
|
|
39
|
+
};
|
|
44
40
|
|
|
45
|
-
export
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
export const load = async (filename) => {
|
|
42
|
+
const suites = [];
|
|
43
|
+
const script = { filename, suites };
|
|
44
|
+
await overtakeContext.contextualize(script, () => import(filename));
|
|
49
45
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
return script;
|
|
47
|
+
};
|
|
48
|
+
const map = {
|
|
49
|
+
script: '⭐ Script ',
|
|
50
|
+
suite: '⇶ Suite ',
|
|
51
|
+
perform: '➤ Perform ',
|
|
52
|
+
measure: '✓ Measure',
|
|
53
|
+
};
|
|
54
54
|
|
|
55
|
-
export
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
export const defaultReporter = async (type, title, test) => {
|
|
56
|
+
console.group(`${map[type]} ${title}`);
|
|
57
|
+
await test({ test: defaultReporter, output: (report) => console.table(report) });
|
|
58
|
+
console.groupEnd();
|
|
59
|
+
};
|
|
59
60
|
|
|
61
|
+
const ACCURACY = 6;
|
|
60
62
|
export function formatFloat(value, digits = ACCURACY) {
|
|
61
63
|
return parseFloat(value.toFixed(digits));
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
export
|
|
66
|
+
export const run = async (scripts, reporter) => {
|
|
67
|
+
for (const script of scripts) {
|
|
68
|
+
await reporter('script', script.filename, async (scriptTest) => {
|
|
69
|
+
for (const suite of script.suites) {
|
|
70
|
+
await scriptTest.test('suite', suite.title, async (suiteTest) => {
|
|
71
|
+
await suiteContext.contextualize(suite, suite.init);
|
|
72
|
+
for (const perform of suite.performs) {
|
|
73
|
+
await suiteTest.test('perform', perform.title, async (performTest) => {
|
|
74
|
+
for (const measure of suite.measures) {
|
|
75
|
+
await performTest.test('measure', measure.title, async (measureTest) => {
|
|
76
|
+
const result = await runWorker({
|
|
77
|
+
setup: suite.setup,
|
|
78
|
+
teardown: suite.teardown,
|
|
79
|
+
init: measure.init,
|
|
80
|
+
count: perform.count,
|
|
81
|
+
args: perform.args,
|
|
82
|
+
});
|
|
83
|
+
if (result.success) {
|
|
84
|
+
measureTest.output({
|
|
85
|
+
[formatFloat(result.mode)]: {
|
|
86
|
+
total: formatFloat(result.total),
|
|
87
|
+
med: formatFloat(result.med),
|
|
88
|
+
p95: formatFloat(result.p95),
|
|
89
|
+
p99: formatFloat(result.p99),
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
measureTest.output({
|
|
94
|
+
error: {
|
|
95
|
+
reason: result.error,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export async function runWorker({ args, count, ...options }, onProgress = null) {
|
|
65
110
|
const setupCode = options.setup.toString();
|
|
66
111
|
const teardownCode = options.teardown.toString();
|
|
67
112
|
const initCode = options.init.toString();
|
|
@@ -72,81 +117,42 @@ export async function runWorker({ args, count, ...options }) {
|
|
|
72
117
|
count,
|
|
73
118
|
args,
|
|
74
119
|
});
|
|
75
|
-
let i = 0;
|
|
76
|
-
const spinnerSize = SPINNER.length - 1;
|
|
77
|
-
|
|
78
|
-
const timerId = setInterval(() => renderSpinner(i++ % spinnerSize), SPINNER_INTERVAL);
|
|
79
120
|
|
|
80
121
|
const worker = new WorkerThreads.Worker(new URL('runner.js', import.meta.url), { argv: [params] });
|
|
81
122
|
return new Promise((resolve) => {
|
|
82
|
-
worker.on('message',
|
|
123
|
+
worker.on('message', (data) => {
|
|
124
|
+
if (onProgress && data.type === 'progress') {
|
|
125
|
+
onProgress(data);
|
|
126
|
+
} else if (data.type === 'report') {
|
|
127
|
+
resolve(data);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
83
130
|
worker.on('error', (error) => resolve({ success: false, error: error.message }));
|
|
84
|
-
}).finally((result) => {
|
|
85
|
-
clearInterval(timerId);
|
|
86
|
-
renderSpinner(spinnerSize);
|
|
87
|
-
|
|
88
|
-
return result;
|
|
89
131
|
});
|
|
90
132
|
}
|
|
91
133
|
|
|
92
|
-
export async function runner(suite) {
|
|
93
|
-
console.group(`\nStart ${suite.title} benchmark`);
|
|
94
|
-
|
|
95
|
-
for (let measureIdx = 0; measureIdx < suite.measures.length; measureIdx++) {
|
|
96
|
-
const currentMeasure = suite.measures[measureIdx];
|
|
97
|
-
const reports = {};
|
|
98
|
-
console.group(`\n Measuring performance of ${currentMeasure.title}`);
|
|
99
|
-
for (let performIdx = 0; performIdx < suite.performs.length; performIdx++) {
|
|
100
|
-
const currentPerform = suite.performs[performIdx];
|
|
101
|
-
const report = await runWorker({
|
|
102
|
-
setup: suite.setup,
|
|
103
|
-
teardown: suite.teardown,
|
|
104
|
-
init: currentMeasure.init,
|
|
105
|
-
count: currentPerform.count,
|
|
106
|
-
args: currentPerform.args,
|
|
107
|
-
});
|
|
108
|
-
reports[currentPerform.title] = { title: perform.title, report };
|
|
109
|
-
if (report.success) {
|
|
110
|
-
reports[currentPerform.title] = {
|
|
111
|
-
Count: currentPerform.count,
|
|
112
|
-
'Setup, ms': formatFloat(report.setup),
|
|
113
|
-
'Work, ms': formatFloat(report.work),
|
|
114
|
-
'Avg, ms': formatFloat(report.avg),
|
|
115
|
-
'Mode, ms': report.mode,
|
|
116
|
-
};
|
|
117
|
-
} else {
|
|
118
|
-
reports[`${currentPerform.title} ${currentMeasure.title}`] = {
|
|
119
|
-
Count: currentPerform.count,
|
|
120
|
-
'Setup, ms': '?',
|
|
121
|
-
'Work, ms': '?',
|
|
122
|
-
'Avg, ms': '?',
|
|
123
|
-
'Mode, ms': '?',
|
|
124
|
-
Error: report.error,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
console.groupEnd();
|
|
129
|
-
console.table(reports);
|
|
130
|
-
}
|
|
131
|
-
console.groupEnd();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
134
|
const FALSE_START = () => {
|
|
135
135
|
throw new Error('False start');
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
export async function start(input) {
|
|
139
|
-
const { setupCode, teardownCode, initCode, count, args = [[]] } = JSON.parse(input);
|
|
139
|
+
const { setupCode, teardownCode, initCode, count, reportInterval = 500, args = [[]] } = JSON.parse(input);
|
|
140
140
|
const setup = Function(`return ${setupCode};`)();
|
|
141
141
|
const teardown = Function(`return ${teardownCode};`)();
|
|
142
142
|
const init = Function(`return ${initCode};`)();
|
|
143
|
+
const send = WorkerThreads.parentPort ? (data) => WorkerThreads.parentPort.postMessage(data) : (data) => console.log(data);
|
|
143
144
|
|
|
144
145
|
let i = count;
|
|
145
146
|
let done = FALSE_START;
|
|
146
147
|
|
|
147
148
|
const timings = [];
|
|
148
149
|
const argSize = args.length;
|
|
150
|
+
|
|
151
|
+
send({ type: 'progress', stage: 'setup' });
|
|
152
|
+
const startMark = performance.now();
|
|
149
153
|
const context = await setup();
|
|
154
|
+
const setupMark = performance.now();
|
|
155
|
+
|
|
150
156
|
const initArgs = [() => done()];
|
|
151
157
|
if (init.length > 2) {
|
|
152
158
|
initArgs.unshift(args);
|
|
@@ -154,70 +160,98 @@ export async function start(input) {
|
|
|
154
160
|
if (init.length > 1) {
|
|
155
161
|
initArgs.unshift(context);
|
|
156
162
|
}
|
|
157
|
-
|
|
163
|
+
|
|
164
|
+
send({ type: 'progress', stage: 'init' });
|
|
165
|
+
const initMark = performance.now();
|
|
158
166
|
const action = await init(...initArgs);
|
|
159
|
-
const
|
|
167
|
+
const initDoneMark = performance.now();
|
|
160
168
|
|
|
161
169
|
try {
|
|
170
|
+
let lastCheck = performance.now();
|
|
162
171
|
const loop = (resolve, reject) => {
|
|
163
|
-
const
|
|
172
|
+
const idx = count - i;
|
|
173
|
+
const argIdx = idx % argSize;
|
|
164
174
|
const timerId = setTimeout(reject, 10000, new Error('Timeout'));
|
|
165
175
|
|
|
166
176
|
done = () => {
|
|
167
|
-
|
|
168
|
-
const elapsed =
|
|
177
|
+
const doneTick = performance.now();
|
|
178
|
+
const elapsed = doneTick - startTickTime;
|
|
169
179
|
clearTimeout(timerId);
|
|
170
180
|
done = FALSE_START;
|
|
171
181
|
timings.push(elapsed);
|
|
172
|
-
|
|
182
|
+
if (doneTick - lastCheck > reportInterval) {
|
|
183
|
+
lastCheck = doneTick;
|
|
184
|
+
send({ type: 'progress', stage: 'cycles', progress: idx / count });
|
|
185
|
+
}
|
|
173
186
|
resolve();
|
|
174
187
|
};
|
|
188
|
+
|
|
175
189
|
const startTickTime = performance.now();
|
|
176
|
-
action(...args[argIdx],
|
|
190
|
+
action(...args[argIdx], idx);
|
|
177
191
|
};
|
|
192
|
+
const cyclesMark = performance.now();
|
|
178
193
|
|
|
194
|
+
send({ type: 'progress', stage: 'cycles', progress: 0 });
|
|
179
195
|
while (i--) {
|
|
180
196
|
await new Promise(loop);
|
|
181
197
|
}
|
|
198
|
+
send({ type: 'progress', stage: 'teardown' });
|
|
199
|
+
const teardownMark = performance.now();
|
|
200
|
+
await teardown(context);
|
|
182
201
|
const completeMark = performance.now();
|
|
202
|
+
send({ type: 'progress', stage: 'complete', progress: (count - i) / count });
|
|
183
203
|
|
|
184
|
-
|
|
204
|
+
timings.sort((a, b) => a - b);
|
|
205
|
+
|
|
206
|
+
const min = timings[0];
|
|
207
|
+
const max = timings[timings.length - 1];
|
|
208
|
+
const range = max - min || Number.MIN_VALUE;
|
|
209
|
+
const sum = timings.reduce((a, b) => a + b, 0);
|
|
210
|
+
const avg = sum / timings.length;
|
|
185
211
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const p95 = timings[p95idx];
|
|
206
|
-
const p99 = timings[p99idx];
|
|
207
|
-
|
|
208
|
-
WorkerThreads.parentPort.postMessage({
|
|
212
|
+
const step = range / 99 || Number.MIN_VALUE;
|
|
213
|
+
const buckets = Array(100)
|
|
214
|
+
.fill(0)
|
|
215
|
+
.map((_, idx) => [min + idx * step, 0]);
|
|
216
|
+
|
|
217
|
+
// Calc mode O(n)
|
|
218
|
+
timings.forEach((timing, idx) => {
|
|
219
|
+
const index = Math.round((timing - min) / step);
|
|
220
|
+
buckets[index][1] += 1;
|
|
221
|
+
});
|
|
222
|
+
buckets.sort((a, b) => a[1] - b[1]);
|
|
223
|
+
|
|
224
|
+
const percentile = (p) => timings[Math.trunc((p * timings.length) / 100)];
|
|
225
|
+
const mode = buckets[buckets.length - 1][0];
|
|
226
|
+
|
|
227
|
+
send({
|
|
228
|
+
type: 'report',
|
|
229
|
+
success: true,
|
|
230
|
+
count: timings.length,
|
|
209
231
|
min,
|
|
210
232
|
max,
|
|
233
|
+
sum,
|
|
211
234
|
avg,
|
|
212
|
-
p90,
|
|
213
|
-
p95,
|
|
214
|
-
p99,
|
|
215
235
|
mode,
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
236
|
+
p1: percentile(1),
|
|
237
|
+
p5: percentile(5),
|
|
238
|
+
p10: percentile(10),
|
|
239
|
+
p20: percentile(20),
|
|
240
|
+
p33: percentile(33),
|
|
241
|
+
p50: percentile(50),
|
|
242
|
+
med: percentile(50),
|
|
243
|
+
p66: percentile(66),
|
|
244
|
+
p80: percentile(80),
|
|
245
|
+
p90: percentile(90),
|
|
246
|
+
p95: percentile(95),
|
|
247
|
+
p99: percentile(99),
|
|
248
|
+
setup: setupMark - startMark,
|
|
249
|
+
init: initDoneMark - initMark,
|
|
250
|
+
cycles: teardownMark - cyclesMark,
|
|
251
|
+
teardown: completeMark - teardownMark,
|
|
252
|
+
total: completeMark - setupMark,
|
|
219
253
|
});
|
|
220
254
|
} catch (error) {
|
|
221
|
-
|
|
255
|
+
send({ type: 'report', success: false, error: error.stack });
|
|
222
256
|
}
|
|
223
257
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overtake",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "NodeJS performance benchmark",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"overtake": "cli.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"
|
|
13
|
-
"test": "yarn node --experimental-vm-modules $(yarn bin jest)",
|
|
12
|
+
"start": "node ./cli.js",
|
|
13
|
+
"test": "yarn node --experimental-vm-modules $(yarn bin jest) --detectOpenHandles",
|
|
14
14
|
"lint": "eslint .",
|
|
15
15
|
"prepare": "husky install"
|
|
16
16
|
},
|
|
@@ -33,16 +33,13 @@
|
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@jest/globals": "^27.5.1",
|
|
35
35
|
"@types/jest": "^27.4.1",
|
|
36
|
-
"eslint": "^8.14.0",
|
|
37
|
-
"eslint-config-airbnb-base": "^15.0.0",
|
|
38
|
-
"eslint-config-prettier": "^8.5.0",
|
|
39
|
-
"eslint-plugin-import": "^2.26.0",
|
|
40
36
|
"husky": "^7.0.4",
|
|
41
37
|
"jest": "^27.5.1",
|
|
42
38
|
"prettier": "^2.6.2",
|
|
43
39
|
"pretty-quick": "^3.1.3"
|
|
44
40
|
},
|
|
45
41
|
"dependencies": {
|
|
42
|
+
"conode": "^0.1.0",
|
|
46
43
|
"glob": "^8.0.1"
|
|
47
44
|
}
|
|
48
45
|
}
|