flexi-bench 0.0.0-alpha.2 → 0.0.0-alpha.4
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/CHANGELOG.md +19 -0
- package/README.md +373 -0
- package/dist/api-types.d.ts +7 -8
- package/dist/benchmark-runner.d.ts +79 -0
- package/dist/benchmark-runner.js +172 -0
- package/dist/benchmark.d.ts +15 -15
- package/dist/benchmark.js +82 -22
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/performance-observer.d.ts +12 -0
- package/dist/performance-observer.js +60 -0
- package/dist/reporters/benchmark-console-reporter.d.ts +10 -0
- package/dist/{console-reporter.js → reporters/benchmark-console-reporter.js} +6 -9
- package/dist/reporters/markdown-benchmark-reporter.d.ts +12 -0
- package/dist/reporters/markdown-benchmark-reporter.js +29 -0
- package/dist/reporters/noop-reporter.d.ts +4 -0
- package/dist/reporters/noop-reporter.js +9 -0
- package/dist/reporters/suite-console-reporter.d.ts +5 -0
- package/dist/reporters/suite-console-reporter.js +15 -0
- package/dist/results.d.ts +34 -0
- package/dist/results.js +14 -0
- package/dist/shared-api.d.ts +13 -0
- package/dist/shared-api.js +32 -0
- package/dist/suite.d.ts +21 -0
- package/dist/suite.js +58 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +14 -0
- package/dist/variation.d.ts +22 -8
- package/dist/variation.js +33 -13
- package/package.json +23 -9
- package/dist/console-reporter.d.ts +0 -8
package/dist/benchmark.d.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { Variation } from './variation';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
export declare class Benchmark {
|
|
2
|
+
import { TeardownMethod, SetupMethod, Action, BenchmarkReporter } from './api-types';
|
|
3
|
+
import { Result } from './results';
|
|
4
|
+
import { PerformanceObserverOptions } from './performance-observer';
|
|
5
|
+
import { BenchmarkBase } from './shared-api';
|
|
6
|
+
export declare class Benchmark extends BenchmarkBase {
|
|
7
7
|
name: string;
|
|
8
|
-
private setupMethods;
|
|
9
|
-
private teardownMethods;
|
|
10
|
-
private action?;
|
|
11
8
|
variations: Variation[];
|
|
12
9
|
private iterations?;
|
|
13
10
|
private timeout?;
|
|
14
11
|
private reporter;
|
|
12
|
+
private watcher?;
|
|
15
13
|
constructor(name: string, options?: {
|
|
16
14
|
setup?: SetupMethod;
|
|
17
15
|
teardown?: TeardownMethod;
|
|
18
|
-
action?:
|
|
16
|
+
action?: Action;
|
|
19
17
|
iterations?: number;
|
|
20
18
|
timeout?: number;
|
|
21
|
-
reporter?:
|
|
19
|
+
reporter?: BenchmarkReporter;
|
|
22
20
|
});
|
|
23
21
|
withVariation(name: string, builder: (variation: Variation) => Variation): this;
|
|
22
|
+
withVariation(variation: Variation): this;
|
|
24
23
|
withVariations(variations: Variation[]): this;
|
|
25
|
-
withSetup(setup:
|
|
26
|
-
withTeardown(teardown:
|
|
27
|
-
withAction(action:
|
|
24
|
+
withSetup(setup: SetupMethod): this;
|
|
25
|
+
withTeardown(teardown: TeardownMethod): this;
|
|
26
|
+
withAction(action: Action): this;
|
|
28
27
|
withIterations(iterations: number): this;
|
|
29
28
|
withTimeout(timeout: number): this;
|
|
30
|
-
withReporter(reporter:
|
|
31
|
-
|
|
29
|
+
withReporter(reporter: BenchmarkReporter): this;
|
|
30
|
+
withPerformanceObserver(options?: PerformanceObserverOptions): this;
|
|
31
|
+
run(): Promise<Result[]>;
|
|
32
32
|
private validate;
|
|
33
33
|
}
|
package/dist/benchmark.js
CHANGED
|
@@ -10,13 +10,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.Benchmark = void 0;
|
|
13
|
-
const
|
|
13
|
+
const benchmark_console_reporter_1 = require("./reporters/benchmark-console-reporter");
|
|
14
14
|
const variation_1 = require("./variation");
|
|
15
|
-
|
|
15
|
+
const child_process_1 = require("child_process");
|
|
16
|
+
const results_1 = require("./results");
|
|
17
|
+
const performance_observer_1 = require("./performance-observer");
|
|
18
|
+
const shared_api_1 = require("./shared-api");
|
|
19
|
+
class Benchmark extends shared_api_1.BenchmarkBase {
|
|
16
20
|
constructor(name, options) {
|
|
21
|
+
super();
|
|
17
22
|
this.name = name;
|
|
18
|
-
this.setupMethods = [];
|
|
19
|
-
this.teardownMethods = [];
|
|
20
23
|
this.variations = [];
|
|
21
24
|
if (options === null || options === void 0 ? void 0 : options.action) {
|
|
22
25
|
this.action = options.action;
|
|
@@ -33,10 +36,19 @@ class Benchmark {
|
|
|
33
36
|
if (options === null || options === void 0 ? void 0 : options.timeout) {
|
|
34
37
|
this.timeout = options.timeout;
|
|
35
38
|
}
|
|
36
|
-
this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new
|
|
39
|
+
this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new benchmark_console_reporter_1.BenchmarkConsoleReporter();
|
|
37
40
|
}
|
|
38
|
-
withVariation(
|
|
39
|
-
|
|
41
|
+
withVariation(nameOrVariation, builder) {
|
|
42
|
+
if (nameOrVariation instanceof variation_1.Variation) {
|
|
43
|
+
this.variations.push(nameOrVariation);
|
|
44
|
+
}
|
|
45
|
+
else if (builder) {
|
|
46
|
+
this.variations.push(builder(new variation_1.Variation(nameOrVariation)));
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw new Error('`withVariation` must be called with either a Variation or a name and a builder function.');
|
|
51
|
+
}
|
|
40
52
|
return this;
|
|
41
53
|
}
|
|
42
54
|
withVariations(variations) {
|
|
@@ -67,8 +79,13 @@ class Benchmark {
|
|
|
67
79
|
this.reporter = reporter;
|
|
68
80
|
return this;
|
|
69
81
|
}
|
|
82
|
+
withPerformanceObserver(options) {
|
|
83
|
+
this.watcher = new performance_observer_1.PerformanceWatcher(options);
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
70
86
|
run() {
|
|
71
87
|
return __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
var _a, _b;
|
|
72
89
|
this.validate();
|
|
73
90
|
let results = [];
|
|
74
91
|
if (this.variations.length === 0) {
|
|
@@ -107,14 +124,20 @@ class Benchmark {
|
|
|
107
124
|
: null;
|
|
108
125
|
let running = true;
|
|
109
126
|
while (running) {
|
|
127
|
+
for (const setup of this.setupEachMethods.concat(variation.setupEachMethods)) {
|
|
128
|
+
yield setup(variation);
|
|
129
|
+
}
|
|
110
130
|
const a = performance.now();
|
|
111
131
|
if (variation.action) {
|
|
112
|
-
yield variation.action
|
|
132
|
+
yield runAction(variation.action, variation);
|
|
113
133
|
}
|
|
114
134
|
else if (this.action) {
|
|
115
|
-
yield this.action
|
|
135
|
+
yield runAction(this.action, variation);
|
|
116
136
|
}
|
|
117
137
|
const b = performance.now();
|
|
138
|
+
for (const teardown of this.teardownEachMethods.concat(variation.teardownEachMethods)) {
|
|
139
|
+
yield teardown(variation);
|
|
140
|
+
}
|
|
118
141
|
const duration = b - a;
|
|
119
142
|
completedIterations++;
|
|
120
143
|
totalCompletedIterations++;
|
|
@@ -155,24 +178,38 @@ class Benchmark {
|
|
|
155
178
|
}
|
|
156
179
|
process.env = oldEnv;
|
|
157
180
|
// REPORT
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
p95,
|
|
170
|
-
});
|
|
181
|
+
const result = (0, results_1.calculateResultsFromDurations)(variation.name, timings);
|
|
182
|
+
// PerformanceObserver needs a chance to flush
|
|
183
|
+
if (this.watcher) {
|
|
184
|
+
const measures = yield this.watcher.getMeasures();
|
|
185
|
+
for (const key in measures) {
|
|
186
|
+
(_a = result.subresults) !== null && _a !== void 0 ? _a : (result.subresults = []);
|
|
187
|
+
result.subresults.push((0, results_1.calculateResultsFromDurations)(key, measures[key]));
|
|
188
|
+
}
|
|
189
|
+
this.watcher.clearMeasures();
|
|
190
|
+
}
|
|
191
|
+
results.push(result);
|
|
171
192
|
}
|
|
193
|
+
(_b = this.watcher) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
172
194
|
this.reporter.report(this, results);
|
|
195
|
+
return results;
|
|
173
196
|
});
|
|
174
197
|
}
|
|
175
198
|
validate() {
|
|
199
|
+
if (!this.timeout && !this.iterations) {
|
|
200
|
+
this.iterations = 5;
|
|
201
|
+
}
|
|
202
|
+
const missingActions = [];
|
|
203
|
+
for (const variation of this.variations) {
|
|
204
|
+
let action = variation.action || this.action;
|
|
205
|
+
if (!action) {
|
|
206
|
+
missingActions.push(variation.name);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (typeof action !== 'string' && variation.cliArgs.length > 0) {
|
|
210
|
+
throw new Error(`Cannot use CLI args with a non-command action for ${this.name}:${variation.name}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
176
213
|
if (!this.action) {
|
|
177
214
|
const missingActions = this.variations.filter((v) => !v.action);
|
|
178
215
|
if (missingActions.length > 0) {
|
|
@@ -187,3 +224,26 @@ class Benchmark {
|
|
|
187
224
|
}
|
|
188
225
|
}
|
|
189
226
|
exports.Benchmark = Benchmark;
|
|
227
|
+
function runAction(action, variation) {
|
|
228
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
229
|
+
if (typeof action === 'string') {
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
const child = (0, child_process_1.spawn)(action, variation.cliArgs, {
|
|
232
|
+
shell: true,
|
|
233
|
+
windowsHide: true,
|
|
234
|
+
});
|
|
235
|
+
child.on('exit', (code) => {
|
|
236
|
+
if (code === 0) {
|
|
237
|
+
resolve();
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
reject(`Action failed with code ${code}`);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
return action(variation);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
export * from './reporters/benchmark-console-reporter';
|
|
2
|
+
export * from './reporters/markdown-benchmark-reporter';
|
|
3
|
+
export * from './reporters/suite-console-reporter';
|
|
1
4
|
export * from './api-types';
|
|
2
5
|
export * from './benchmark';
|
|
3
6
|
export * from './variation';
|
|
4
|
-
export * from './
|
|
7
|
+
export * from './suite';
|
|
8
|
+
export * from './performance-observer';
|
|
9
|
+
export * from './benchmark-runner';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./reporters/benchmark-console-reporter"), exports);
|
|
18
|
+
__exportStar(require("./reporters/markdown-benchmark-reporter"), exports);
|
|
19
|
+
__exportStar(require("./reporters/suite-console-reporter"), exports);
|
|
17
20
|
__exportStar(require("./api-types"), exports);
|
|
18
21
|
__exportStar(require("./benchmark"), exports);
|
|
19
22
|
__exportStar(require("./variation"), exports);
|
|
20
|
-
__exportStar(require("./
|
|
23
|
+
__exportStar(require("./suite"), exports);
|
|
24
|
+
__exportStar(require("./performance-observer"), exports);
|
|
25
|
+
__exportStar(require("./benchmark-runner"), exports);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class PerformanceWatcher {
|
|
2
|
+
private observer?;
|
|
3
|
+
private measures;
|
|
4
|
+
constructor(opts?: PerformanceObserverOptions);
|
|
5
|
+
getMeasures(): Promise<Record<string, number[]>>;
|
|
6
|
+
clearMeasures(): void;
|
|
7
|
+
disconnect(): void;
|
|
8
|
+
}
|
|
9
|
+
export type PerformanceObserverOptions = {
|
|
10
|
+
measureFilter?: (entry: PerformanceEntry) => boolean;
|
|
11
|
+
label?: Record<string, string> | ((label: string) => string);
|
|
12
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PerformanceWatcher = void 0;
|
|
13
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
14
|
+
class PerformanceWatcher {
|
|
15
|
+
constructor(opts = {}) {
|
|
16
|
+
this.measures = {};
|
|
17
|
+
this.observer = new node_perf_hooks_1.PerformanceObserver((list) => {
|
|
18
|
+
var _a;
|
|
19
|
+
var _b;
|
|
20
|
+
for (const entry of list.getEntries()) {
|
|
21
|
+
if (entry.entryType === 'measure' &&
|
|
22
|
+
(!opts.measureFilter || opts.measureFilter(entry))) {
|
|
23
|
+
const label = normalizeLabel(entry.name, opts === null || opts === void 0 ? void 0 : opts.label);
|
|
24
|
+
(_a = (_b = this.measures)[label]) !== null && _a !== void 0 ? _a : (_b[label] = []);
|
|
25
|
+
this.measures[label].push(entry.duration);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
this.observer.observe({ entryTypes: ['measure'] });
|
|
30
|
+
}
|
|
31
|
+
// This method is async to give the observer time to collect the measures...
|
|
32
|
+
// If the action being ran by the benchmark is synchronous, the observer will
|
|
33
|
+
// not fire until the next tick so we need that to happen before the measures are
|
|
34
|
+
// retrieved. Since this method is async, it must be awaited, which actually gives
|
|
35
|
+
// the observer time to collect the measures.
|
|
36
|
+
getMeasures() {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
return this.measures;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
clearMeasures() {
|
|
42
|
+
for (const key in this.measures) {
|
|
43
|
+
delete this.measures[key];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
disconnect() {
|
|
47
|
+
var _a;
|
|
48
|
+
(_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
49
|
+
delete this.observer;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.PerformanceWatcher = PerformanceWatcher;
|
|
53
|
+
function normalizeLabel(label, transform) {
|
|
54
|
+
if (transform) {
|
|
55
|
+
return typeof transform === 'function'
|
|
56
|
+
? transform(label)
|
|
57
|
+
: transform[label];
|
|
58
|
+
}
|
|
59
|
+
return label;
|
|
60
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BenchmarkReporter, ProgressContext } from '../api-types';
|
|
2
|
+
import { Benchmark } from '../benchmark';
|
|
3
|
+
import { SingleBar } from 'cli-progress';
|
|
4
|
+
import { Result } from '../results';
|
|
5
|
+
export declare class BenchmarkConsoleReporter implements BenchmarkReporter {
|
|
6
|
+
bar: SingleBar;
|
|
7
|
+
constructor();
|
|
8
|
+
progress(name: string, percent: number, context: ProgressContext): void;
|
|
9
|
+
report(benchmark: Benchmark, results: Result[]): void;
|
|
10
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.BenchmarkConsoleReporter = void 0;
|
|
4
4
|
const cli_progress_1 = require("cli-progress");
|
|
5
|
-
class
|
|
5
|
+
class BenchmarkConsoleReporter {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.bar = new cli_progress_1.SingleBar({
|
|
8
|
-
format: 'Running
|
|
8
|
+
format: 'Running variation {label}: {bar} {percentage}% | {value}/{total} - ETA: {eta}s',
|
|
9
9
|
barCompleteChar: '\u2588',
|
|
10
10
|
barIncompleteChar: '\u2591',
|
|
11
11
|
hideCursor: true,
|
|
12
|
+
stopOnComplete: true,
|
|
13
|
+
clearOnComplete: true,
|
|
12
14
|
});
|
|
13
15
|
}
|
|
14
16
|
progress(name, percent, context) {
|
|
@@ -17,15 +19,10 @@ class ConsoleReporter {
|
|
|
17
19
|
this.bar.start((_a = context.totalIterations) !== null && _a !== void 0 ? _a : 100, 0);
|
|
18
20
|
}
|
|
19
21
|
this.bar.update(context.completedIterations, { label: name });
|
|
20
|
-
process.stdout.moveCursor(0, -1);
|
|
21
|
-
// console.log(`Progress: ${name} ${Math.round(percent * 10000) / 100}%`);
|
|
22
22
|
}
|
|
23
23
|
report(benchmark, results) {
|
|
24
|
-
this.bar.stop();
|
|
25
|
-
process.stdout.moveCursor(0, -1);
|
|
26
|
-
process.stdout.clearScreenDown();
|
|
27
24
|
console.log(`Benchmark: ${benchmark.name}`);
|
|
28
25
|
console.table(results);
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
|
-
exports.
|
|
28
|
+
exports.BenchmarkConsoleReporter = BenchmarkConsoleReporter;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BenchmarkReporter } from '../api-types';
|
|
2
|
+
import { Benchmark } from '../benchmark';
|
|
3
|
+
import { Result } from '../results';
|
|
4
|
+
export declare class MarkdownBenchmarkReporter implements BenchmarkReporter {
|
|
5
|
+
outputFile: string;
|
|
6
|
+
fields: Array<keyof Omit<Result, 'subresults' | 'label'>>;
|
|
7
|
+
constructor(opts: {
|
|
8
|
+
outputFile: string;
|
|
9
|
+
fields?: MarkdownBenchmarkReporter['fields'];
|
|
10
|
+
});
|
|
11
|
+
report: (benchmark: Benchmark, results: Result[]) => void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MarkdownBenchmarkReporter = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const markdown_factory_1 = require("markdown-factory");
|
|
6
|
+
class MarkdownBenchmarkReporter {
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
var _a;
|
|
9
|
+
this.report = (benchmark, results) => {
|
|
10
|
+
(0, fs_1.writeFileSync)(this.outputFile, (0, markdown_factory_1.h1)(benchmark.name, results.some((r) => !!r.subresults)
|
|
11
|
+
? (0, markdown_factory_1.lines)(results.map((r) => {
|
|
12
|
+
var _a;
|
|
13
|
+
const entries = [Object.assign(Object.assign({}, r), { label: 'total' })];
|
|
14
|
+
delete entries[0].subresults;
|
|
15
|
+
for (const subresult of (_a = r.subresults) !== null && _a !== void 0 ? _a : []) {
|
|
16
|
+
entries.push(subresult);
|
|
17
|
+
}
|
|
18
|
+
return (0, markdown_factory_1.h2)(r.label, (0, markdown_factory_1.table)(entries, [
|
|
19
|
+
{ field: 'label', label: '' },
|
|
20
|
+
...this.fields,
|
|
21
|
+
]));
|
|
22
|
+
}))
|
|
23
|
+
: (0, markdown_factory_1.table)(results, [{ field: 'label', label: '' }, ...this.fields])));
|
|
24
|
+
};
|
|
25
|
+
this.outputFile = opts.outputFile;
|
|
26
|
+
this.fields = (_a = opts.fields) !== null && _a !== void 0 ? _a : ['min', 'average', 'p95', 'max'];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.MarkdownBenchmarkReporter = MarkdownBenchmarkReporter;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SuiteConsoleReporter = void 0;
|
|
4
|
+
class SuiteConsoleReporter {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.report = (results) => {
|
|
7
|
+
console.log('Suite Results:');
|
|
8
|
+
for (const [name, result] of Object.entries(results)) {
|
|
9
|
+
console.log(`Benchmark: ${name}`);
|
|
10
|
+
console.table(result);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.SuiteConsoleReporter = SuiteConsoleReporter;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A measurement result.
|
|
3
|
+
*/
|
|
4
|
+
export type Result = {
|
|
5
|
+
/**
|
|
6
|
+
* The label of the result. Typically the name of the benchmark or variation.
|
|
7
|
+
*/
|
|
8
|
+
label: string;
|
|
9
|
+
/**
|
|
10
|
+
* The minimum duration.
|
|
11
|
+
*/
|
|
12
|
+
min: number;
|
|
13
|
+
/**
|
|
14
|
+
* The maximum duration.
|
|
15
|
+
*/
|
|
16
|
+
max: number;
|
|
17
|
+
/**
|
|
18
|
+
* The average duration.
|
|
19
|
+
*/
|
|
20
|
+
average: number;
|
|
21
|
+
/**
|
|
22
|
+
* The 95th percentile duration.
|
|
23
|
+
*/
|
|
24
|
+
p95: number;
|
|
25
|
+
/**
|
|
26
|
+
* The raw durations, in order. Used for custom reporters.
|
|
27
|
+
*/
|
|
28
|
+
raw: number[];
|
|
29
|
+
/**
|
|
30
|
+
* Subresults, if any. Typically sourced from performance observer.
|
|
31
|
+
*/
|
|
32
|
+
subresults?: Result[];
|
|
33
|
+
};
|
|
34
|
+
export declare function calculateResultsFromDurations(label: string, durations: number[]): Result;
|
package/dist/results.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateResultsFromDurations = calculateResultsFromDurations;
|
|
4
|
+
function calculateResultsFromDurations(label, durations) {
|
|
5
|
+
durations.sort((a, b) => a - b);
|
|
6
|
+
return {
|
|
7
|
+
label,
|
|
8
|
+
min: Math.min(...durations),
|
|
9
|
+
max: Math.max(...durations),
|
|
10
|
+
average: durations.reduce((acc, duration) => acc + duration, 0) / durations.length,
|
|
11
|
+
p95: durations[Math.floor(durations.length * 0.95)],
|
|
12
|
+
raw: durations,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Action, SetupMethod, TeardownMethod } from './api-types';
|
|
2
|
+
export declare class BenchmarkBase {
|
|
3
|
+
setupEachMethods: SetupMethod[];
|
|
4
|
+
setupMethods: SetupMethod[];
|
|
5
|
+
teardownMethods: TeardownMethod[];
|
|
6
|
+
teardownEachMethods: TeardownMethod[];
|
|
7
|
+
action?: Action;
|
|
8
|
+
withSetup(setup: SetupMethod): this;
|
|
9
|
+
withSetupEach(setup: SetupMethod): this;
|
|
10
|
+
withTeardown(teardown: TeardownMethod): this;
|
|
11
|
+
withTeardownEach(teardown: TeardownMethod): this;
|
|
12
|
+
withAction(action: Action): this;
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BenchmarkBase = void 0;
|
|
4
|
+
class BenchmarkBase {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.setupEachMethods = [];
|
|
7
|
+
this.setupMethods = [];
|
|
8
|
+
this.teardownMethods = [];
|
|
9
|
+
this.teardownEachMethods = [];
|
|
10
|
+
}
|
|
11
|
+
withSetup(setup) {
|
|
12
|
+
this.setupMethods.push(setup);
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
withSetupEach(setup) {
|
|
16
|
+
this.setupEachMethods.push(setup);
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
withTeardown(teardown) {
|
|
20
|
+
this.teardownMethods.push(teardown);
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
withTeardownEach(teardown) {
|
|
24
|
+
this.teardownEachMethods.push(teardown);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
withAction(action) {
|
|
28
|
+
this.action = action;
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.BenchmarkBase = BenchmarkBase;
|
package/dist/suite.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BenchmarkReporter, SuiteReporter } from './api-types';
|
|
2
|
+
import { Benchmark } from './benchmark';
|
|
3
|
+
import { Result } from './results';
|
|
4
|
+
import { Variation } from './variation';
|
|
5
|
+
export interface SuiteOptions {
|
|
6
|
+
reporter?: SuiteReporter;
|
|
7
|
+
}
|
|
8
|
+
export declare class Suite {
|
|
9
|
+
private name;
|
|
10
|
+
private benchmarks;
|
|
11
|
+
private variations;
|
|
12
|
+
private reporter;
|
|
13
|
+
private benchmarkReporter?;
|
|
14
|
+
constructor(name: string, options?: SuiteOptions);
|
|
15
|
+
addBenchmark(benchmark: Benchmark): this;
|
|
16
|
+
withVariation(variation: Variation): this;
|
|
17
|
+
withVariations(variations: Variation[]): this;
|
|
18
|
+
withReporter(reporter: SuiteReporter): this;
|
|
19
|
+
withBenchmarkReporter(reporter: BenchmarkReporter): this;
|
|
20
|
+
run(): Promise<Record<string, Result[]>>;
|
|
21
|
+
}
|
package/dist/suite.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Suite = void 0;
|
|
13
|
+
const suite_console_reporter_1 = require("./reporters/suite-console-reporter");
|
|
14
|
+
class Suite {
|
|
15
|
+
constructor(name, options) {
|
|
16
|
+
this.name = name;
|
|
17
|
+
this.benchmarks = [];
|
|
18
|
+
this.variations = [];
|
|
19
|
+
this.name = name;
|
|
20
|
+
this.benchmarks = [];
|
|
21
|
+
this.reporter = (options === null || options === void 0 ? void 0 : options.reporter) || new suite_console_reporter_1.SuiteConsoleReporter();
|
|
22
|
+
}
|
|
23
|
+
addBenchmark(benchmark) {
|
|
24
|
+
this.benchmarks.push(benchmark);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
withVariation(variation) {
|
|
28
|
+
this.variations.push(variation);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
withVariations(variations) {
|
|
32
|
+
this.variations.push(...variations);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
withReporter(reporter) {
|
|
36
|
+
this.reporter = reporter;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
withBenchmarkReporter(reporter) {
|
|
40
|
+
this.benchmarkReporter = reporter;
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
run() {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
const results = {};
|
|
46
|
+
for (const benchmark of this.benchmarks) {
|
|
47
|
+
benchmark.withVariations(this.variations);
|
|
48
|
+
if (this.benchmarkReporter) {
|
|
49
|
+
benchmark.withReporter(this.benchmarkReporter);
|
|
50
|
+
}
|
|
51
|
+
results[benchmark.name] = yield benchmark.run();
|
|
52
|
+
}
|
|
53
|
+
this.reporter.report(results);
|
|
54
|
+
return results;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.Suite = Suite;
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function findCombinations<T>(variables: T[][]): T[][];
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findCombinations = findCombinations;
|
|
4
|
+
function findCombinations(variables) {
|
|
5
|
+
// Generates all possible combinations of the given variables.
|
|
6
|
+
// e.g. findCombinations([[1, 2], [3, 4]]) => [[1, 3], [1, 4], [2, 3], [2, 4]]
|
|
7
|
+
return variables.reduce((acc, values) => {
|
|
8
|
+
return acc.flatMap((accItem) => {
|
|
9
|
+
return values.map((value) => {
|
|
10
|
+
return [...accItem, value];
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
}, [[]]);
|
|
14
|
+
}
|