flexi-bench 0.0.0-alpha.4 → 0.2.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/CHANGELOG.md +43 -0
- package/README.md +276 -3
- package/dist/api-types.d.ts +45 -0
- package/dist/api-types.js +35 -0
- package/dist/benchmark-runner.js +5 -5
- package/dist/benchmark.d.ts +2 -1
- package/dist/benchmark.js +160 -141
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/performance-observer.js +7 -20
- package/dist/reporters/benchmark-console-reporter.d.ts +4 -1
- package/dist/reporters/benchmark-console-reporter.js +20 -7
- package/dist/reporters/composite-reporter.d.ts +21 -0
- package/dist/reporters/composite-reporter.js +29 -0
- package/dist/reporters/json-suite-reporter.d.ts +26 -0
- package/dist/reporters/json-suite-reporter.js +38 -0
- package/dist/reporters/markdown-benchmark-reporter.d.ts +13 -1
- package/dist/reporters/markdown-benchmark-reporter.js +154 -18
- package/dist/reporters/markdown-suite-reporter.d.ts +16 -0
- package/dist/reporters/markdown-suite-reporter.js +140 -0
- package/dist/reporters/noop-reporter.js +1 -3
- package/dist/reporters/suite-console-reporter.d.ts +4 -0
- package/dist/reporters/suite-console-reporter.js +24 -8
- package/dist/results.d.ts +41 -2
- package/dist/results.js +63 -6
- package/dist/shared-api.d.ts +3 -1
- package/dist/shared-api.js +10 -6
- package/dist/suite.d.ts +11 -1
- package/dist/suite.js +44 -24
- package/dist/variation.d.ts +62 -0
- package/dist/variation.js +80 -3
- package/package.json +7 -2
package/dist/benchmark.js
CHANGED
|
@@ -1,42 +1,40 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.Benchmark = void 0;
|
|
13
4
|
const benchmark_console_reporter_1 = require("./reporters/benchmark-console-reporter");
|
|
14
5
|
const variation_1 = require("./variation");
|
|
6
|
+
const api_types_1 = require("./api-types");
|
|
15
7
|
const child_process_1 = require("child_process");
|
|
16
8
|
const results_1 = require("./results");
|
|
17
9
|
const performance_observer_1 = require("./performance-observer");
|
|
18
10
|
const shared_api_1 = require("./shared-api");
|
|
19
11
|
class Benchmark extends shared_api_1.BenchmarkBase {
|
|
12
|
+
name;
|
|
13
|
+
variations = [];
|
|
14
|
+
iterations;
|
|
15
|
+
timeout;
|
|
16
|
+
reporter;
|
|
17
|
+
watcher;
|
|
18
|
+
errorStrategy = api_types_1.ErrorStrategy.Continue;
|
|
20
19
|
constructor(name, options) {
|
|
21
20
|
super();
|
|
22
21
|
this.name = name;
|
|
23
|
-
|
|
24
|
-
if (options === null || options === void 0 ? void 0 : options.action) {
|
|
22
|
+
if (options?.action) {
|
|
25
23
|
this.action = options.action;
|
|
26
24
|
}
|
|
27
|
-
if (options
|
|
25
|
+
if (options?.setup) {
|
|
28
26
|
this.setupMethods.push(options.setup);
|
|
29
27
|
}
|
|
30
|
-
if (options
|
|
28
|
+
if (options?.teardown) {
|
|
31
29
|
this.teardownMethods.push(options.teardown);
|
|
32
30
|
}
|
|
33
|
-
if (options
|
|
31
|
+
if (options?.iterations) {
|
|
34
32
|
this.iterations = options.iterations;
|
|
35
33
|
}
|
|
36
|
-
if (options
|
|
34
|
+
if (options?.timeout) {
|
|
37
35
|
this.timeout = options.timeout;
|
|
38
36
|
}
|
|
39
|
-
this.reporter =
|
|
37
|
+
this.reporter = options?.reporter || new benchmark_console_reporter_1.BenchmarkConsoleReporter();
|
|
40
38
|
}
|
|
41
39
|
withVariation(nameOrVariation, builder) {
|
|
42
40
|
if (nameOrVariation instanceof variation_1.Variation) {
|
|
@@ -83,117 +81,129 @@ class Benchmark extends shared_api_1.BenchmarkBase {
|
|
|
83
81
|
this.watcher = new performance_observer_1.PerformanceWatcher(options);
|
|
84
82
|
return this;
|
|
85
83
|
}
|
|
86
|
-
run() {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
async run() {
|
|
85
|
+
this.validate();
|
|
86
|
+
let results = [];
|
|
87
|
+
if (this.variations.length === 0) {
|
|
88
|
+
this.variations.push(new variation_1.Variation('default'));
|
|
89
|
+
}
|
|
90
|
+
const totalIterations = this.iterations
|
|
91
|
+
? this.variations.length * this.iterations
|
|
92
|
+
: undefined;
|
|
93
|
+
const startTime = performance.now();
|
|
94
|
+
let totalCompletedIterations = 0;
|
|
95
|
+
for (let variationIndex = 0; variationIndex < this.variations.length; variationIndex++) {
|
|
96
|
+
const variation = this.variations[variationIndex];
|
|
97
|
+
const variationStartTime = performance.now();
|
|
98
|
+
const iterationResults = [];
|
|
99
|
+
// SETUP
|
|
100
|
+
const oldEnv = { ...process.env };
|
|
101
|
+
process.env = {
|
|
102
|
+
...process.env,
|
|
103
|
+
...variation.environment,
|
|
104
|
+
};
|
|
105
|
+
for (const setup of this.setupMethods) {
|
|
106
|
+
await setup(variation);
|
|
93
107
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
for (const setup of variation.setupMethods) {
|
|
109
|
-
yield setup(variation);
|
|
110
|
-
}
|
|
111
|
-
// ACT
|
|
112
|
-
const benchmarkThis = this;
|
|
113
|
-
yield new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
114
|
-
let completedIterations = 0;
|
|
115
|
-
let timeout = benchmarkThis.timeout
|
|
116
|
-
? setTimeout(() => {
|
|
117
|
-
running = false;
|
|
118
|
-
if ((benchmarkThis === null || benchmarkThis === void 0 ? void 0 : benchmarkThis.iterations) &&
|
|
119
|
-
completedIterations < benchmarkThis.iterations) {
|
|
120
|
-
reject('Timeout');
|
|
121
|
-
}
|
|
122
|
-
resolve();
|
|
123
|
-
}, benchmarkThis.timeout)
|
|
124
|
-
: null;
|
|
125
|
-
let running = true;
|
|
126
|
-
while (running) {
|
|
127
|
-
for (const setup of this.setupEachMethods.concat(variation.setupEachMethods)) {
|
|
128
|
-
yield setup(variation);
|
|
129
|
-
}
|
|
130
|
-
const a = performance.now();
|
|
131
|
-
if (variation.action) {
|
|
132
|
-
yield runAction(variation.action, variation);
|
|
133
|
-
}
|
|
134
|
-
else if (this.action) {
|
|
135
|
-
yield runAction(this.action, variation);
|
|
136
|
-
}
|
|
137
|
-
const b = performance.now();
|
|
138
|
-
for (const teardown of this.teardownEachMethods.concat(variation.teardownEachMethods)) {
|
|
139
|
-
yield teardown(variation);
|
|
140
|
-
}
|
|
141
|
-
const duration = b - a;
|
|
142
|
-
completedIterations++;
|
|
143
|
-
totalCompletedIterations++;
|
|
144
|
-
timings.push(duration);
|
|
145
|
-
if (this.reporter.progress &&
|
|
146
|
-
totalIterations &&
|
|
147
|
-
benchmarkThis.iterations) {
|
|
148
|
-
this.reporter.progress(variation.name, totalCompletedIterations / totalIterations, {
|
|
149
|
-
timeElapsed: performance.now() - startTime,
|
|
150
|
-
totalIterations,
|
|
151
|
-
completedIterations: totalCompletedIterations,
|
|
152
|
-
timeout: benchmarkThis.timeout,
|
|
153
|
-
});
|
|
108
|
+
for (const setup of variation.setupMethods) {
|
|
109
|
+
await setup(variation);
|
|
110
|
+
}
|
|
111
|
+
// ACT
|
|
112
|
+
const benchmarkThis = this;
|
|
113
|
+
await new Promise(async (resolve, reject) => {
|
|
114
|
+
let completedIterations = 0;
|
|
115
|
+
let timeout = benchmarkThis.timeout
|
|
116
|
+
? setTimeout(() => {
|
|
117
|
+
running = false;
|
|
118
|
+
if (benchmarkThis?.iterations &&
|
|
119
|
+
completedIterations < benchmarkThis.iterations) {
|
|
120
|
+
reject('Timeout');
|
|
154
121
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
122
|
+
resolve();
|
|
123
|
+
}, benchmarkThis.timeout)
|
|
124
|
+
: null;
|
|
125
|
+
let running = true;
|
|
126
|
+
while (running) {
|
|
127
|
+
for (const setup of this.setupEachMethods.concat(variation.setupEachMethods)) {
|
|
128
|
+
await setup(variation);
|
|
129
|
+
}
|
|
130
|
+
const result = await runAndMeasureAction(benchmarkThis, variation);
|
|
131
|
+
const errorStrategy = variation.errorStrategy ?? benchmarkThis.errorStrategy;
|
|
132
|
+
if (errorStrategy === api_types_1.ErrorStrategy.Abort &&
|
|
133
|
+
result instanceof Error) {
|
|
134
|
+
reject(result);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
for (const teardown of this.teardownEachMethods.concat(variation.teardownEachMethods)) {
|
|
138
|
+
await teardown(variation);
|
|
139
|
+
}
|
|
140
|
+
completedIterations++;
|
|
141
|
+
totalCompletedIterations++;
|
|
142
|
+
iterationResults.push(result);
|
|
143
|
+
if (this.reporter.progress &&
|
|
144
|
+
totalIterations &&
|
|
145
|
+
benchmarkThis.iterations) {
|
|
146
|
+
this.reporter.progress(variation.name, totalCompletedIterations / totalIterations, {
|
|
147
|
+
timeElapsed: performance.now() - startTime,
|
|
148
|
+
totalIterations,
|
|
149
|
+
completedIterations: totalCompletedIterations,
|
|
150
|
+
timeout: benchmarkThis.timeout,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (benchmarkThis?.iterations &&
|
|
154
|
+
completedIterations >= benchmarkThis.iterations) {
|
|
155
|
+
running = false;
|
|
156
|
+
if (timeout) {
|
|
157
|
+
clearTimeout(timeout);
|
|
162
158
|
}
|
|
159
|
+
resolve();
|
|
163
160
|
}
|
|
164
|
-
}));
|
|
165
|
-
if (this.reporter.progress && !totalIterations) {
|
|
166
|
-
this.reporter.progress(variation.name, variationIndex / this.variations.length, {
|
|
167
|
-
timeElapsed: performance.now() - startTime,
|
|
168
|
-
timeout: this.timeout,
|
|
169
|
-
completedIterations: totalCompletedIterations,
|
|
170
|
-
});
|
|
171
161
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
162
|
+
});
|
|
163
|
+
if (this.reporter.progress && !totalIterations) {
|
|
164
|
+
this.reporter.progress(variation.name, variationIndex / this.variations.length, {
|
|
165
|
+
timeElapsed: performance.now() - startTime,
|
|
166
|
+
timeout: this.timeout,
|
|
167
|
+
completedIterations: totalCompletedIterations,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// TEARDOWN
|
|
171
|
+
for (const teardown of variation.teardownMethods) {
|
|
172
|
+
await teardown(variation);
|
|
173
|
+
}
|
|
174
|
+
for (const teardown of this.teardownMethods) {
|
|
175
|
+
await teardown(variation);
|
|
176
|
+
}
|
|
177
|
+
process.env = oldEnv;
|
|
178
|
+
// REPORT
|
|
179
|
+
const variationEndTime = performance.now();
|
|
180
|
+
const result = (0, results_1.calculateResultsFromDurations)(variation.name, iterationResults, {
|
|
181
|
+
iterations: iterationResults.length,
|
|
182
|
+
totalDuration: variationEndTime - variationStartTime,
|
|
183
|
+
benchmarkName: this.name,
|
|
184
|
+
variationName: variation.name,
|
|
185
|
+
});
|
|
186
|
+
// PerformanceObserver needs a chance to flush
|
|
187
|
+
if (this.watcher) {
|
|
188
|
+
const measures = await this.watcher.getMeasures();
|
|
189
|
+
for (const key in measures) {
|
|
190
|
+
result.subresults ??= [];
|
|
191
|
+
result.subresults.push((0, results_1.calculateResultsFromDurations)(key, measures[key], {
|
|
192
|
+
benchmarkName: this.name,
|
|
193
|
+
variationName: variation.name,
|
|
194
|
+
}));
|
|
190
195
|
}
|
|
191
|
-
|
|
196
|
+
this.watcher.clearMeasures();
|
|
192
197
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
results.push(result);
|
|
199
|
+
}
|
|
200
|
+
this.watcher?.disconnect();
|
|
201
|
+
this.reporter.report(this, results);
|
|
202
|
+
if (this.errorStrategy === api_types_1.ErrorStrategy.DelayedThrow &&
|
|
203
|
+
results.some((r) => r.failed)) {
|
|
204
|
+
throw new api_types_1.AggregateBenchmarkError(results);
|
|
205
|
+
}
|
|
206
|
+
return results;
|
|
197
207
|
}
|
|
198
208
|
validate() {
|
|
199
209
|
if (!this.timeout && !this.iterations) {
|
|
@@ -224,26 +234,35 @@ class Benchmark extends shared_api_1.BenchmarkBase {
|
|
|
224
234
|
}
|
|
225
235
|
}
|
|
226
236
|
exports.Benchmark = Benchmark;
|
|
227
|
-
function
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
237
|
+
async function runAndMeasureAction(benchmark, variation) {
|
|
238
|
+
try {
|
|
239
|
+
const a = performance.now();
|
|
240
|
+
await runAction((variation.action ?? benchmark.action), variation);
|
|
241
|
+
const b = performance.now();
|
|
242
|
+
return b - a;
|
|
243
|
+
}
|
|
244
|
+
catch (e) {
|
|
245
|
+
return e instanceof Error ? e : new Error('Unknown error during action.');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async function runAction(action, variation) {
|
|
249
|
+
if (typeof action === 'string') {
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
const child = (0, child_process_1.spawn)(action, variation.cliArgs, {
|
|
252
|
+
shell: true,
|
|
253
|
+
windowsHide: true,
|
|
243
254
|
});
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
255
|
+
child.on('exit', (code) => {
|
|
256
|
+
if (code === 0) {
|
|
257
|
+
resolve();
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
reject(`Action failed with code ${code}`);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
return action(variation);
|
|
267
|
+
}
|
|
249
268
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export * from './reporters/benchmark-console-reporter';
|
|
2
2
|
export * from './reporters/markdown-benchmark-reporter';
|
|
3
|
+
export * from './reporters/markdown-suite-reporter';
|
|
3
4
|
export * from './reporters/suite-console-reporter';
|
|
5
|
+
export * from './reporters/noop-reporter';
|
|
6
|
+
export * from './reporters/composite-reporter';
|
|
7
|
+
export * from './reporters/json-suite-reporter';
|
|
4
8
|
export * from './api-types';
|
|
5
9
|
export * from './benchmark';
|
|
6
10
|
export * from './variation';
|
|
7
11
|
export * from './suite';
|
|
8
12
|
export * from './performance-observer';
|
|
9
13
|
export * from './benchmark-runner';
|
|
14
|
+
export * from './results';
|
package/dist/index.js
CHANGED
|
@@ -16,10 +16,15 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./reporters/benchmark-console-reporter"), exports);
|
|
18
18
|
__exportStar(require("./reporters/markdown-benchmark-reporter"), exports);
|
|
19
|
+
__exportStar(require("./reporters/markdown-suite-reporter"), exports);
|
|
19
20
|
__exportStar(require("./reporters/suite-console-reporter"), exports);
|
|
21
|
+
__exportStar(require("./reporters/noop-reporter"), exports);
|
|
22
|
+
__exportStar(require("./reporters/composite-reporter"), exports);
|
|
23
|
+
__exportStar(require("./reporters/json-suite-reporter"), exports);
|
|
20
24
|
__exportStar(require("./api-types"), exports);
|
|
21
25
|
__exportStar(require("./benchmark"), exports);
|
|
22
26
|
__exportStar(require("./variation"), exports);
|
|
23
27
|
__exportStar(require("./suite"), exports);
|
|
24
28
|
__exportStar(require("./performance-observer"), exports);
|
|
25
29
|
__exportStar(require("./benchmark-runner"), exports);
|
|
30
|
+
__exportStar(require("./results"), exports);
|
|
@@ -1,27 +1,17 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.PerformanceWatcher = void 0;
|
|
13
4
|
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
14
5
|
class PerformanceWatcher {
|
|
6
|
+
observer;
|
|
7
|
+
measures = {};
|
|
15
8
|
constructor(opts = {}) {
|
|
16
|
-
this.measures = {};
|
|
17
9
|
this.observer = new node_perf_hooks_1.PerformanceObserver((list) => {
|
|
18
|
-
var _a;
|
|
19
|
-
var _b;
|
|
20
10
|
for (const entry of list.getEntries()) {
|
|
21
11
|
if (entry.entryType === 'measure' &&
|
|
22
12
|
(!opts.measureFilter || opts.measureFilter(entry))) {
|
|
23
|
-
const label = normalizeLabel(entry.name, opts
|
|
24
|
-
|
|
13
|
+
const label = normalizeLabel(entry.name, opts?.label);
|
|
14
|
+
this.measures[label] ??= [];
|
|
25
15
|
this.measures[label].push(entry.duration);
|
|
26
16
|
}
|
|
27
17
|
}
|
|
@@ -33,10 +23,8 @@ class PerformanceWatcher {
|
|
|
33
23
|
// not fire until the next tick so we need that to happen before the measures are
|
|
34
24
|
// retrieved. Since this method is async, it must be awaited, which actually gives
|
|
35
25
|
// the observer time to collect the measures.
|
|
36
|
-
getMeasures() {
|
|
37
|
-
return
|
|
38
|
-
return this.measures;
|
|
39
|
-
});
|
|
26
|
+
async getMeasures() {
|
|
27
|
+
return this.measures;
|
|
40
28
|
}
|
|
41
29
|
clearMeasures() {
|
|
42
30
|
for (const key in this.measures) {
|
|
@@ -44,8 +32,7 @@ class PerformanceWatcher {
|
|
|
44
32
|
}
|
|
45
33
|
}
|
|
46
34
|
disconnect() {
|
|
47
|
-
|
|
48
|
-
(_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
35
|
+
this.observer?.disconnect();
|
|
49
36
|
delete this.observer;
|
|
50
37
|
}
|
|
51
38
|
}
|
|
@@ -3,8 +3,11 @@ import { Benchmark } from '../benchmark';
|
|
|
3
3
|
import { SingleBar } from 'cli-progress';
|
|
4
4
|
import { Result } from '../results';
|
|
5
5
|
export declare class BenchmarkConsoleReporter implements BenchmarkReporter {
|
|
6
|
+
private noColor;
|
|
6
7
|
bar: SingleBar;
|
|
7
|
-
constructor(
|
|
8
|
+
constructor(opts?: {
|
|
9
|
+
noColor?: boolean;
|
|
10
|
+
});
|
|
8
11
|
progress(name: string, percent: number, context: ProgressContext): void;
|
|
9
12
|
report(benchmark: Benchmark, results: Result[]): void;
|
|
10
13
|
}
|
|
@@ -2,27 +2,40 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BenchmarkConsoleReporter = void 0;
|
|
4
4
|
const cli_progress_1 = require("cli-progress");
|
|
5
|
+
function getNoColorOption(explicitNoColor) {
|
|
6
|
+
if (explicitNoColor !== undefined) {
|
|
7
|
+
return explicitNoColor;
|
|
8
|
+
}
|
|
9
|
+
return process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== '';
|
|
10
|
+
}
|
|
5
11
|
class BenchmarkConsoleReporter {
|
|
6
|
-
|
|
12
|
+
noColor;
|
|
13
|
+
bar;
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
this.noColor = getNoColorOption(opts?.noColor);
|
|
7
16
|
this.bar = new cli_progress_1.SingleBar({
|
|
8
|
-
format:
|
|
9
|
-
|
|
10
|
-
|
|
17
|
+
format: this.noColor
|
|
18
|
+
? 'Running variation {label}: [{bar}] {percentage}% | {value}/{total} - ETA: {eta}s'
|
|
19
|
+
: 'Running variation {label}: {bar} {percentage}% | {value}/{total} - ETA: {eta}s',
|
|
20
|
+
barCompleteChar: this.noColor ? '#' : '\u2588',
|
|
21
|
+
barIncompleteChar: this.noColor ? '-' : '\u2591',
|
|
11
22
|
hideCursor: true,
|
|
12
23
|
stopOnComplete: true,
|
|
13
24
|
clearOnComplete: true,
|
|
14
25
|
});
|
|
15
26
|
}
|
|
16
27
|
progress(name, percent, context) {
|
|
17
|
-
var _a;
|
|
18
28
|
if (!this.bar.isActive) {
|
|
19
|
-
this.bar.start(
|
|
29
|
+
this.bar.start(context.totalIterations ?? 100, 0);
|
|
20
30
|
}
|
|
21
31
|
this.bar.update(context.completedIterations, { label: name });
|
|
22
32
|
}
|
|
23
33
|
report(benchmark, results) {
|
|
34
|
+
const tableEntries = results.map(({ raw, ...rest }) => ({
|
|
35
|
+
...rest,
|
|
36
|
+
}));
|
|
24
37
|
console.log(`Benchmark: ${benchmark.name}`);
|
|
25
|
-
console.table(
|
|
38
|
+
console.table(tableEntries);
|
|
26
39
|
}
|
|
27
40
|
}
|
|
28
41
|
exports.BenchmarkConsoleReporter = BenchmarkConsoleReporter;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { SuiteReporter } from '../api-types';
|
|
2
|
+
import { Result } from '../results';
|
|
3
|
+
/**
|
|
4
|
+
* A reporter that chains multiple suite reporters together.
|
|
5
|
+
* Useful when you want to output results to multiple destinations
|
|
6
|
+
* (e.g., console and file) simultaneously.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* suite.withReporter(new CompositeReporter([
|
|
11
|
+
* new SuiteConsoleReporter(),
|
|
12
|
+
* new MarkdownSuiteReporter({ outputFile: 'results.md' }),
|
|
13
|
+
* new JsonSuiteReporter({ outputFile: 'results.json' }),
|
|
14
|
+
* ]))
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare class CompositeReporter implements SuiteReporter {
|
|
18
|
+
private reporters;
|
|
19
|
+
constructor(reporters: SuiteReporter[]);
|
|
20
|
+
report: (results: Record<string, Result[]>) => void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CompositeReporter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* A reporter that chains multiple suite reporters together.
|
|
6
|
+
* Useful when you want to output results to multiple destinations
|
|
7
|
+
* (e.g., console and file) simultaneously.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* suite.withReporter(new CompositeReporter([
|
|
12
|
+
* new SuiteConsoleReporter(),
|
|
13
|
+
* new MarkdownSuiteReporter({ outputFile: 'results.md' }),
|
|
14
|
+
* new JsonSuiteReporter({ outputFile: 'results.json' }),
|
|
15
|
+
* ]))
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
class CompositeReporter {
|
|
19
|
+
reporters;
|
|
20
|
+
constructor(reporters) {
|
|
21
|
+
this.reporters = reporters;
|
|
22
|
+
}
|
|
23
|
+
report = (results) => {
|
|
24
|
+
for (const reporter of this.reporters) {
|
|
25
|
+
reporter.report(results);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.CompositeReporter = CompositeReporter;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SuiteReporter } from '../api-types';
|
|
2
|
+
import { Result } from '../results';
|
|
3
|
+
export interface JsonSuiteReporterOptions {
|
|
4
|
+
outputFile: string;
|
|
5
|
+
pretty?: boolean;
|
|
6
|
+
includeMetadata?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A reporter that outputs benchmark results as JSON.
|
|
10
|
+
* Useful for CI/CD integration and programmatic analysis.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* suite.withReporter(new JsonSuiteReporter({
|
|
15
|
+
* outputFile: 'results.json',
|
|
16
|
+
* pretty: true,
|
|
17
|
+
* }))
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class JsonSuiteReporter implements SuiteReporter {
|
|
21
|
+
private outputFile;
|
|
22
|
+
private pretty;
|
|
23
|
+
private includeMetadata;
|
|
24
|
+
constructor(opts: JsonSuiteReporterOptions);
|
|
25
|
+
report: (results: Record<string, Result[]>) => void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JsonSuiteReporter = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
/**
|
|
6
|
+
* A reporter that outputs benchmark results as JSON.
|
|
7
|
+
* Useful for CI/CD integration and programmatic analysis.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* suite.withReporter(new JsonSuiteReporter({
|
|
12
|
+
* outputFile: 'results.json',
|
|
13
|
+
* pretty: true,
|
|
14
|
+
* }))
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
class JsonSuiteReporter {
|
|
18
|
+
outputFile;
|
|
19
|
+
pretty;
|
|
20
|
+
includeMetadata;
|
|
21
|
+
constructor(opts) {
|
|
22
|
+
this.outputFile = opts.outputFile;
|
|
23
|
+
this.pretty = opts.pretty ?? false;
|
|
24
|
+
this.includeMetadata = opts.includeMetadata ?? true;
|
|
25
|
+
}
|
|
26
|
+
report = (results) => {
|
|
27
|
+
const output = this.includeMetadata
|
|
28
|
+
? {
|
|
29
|
+
timestamp: new Date().toISOString(),
|
|
30
|
+
platform: process.platform,
|
|
31
|
+
nodeVersion: process.version,
|
|
32
|
+
results,
|
|
33
|
+
}
|
|
34
|
+
: results;
|
|
35
|
+
(0, fs_1.writeFileSync)(this.outputFile, JSON.stringify(output, null, this.pretty ? 2 : undefined));
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
exports.JsonSuiteReporter = JsonSuiteReporter;
|
|
@@ -3,10 +3,22 @@ import { Benchmark } from '../benchmark';
|
|
|
3
3
|
import { Result } from '../results';
|
|
4
4
|
export declare class MarkdownBenchmarkReporter implements BenchmarkReporter {
|
|
5
5
|
outputFile: string;
|
|
6
|
-
fields: Array<keyof Omit<Result, 'subresults' | 'label'>>;
|
|
6
|
+
fields: Array<keyof Omit<Result, 'subresults' | 'label' | 'raw'>>;
|
|
7
|
+
append: boolean;
|
|
8
|
+
private isFirstReport;
|
|
9
|
+
private accumulatedResults;
|
|
7
10
|
constructor(opts: {
|
|
8
11
|
outputFile: string;
|
|
9
12
|
fields?: MarkdownBenchmarkReporter['fields'];
|
|
13
|
+
append?: boolean;
|
|
10
14
|
});
|
|
15
|
+
private formatDuration;
|
|
11
16
|
report: (benchmark: Benchmark, results: Result[]) => void;
|
|
17
|
+
private generateBenchmarkContent;
|
|
18
|
+
private generateResultsTable;
|
|
19
|
+
private generateComparison;
|
|
20
|
+
/**
|
|
21
|
+
* Clears the output file. Useful when re-running benchmarks.
|
|
22
|
+
*/
|
|
23
|
+
clear(): void;
|
|
12
24
|
}
|