overtake 0.0.1-rc2 → 0.0.3
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 +12 -8
- package/cli.js +73 -15
- package/index.d.ts +56 -0
- package/index.js +117 -177
- package/package.json +4 -3
- package/reporter.js +0 -90
package/README.md
CHANGED
|
@@ -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,21 +63,19 @@ 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
|
|
|
@@ -87,6 +85,12 @@ Make sure you have installed used modules and run
|
|
|
87
85
|
yarn overtake
|
|
88
86
|
```
|
|
89
87
|
|
|
88
|
+
or
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx overtake
|
|
92
|
+
```
|
|
93
|
+
|
|
90
94
|
Please take a look at [benchmarks](__benchmarks__) to see more examples
|
|
91
95
|
|
|
92
96
|
## License
|
package/cli.js
CHANGED
|
@@ -1,19 +1,77 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { Command } from 'commander';
|
|
3
4
|
import { promisify } from 'util';
|
|
5
|
+
import Path from 'path';
|
|
4
6
|
import glob from 'glob';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
import { load, createScript, benchmark, setup, teardown, measure, perform, run, defaultReporter } from './index.js';
|
|
8
|
+
import packageJson from './package.json' assert { type: 'json' };
|
|
9
|
+
|
|
10
|
+
const commands = new Command();
|
|
11
|
+
|
|
12
|
+
commands.name('overtake').description(packageJson.description).version(packageJson.version, '-v, --version');
|
|
13
|
+
|
|
14
|
+
commands
|
|
15
|
+
.argument('[files...]', 'file paths or path patterns to search benchmark scripts')
|
|
16
|
+
.option('-i, --inline [inline]', 'inline code to benchmark', (value, previous) => previous.concat([value]), [])
|
|
17
|
+
.option('-c, --count [count]', 'perform count for inline code', (v) => parseInt(v))
|
|
18
|
+
.action(async (patterns, { count = 100, inline }) => {
|
|
19
|
+
Object.assign(globalThis, { benchmark, setup, teardown, measure, perform });
|
|
20
|
+
|
|
21
|
+
const globAsync = promisify(glob);
|
|
22
|
+
const foundFiles = await Promise.all(patterns.map((pattern) => globAsync(pattern)));
|
|
23
|
+
const files = [
|
|
24
|
+
...new Set(
|
|
25
|
+
[]
|
|
26
|
+
.concat(...foundFiles)
|
|
27
|
+
.map((filename) => Path.resolve(filename))
|
|
28
|
+
.filter(Boolean)
|
|
29
|
+
),
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const scripts = [];
|
|
33
|
+
if (inline.length) {
|
|
34
|
+
const inlineScript = await createScript('', () => {
|
|
35
|
+
benchmark('', () => {
|
|
36
|
+
inline.forEach((code) => {
|
|
37
|
+
measure(code, `() => () => { ${code} }`);
|
|
38
|
+
});
|
|
39
|
+
perform('', count);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
scripts.push(inlineScript);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
for (const file of files) {
|
|
46
|
+
const filename = Path.resolve(file);
|
|
47
|
+
const script = await load(filename);
|
|
48
|
+
scripts.push(script);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
await run(scripts, defaultReporter);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
commands.on('--help', () => {
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log('Examples:');
|
|
57
|
+
console.log(' $ overtake **/__benchmarks__/*.js');
|
|
58
|
+
console.log(' $ overtake -i "class A{}" -i "function A(){}" -i "const A = () => {}" -c 1000000');
|
|
59
|
+
console.log(' $ overtake -v');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
commands.parse(process.argv);
|
|
63
|
+
|
|
64
|
+
//
|
|
65
|
+
|
|
66
|
+
//
|
|
67
|
+
// (async () => {
|
|
68
|
+
// const files = await globAsync(pattern);
|
|
69
|
+
// const scripts = [];
|
|
70
|
+
// for (const file of files) {
|
|
71
|
+
// const filename = Path.resolve(file);
|
|
72
|
+
// const script = await load(filename);
|
|
73
|
+
// scripts.push(script);
|
|
74
|
+
// }
|
|
75
|
+
//
|
|
76
|
+
// await run(scripts, defaultReporter);
|
|
77
|
+
// })().catch((e) => console.error(e));
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
type CanBePromise<T> = Promise<T> | T;
|
|
3
|
+
|
|
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
|
+
}
|
|
30
|
+
|
|
31
|
+
type MeasureInitResult = CanBePromise<() => void>;
|
|
32
|
+
|
|
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;
|
|
37
|
+
|
|
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;
|
|
43
|
+
|
|
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,185 +1,118 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createContext } from 'conode';
|
|
2
2
|
import WorkerThreads from 'worker_threads';
|
|
3
|
-
import { Event } from 'evnty';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export class Perform {
|
|
8
|
-
title = '';
|
|
9
|
-
|
|
10
|
-
count = 0;
|
|
11
|
-
|
|
12
|
-
args;
|
|
13
|
-
|
|
14
|
-
constructor(overtake, title, count, args) {
|
|
15
|
-
this.title = title;
|
|
16
|
-
this.count = count;
|
|
17
|
-
this.args = args;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class Measure {
|
|
22
|
-
title = '';
|
|
4
|
+
const overtakeContext = createContext();
|
|
5
|
+
const suiteContext = createContext();
|
|
23
6
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
constructor(overtake, title, init = NOOP) {
|
|
27
|
-
this.title = title;
|
|
28
|
-
this.init = init;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export class Suite {
|
|
33
|
-
title = '';
|
|
34
|
-
|
|
35
|
-
setup = NOOP;
|
|
36
|
-
|
|
37
|
-
measures = [];
|
|
7
|
+
export const NOOP = () => {};
|
|
38
8
|
|
|
39
|
-
|
|
9
|
+
export const setup = (fn) => {
|
|
10
|
+
suiteContext.getContext().setup = fn;
|
|
11
|
+
};
|
|
40
12
|
|
|
41
|
-
|
|
13
|
+
export const teardown = (fn) => {
|
|
14
|
+
suiteContext.getContext().teardown = fn;
|
|
15
|
+
};
|
|
42
16
|
|
|
43
|
-
|
|
17
|
+
export const measure = (title, fn) => {
|
|
18
|
+
suiteContext.getContext().measures.push({ title, init: fn });
|
|
19
|
+
};
|
|
44
20
|
|
|
45
|
-
|
|
21
|
+
export const perform = (title, count, args) => {
|
|
22
|
+
suiteContext.getContext().performs.push({ title, count, args });
|
|
23
|
+
};
|
|
46
24
|
|
|
47
|
-
|
|
25
|
+
export const benchmark = (title, fn) => {
|
|
26
|
+
const setup = NOOP;
|
|
27
|
+
const teardown = NOOP;
|
|
28
|
+
const measures = [];
|
|
29
|
+
const performs = [];
|
|
30
|
+
|
|
31
|
+
overtakeContext.getContext().suites.push({
|
|
32
|
+
title,
|
|
33
|
+
setup,
|
|
34
|
+
teardown,
|
|
35
|
+
measures,
|
|
36
|
+
performs,
|
|
37
|
+
init: fn,
|
|
38
|
+
});
|
|
39
|
+
};
|
|
48
40
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
41
|
+
export const createScript = async (filename, fn) => {
|
|
42
|
+
const suites = [];
|
|
43
|
+
const script = { filename, suites };
|
|
44
|
+
await overtakeContext.contextualize(script, fn);
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.#overtake.onSetupRegister.on((setup) => (this.setup = setup)),
|
|
58
|
-
this.#overtake.onMeasureRegister.on((measure) => this.measures.push(measure)),
|
|
59
|
-
this.#overtake.onPerformRegister.on((perform) => this.performs.push(perform)),
|
|
60
|
-
this.#overtake.onTeardownRegister.on((teardown) => (this.teardown = teardown)),
|
|
61
|
-
];
|
|
62
|
-
await this.#init();
|
|
63
|
-
unsubscribes.forEach((unsubscribe) => unsubscribe());
|
|
64
|
-
}
|
|
65
|
-
}
|
|
46
|
+
return script;
|
|
47
|
+
};
|
|
66
48
|
|
|
67
|
-
export
|
|
68
|
-
|
|
49
|
+
export const load = async (filename) => {
|
|
50
|
+
return createScript(filename, () => import(filename));
|
|
51
|
+
};
|
|
69
52
|
|
|
70
|
-
|
|
53
|
+
const map = {
|
|
54
|
+
script: '⭐ Script ',
|
|
55
|
+
suite: '⇶ Suite ',
|
|
56
|
+
perform: '➤ Perform ',
|
|
57
|
+
measure: '✓ Measure',
|
|
58
|
+
};
|
|
71
59
|
|
|
72
|
-
|
|
60
|
+
export const defaultReporter = async (type, title, test) => {
|
|
61
|
+
console.group(`${map[type]} ${title}`);
|
|
62
|
+
await test({ test: defaultReporter, output: (report) => console.table(report) });
|
|
63
|
+
console.groupEnd();
|
|
64
|
+
};
|
|
73
65
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
const ACCURACY = 6;
|
|
67
|
+
export function formatFloat(value, digits = ACCURACY) {
|
|
68
|
+
return parseFloat(value.toFixed(digits));
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
export
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
onRun = new Event();
|
|
83
|
-
|
|
84
|
-
onComplete = new Event();
|
|
85
|
-
|
|
86
|
-
onScriptRegister = new Event();
|
|
87
|
-
|
|
88
|
-
onScriptStart = new Event();
|
|
89
|
-
|
|
90
|
-
onScriptComplete = new Event();
|
|
91
|
-
|
|
92
|
-
onSuiteRegister = new Event();
|
|
93
|
-
|
|
94
|
-
onSuiteStart = new Event();
|
|
95
|
-
|
|
96
|
-
onSuiteComplete = new Event();
|
|
97
|
-
|
|
98
|
-
onSetupRegister = new Event();
|
|
99
|
-
|
|
100
|
-
onTeardownRegister = new Event();
|
|
101
|
-
|
|
102
|
-
onMeasureRegister = new Event();
|
|
103
|
-
|
|
104
|
-
onMeasureStart = new Event();
|
|
105
|
-
|
|
106
|
-
onMeasureComplete = new Event();
|
|
107
|
-
|
|
108
|
-
onPerformRegister = new Event();
|
|
109
|
-
|
|
110
|
-
onPerformStart = new Event();
|
|
111
|
-
|
|
112
|
-
onPerformProgress = new Event();
|
|
113
|
-
|
|
114
|
-
onPerformComplete = new Event();
|
|
115
|
-
|
|
116
|
-
onReport = new Event();
|
|
117
|
-
|
|
118
|
-
scripts = [];
|
|
119
|
-
|
|
120
|
-
reporters = [];
|
|
121
|
-
|
|
122
|
-
constructor(options = {}) {
|
|
123
|
-
Object.assign(globalThis, {
|
|
124
|
-
benchmark: (title, init) => this.onSuiteRegister(new Suite(this, title, init)),
|
|
125
|
-
setup: (init) => this.onSetupRegister(init),
|
|
126
|
-
teardown: (init) => this.onTeardownRegister(init),
|
|
127
|
-
measure: (title, init) => this.onMeasureRegister(new Measure(this, title, init)),
|
|
128
|
-
perform: (title, count, args) => this.onPerformRegister(new Perform(this, title, count, args)),
|
|
129
|
-
reporter: (reporter) => this.reporters.push(reporter(this)),
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async load(files) {
|
|
134
|
-
this.onLoad(this);
|
|
135
|
-
for (const file of files) {
|
|
136
|
-
const filename = Path.resolve(file);
|
|
137
|
-
const script = new Script(filename);
|
|
138
|
-
const unsubscribe = this.onSuiteRegister.on((suite) => {
|
|
139
|
-
script.suites.push(suite);
|
|
140
|
-
});
|
|
141
|
-
await import(filename);
|
|
142
|
-
unsubscribe();
|
|
143
|
-
this.scripts.push(script);
|
|
144
|
-
this.onScriptRegister(script);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async run() {
|
|
149
|
-
this.onRun();
|
|
150
|
-
for (const script of this.scripts) {
|
|
151
|
-
this.onScriptStart(script);
|
|
71
|
+
export const run = async (scripts, reporter) => {
|
|
72
|
+
for (const script of scripts) {
|
|
73
|
+
await reporter('script', script.filename, async (scriptTest) => {
|
|
152
74
|
for (const suite of script.suites) {
|
|
153
|
-
await
|
|
154
|
-
|
|
155
|
-
for (const measure of suite.measures) {
|
|
156
|
-
this.onMeasureStart(measure);
|
|
75
|
+
await scriptTest.test('suite', suite.title, async (suiteTest) => {
|
|
76
|
+
await suiteContext.contextualize(suite, suite.init);
|
|
157
77
|
for (const perform of suite.performs) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
78
|
+
await suiteTest.test('perform', perform.title, async (performTest) => {
|
|
79
|
+
for (const measure of suite.measures) {
|
|
80
|
+
await performTest.test('measure', measure.title, async (measureTest) => {
|
|
81
|
+
const result = await runWorker({
|
|
82
|
+
setup: suite.setup,
|
|
83
|
+
teardown: suite.teardown,
|
|
84
|
+
init: measure.init,
|
|
85
|
+
count: perform.count,
|
|
86
|
+
args: perform.args,
|
|
87
|
+
});
|
|
88
|
+
if (result.success) {
|
|
89
|
+
measureTest.output({
|
|
90
|
+
[formatFloat(result.mode)]: {
|
|
91
|
+
total: formatFloat(result.total),
|
|
92
|
+
med: formatFloat(result.med),
|
|
93
|
+
p95: formatFloat(result.p95),
|
|
94
|
+
p99: formatFloat(result.p99),
|
|
95
|
+
count: result.count,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
measureTest.output({
|
|
100
|
+
error: {
|
|
101
|
+
reason: result.error,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
171
108
|
}
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
this.onSuiteComplete(perform);
|
|
109
|
+
});
|
|
175
110
|
}
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
this.onComplete(this);
|
|
111
|
+
});
|
|
179
112
|
}
|
|
180
|
-
}
|
|
113
|
+
};
|
|
181
114
|
|
|
182
|
-
export async function runWorker({ args, count, ...options }, onProgress) {
|
|
115
|
+
export async function runWorker({ args, count, ...options }, onProgress = null) {
|
|
183
116
|
const setupCode = options.setup.toString();
|
|
184
117
|
const teardownCode = options.teardown.toString();
|
|
185
118
|
const initCode = options.init.toString();
|
|
@@ -194,7 +127,7 @@ export async function runWorker({ args, count, ...options }, onProgress) {
|
|
|
194
127
|
const worker = new WorkerThreads.Worker(new URL('runner.js', import.meta.url), { argv: [params] });
|
|
195
128
|
return new Promise((resolve) => {
|
|
196
129
|
worker.on('message', (data) => {
|
|
197
|
-
if (data.type === 'progress') {
|
|
130
|
+
if (onProgress && data.type === 'progress') {
|
|
198
131
|
onProgress(data);
|
|
199
132
|
} else if (data.type === 'report') {
|
|
200
133
|
resolve(data);
|
|
@@ -213,8 +146,8 @@ export async function start(input) {
|
|
|
213
146
|
const setup = Function(`return ${setupCode};`)();
|
|
214
147
|
const teardown = Function(`return ${teardownCode};`)();
|
|
215
148
|
const init = Function(`return ${initCode};`)();
|
|
149
|
+
const initArgsSize = init.length;
|
|
216
150
|
const send = WorkerThreads.parentPort ? (data) => WorkerThreads.parentPort.postMessage(data) : (data) => console.log(data);
|
|
217
|
-
|
|
218
151
|
let i = count;
|
|
219
152
|
let done = FALSE_START;
|
|
220
153
|
|
|
@@ -226,11 +159,14 @@ export async function start(input) {
|
|
|
226
159
|
const context = await setup();
|
|
227
160
|
const setupMark = performance.now();
|
|
228
161
|
|
|
229
|
-
const initArgs = [
|
|
230
|
-
if (
|
|
162
|
+
const initArgs = [];
|
|
163
|
+
if (initArgsSize !== 0) {
|
|
164
|
+
initArgs.push(() => done());
|
|
165
|
+
}
|
|
166
|
+
if (initArgsSize > 2) {
|
|
231
167
|
initArgs.unshift(args);
|
|
232
168
|
}
|
|
233
|
-
if (
|
|
169
|
+
if (initArgsSize > 1) {
|
|
234
170
|
initArgs.unshift(context);
|
|
235
171
|
}
|
|
236
172
|
|
|
@@ -261,6 +197,9 @@ export async function start(input) {
|
|
|
261
197
|
|
|
262
198
|
const startTickTime = performance.now();
|
|
263
199
|
action(...args[argIdx], idx);
|
|
200
|
+
if (!initArgsSize) {
|
|
201
|
+
done();
|
|
202
|
+
}
|
|
264
203
|
};
|
|
265
204
|
const cyclesMark = performance.now();
|
|
266
205
|
|
|
@@ -294,14 +233,7 @@ export async function start(input) {
|
|
|
294
233
|
});
|
|
295
234
|
buckets.sort((a, b) => a[1] - b[1]);
|
|
296
235
|
|
|
297
|
-
const
|
|
298
|
-
const med = timings[medIdx];
|
|
299
|
-
const p90Idx = Math.trunc((90 * timings.length) / 100);
|
|
300
|
-
const p90 = timings[p90Idx];
|
|
301
|
-
const p95Idx = Math.trunc((95 * timings.length) / 100);
|
|
302
|
-
const p95 = timings[p95Idx];
|
|
303
|
-
const p99Idx = Math.trunc((99 * timings.length) / 100);
|
|
304
|
-
const p99 = timings[p99Idx];
|
|
236
|
+
const percentile = (p) => timings[Math.trunc((p * timings.length) / 100)];
|
|
305
237
|
const mode = buckets[buckets.length - 1][0];
|
|
306
238
|
|
|
307
239
|
send({
|
|
@@ -312,11 +244,19 @@ export async function start(input) {
|
|
|
312
244
|
max,
|
|
313
245
|
sum,
|
|
314
246
|
avg,
|
|
315
|
-
med,
|
|
316
247
|
mode,
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
248
|
+
p1: percentile(1),
|
|
249
|
+
p5: percentile(5),
|
|
250
|
+
p10: percentile(10),
|
|
251
|
+
p20: percentile(20),
|
|
252
|
+
p33: percentile(33),
|
|
253
|
+
p50: percentile(50),
|
|
254
|
+
med: percentile(50),
|
|
255
|
+
p66: percentile(66),
|
|
256
|
+
p80: percentile(80),
|
|
257
|
+
p90: percentile(90),
|
|
258
|
+
p95: percentile(95),
|
|
259
|
+
p99: percentile(99),
|
|
320
260
|
setup: setupMark - startMark,
|
|
321
261
|
init: initDoneMark - initMark,
|
|
322
262
|
cycles: teardownMark - cyclesMark,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overtake",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "NodeJS performance benchmark",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"overtake": "cli.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"start": "node ./cli.js",
|
|
12
|
+
"start": "node --no-warnings ./cli.js",
|
|
13
13
|
"test": "yarn node --experimental-vm-modules $(yarn bin jest) --detectOpenHandles",
|
|
14
14
|
"lint": "eslint .",
|
|
15
15
|
"prepare": "husky install"
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"pretty-quick": "^3.1.3"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"
|
|
42
|
+
"commander": "^9.2.0",
|
|
43
|
+
"conode": "^0.1.0",
|
|
43
44
|
"glob": "^8.0.1"
|
|
44
45
|
}
|
|
45
46
|
}
|
package/reporter.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏', '⠿'];
|
|
2
|
-
const SPINNER_INTERVAL = 100;
|
|
3
|
-
const SPINNER_PADDING = 5;
|
|
4
|
-
|
|
5
|
-
const ACCURACY = 6;
|
|
6
|
-
|
|
7
|
-
/** TODO
|
|
8
|
-
* [PROGRESS] script/file.js
|
|
9
|
-
* Test suite title
|
|
10
|
-
* ➤ Measure
|
|
11
|
-
* ✓ Perform
|
|
12
|
-
* ✕ Perform
|
|
13
|
-
* */
|
|
14
|
-
|
|
15
|
-
const renderString = (message, x, direction) => {
|
|
16
|
-
const size = message.length;
|
|
17
|
-
process.stdout.moveCursor(0, -1);
|
|
18
|
-
process.stdout.cursorTo(x);
|
|
19
|
-
process.stdout.clearLine(direction);
|
|
20
|
-
if (direction === -1) {
|
|
21
|
-
process.stdout.cursorTo(0);
|
|
22
|
-
}
|
|
23
|
-
process.stdout.write(message);
|
|
24
|
-
process.stdout.moveCursor(-process.stdout.rows, 1);
|
|
25
|
-
|
|
26
|
-
return size;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const renderSpinner = (index) => renderString(SPINNER[index], 0, -1);
|
|
30
|
-
|
|
31
|
-
const paddings = [];
|
|
32
|
-
|
|
33
|
-
const renderMessage = (column, message) => {
|
|
34
|
-
const padding = SPINNER_PADDING + column * 10;
|
|
35
|
-
paddings[column + 1] = renderString(message, padding, 1);
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export function formatFloat(value, digits = ACCURACY) {
|
|
39
|
-
return parseFloat(value.toFixed(digits));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function defaultReporter(overtake) {
|
|
43
|
-
const spinnerSize = SPINNER.length - 1;
|
|
44
|
-
let i = 0;
|
|
45
|
-
let timerId = null;
|
|
46
|
-
|
|
47
|
-
overtake.onLoad.on(() => {});
|
|
48
|
-
overtake.onRun.on(() => {
|
|
49
|
-
console.log();
|
|
50
|
-
});
|
|
51
|
-
overtake.onComplete.on(() => {});
|
|
52
|
-
overtake.onScriptRegister.on(() => {});
|
|
53
|
-
overtake.onScriptStart.on(() => {});
|
|
54
|
-
overtake.onScriptComplete.on(() => {});
|
|
55
|
-
overtake.onSuiteRegister.on(() => {});
|
|
56
|
-
overtake.onSuiteStart.on(() => {});
|
|
57
|
-
overtake.onSuiteComplete.on(() => {});
|
|
58
|
-
overtake.onSetupRegister.on(() => {});
|
|
59
|
-
overtake.onTeardownRegister.on(() => {});
|
|
60
|
-
overtake.onMeasureRegister.on(() => {});
|
|
61
|
-
overtake.onMeasureStart.on((measure) => {
|
|
62
|
-
console.log(measure.title);
|
|
63
|
-
});
|
|
64
|
-
overtake.onMeasureComplete.on(() => {});
|
|
65
|
-
overtake.onPerformRegister.on(() => {});
|
|
66
|
-
overtake.onPerformStart.on((perform) => {
|
|
67
|
-
console.log(perform.title);
|
|
68
|
-
console.log();
|
|
69
|
-
i = 0;
|
|
70
|
-
timerId = setInterval(() => renderSpinner(i++ % spinnerSize), SPINNER_INTERVAL);
|
|
71
|
-
});
|
|
72
|
-
overtake.onPerformComplete.on(() => {
|
|
73
|
-
clearInterval(timerId);
|
|
74
|
-
renderSpinner(spinnerSize);
|
|
75
|
-
});
|
|
76
|
-
overtake.onPerformProgress.on(({ stage, progress }) => {
|
|
77
|
-
renderMessage(0, stage);
|
|
78
|
-
if (typeof progress !== 'undefined') {
|
|
79
|
-
renderMessage(1, `${(progress * 100).toFixed(0)}%`.padStart(4, ' '));
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
overtake.onReport.on((report) => {
|
|
83
|
-
if (report.success) {
|
|
84
|
-
renderMessage(2, `total:${report.total.toFixed(0)}ms mode:${report.mode.toFixed(ACCURACY)}ms`);
|
|
85
|
-
} else {
|
|
86
|
-
renderMessage(1, report.error);
|
|
87
|
-
}
|
|
88
|
-
console.log();
|
|
89
|
-
});
|
|
90
|
-
}
|