flexi-bench 0.0.0-alpha.3 → 0.1.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 +39 -0
- package/README.md +373 -0
- package/dist/api-types.d.ts +28 -7
- package/dist/api-types.js +35 -0
- package/dist/benchmark-runner.d.ts +79 -0
- package/dist/benchmark-runner.js +172 -0
- package/dist/benchmark.d.ts +13 -12
- package/dist/benchmark.js +188 -120
- 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 +47 -0
- package/dist/{benchmark-console-reporter.d.ts → reporters/benchmark-console-reporter.d.ts} +5 -3
- package/dist/reporters/benchmark-console-reporter.js +29 -0
- 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 +7 -0
- package/dist/{suite-console-reporter.d.ts → reporters/suite-console-reporter.d.ts} +2 -1
- package/dist/reporters/suite-console-reporter.js +16 -0
- package/dist/results.d.ts +42 -0
- package/dist/results.js +26 -0
- package/dist/shared-api.d.ts +15 -0
- package/dist/shared-api.js +36 -0
- package/dist/suite.d.ts +18 -4
- package/dist/suite.js +51 -23
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +14 -0
- package/dist/variation.d.ts +22 -8
- package/dist/variation.js +39 -15
- package/package.json +27 -10
- package/dist/benchmark-console-reporter.js +0 -31
- package/dist/console-reporter.d.ts +0 -8
- package/dist/console-reporter.js +0 -31
- package/dist/suite-console-reporter.js +0 -15
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BenchmarkConsoleReporter = void 0;
|
|
4
|
+
const cli_progress_1 = require("cli-progress");
|
|
5
|
+
class BenchmarkConsoleReporter {
|
|
6
|
+
bar = new cli_progress_1.SingleBar({
|
|
7
|
+
format: 'Running variation {label}: {bar} {percentage}% | {value}/{total} - ETA: {eta}s',
|
|
8
|
+
barCompleteChar: '\u2588',
|
|
9
|
+
barIncompleteChar: '\u2591',
|
|
10
|
+
hideCursor: true,
|
|
11
|
+
stopOnComplete: true,
|
|
12
|
+
clearOnComplete: true,
|
|
13
|
+
});
|
|
14
|
+
constructor() { }
|
|
15
|
+
progress(name, percent, context) {
|
|
16
|
+
if (!this.bar.isActive) {
|
|
17
|
+
this.bar.start(context.totalIterations ?? 100, 0);
|
|
18
|
+
}
|
|
19
|
+
this.bar.update(context.completedIterations, { label: name });
|
|
20
|
+
}
|
|
21
|
+
report(benchmark, results) {
|
|
22
|
+
const tableEntries = results.map(({ raw, ...rest }) => ({
|
|
23
|
+
...rest,
|
|
24
|
+
}));
|
|
25
|
+
console.log(`Benchmark: ${benchmark.name}`);
|
|
26
|
+
console.table(tableEntries);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
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
|
+
outputFile;
|
|
8
|
+
fields;
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
this.outputFile = opts.outputFile;
|
|
11
|
+
this.fields = opts.fields ?? ['min', 'average', 'p95', 'max'];
|
|
12
|
+
}
|
|
13
|
+
report = (benchmark, results) => {
|
|
14
|
+
(0, fs_1.writeFileSync)(this.outputFile, (0, markdown_factory_1.h1)(benchmark.name, results.some((r) => !!r.subresults)
|
|
15
|
+
? (0, markdown_factory_1.lines)(results.map((r) => {
|
|
16
|
+
const entries = [{ ...r, label: 'total' }];
|
|
17
|
+
delete entries[0].subresults;
|
|
18
|
+
for (const subresult of r.subresults ?? []) {
|
|
19
|
+
entries.push(subresult);
|
|
20
|
+
}
|
|
21
|
+
return (0, markdown_factory_1.h2)(r.label, (0, markdown_factory_1.table)(entries, [
|
|
22
|
+
{ field: 'label', label: '' },
|
|
23
|
+
...this.fields,
|
|
24
|
+
]));
|
|
25
|
+
}))
|
|
26
|
+
: (0, markdown_factory_1.table)(results, [{ field: 'label', label: '' }, ...this.fields])));
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.MarkdownBenchmarkReporter = MarkdownBenchmarkReporter;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SuiteConsoleReporter = void 0;
|
|
4
|
+
class SuiteConsoleReporter {
|
|
5
|
+
report = (results) => {
|
|
6
|
+
console.log('Suite Results:');
|
|
7
|
+
for (const [name, result] of Object.entries(results)) {
|
|
8
|
+
const tableEntries = result.map(({ raw, ...rest }) => ({
|
|
9
|
+
...rest,
|
|
10
|
+
}));
|
|
11
|
+
console.log(`Benchmark: ${name}`);
|
|
12
|
+
console.table(tableEntries);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
exports.SuiteConsoleReporter = SuiteConsoleReporter;
|
|
@@ -0,0 +1,42 @@
|
|
|
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 | Error)[];
|
|
29
|
+
/**
|
|
30
|
+
* Whether any run of the benchmark failed.
|
|
31
|
+
*/
|
|
32
|
+
failed?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The rate of failure, if any.
|
|
35
|
+
*/
|
|
36
|
+
failureRate?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Subresults, if any. Typically sourced from performance observer.
|
|
39
|
+
*/
|
|
40
|
+
subresults?: Result[];
|
|
41
|
+
};
|
|
42
|
+
export declare function calculateResultsFromDurations(label: string, durations: (number | Error)[]): Result;
|
package/dist/results.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateResultsFromDurations = calculateResultsFromDurations;
|
|
4
|
+
function calculateResultsFromDurations(label, durations) {
|
|
5
|
+
const errors = [];
|
|
6
|
+
const results = [];
|
|
7
|
+
for (const duration of durations) {
|
|
8
|
+
if (duration instanceof Error) {
|
|
9
|
+
errors.push(duration);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
results.push(duration);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
results.sort((a, b) => a - b);
|
|
16
|
+
return {
|
|
17
|
+
label,
|
|
18
|
+
min: Math.min(...results),
|
|
19
|
+
max: Math.max(...results),
|
|
20
|
+
average: results.reduce((acc, duration) => acc + duration, 0) / results.length,
|
|
21
|
+
p95: results[Math.floor(results.length * 0.95)],
|
|
22
|
+
raw: durations,
|
|
23
|
+
failed: errors.length > 0,
|
|
24
|
+
failureRate: errors.length / durations.length,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Action, ErrorStrategy, 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
|
+
errorStrategy?: ErrorStrategy;
|
|
9
|
+
withSetup(setup: SetupMethod): this;
|
|
10
|
+
withSetupEach(setup: SetupMethod): this;
|
|
11
|
+
withTeardown(teardown: TeardownMethod): this;
|
|
12
|
+
withTeardownEach(teardown: TeardownMethod): this;
|
|
13
|
+
withAction(action: Action): this;
|
|
14
|
+
withErrorStrategy(errorStrategy: ErrorStrategy): this;
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BenchmarkBase = void 0;
|
|
4
|
+
class BenchmarkBase {
|
|
5
|
+
setupEachMethods = [];
|
|
6
|
+
setupMethods = [];
|
|
7
|
+
teardownMethods = [];
|
|
8
|
+
teardownEachMethods = [];
|
|
9
|
+
action;
|
|
10
|
+
errorStrategy;
|
|
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
|
+
withErrorStrategy(errorStrategy) {
|
|
32
|
+
this.errorStrategy = errorStrategy;
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.BenchmarkBase = BenchmarkBase;
|
package/dist/suite.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SuiteReporter } from './api-types';
|
|
1
|
+
import { BenchmarkReporter, ErrorStrategy, SuiteReporter } from './api-types';
|
|
2
2
|
import { Benchmark } from './benchmark';
|
|
3
|
+
import { Result } from './results';
|
|
3
4
|
import { Variation } from './variation';
|
|
4
5
|
export interface SuiteOptions {
|
|
5
6
|
reporter?: SuiteReporter;
|
|
@@ -9,9 +10,22 @@ export declare class Suite {
|
|
|
9
10
|
private benchmarks;
|
|
10
11
|
private variations;
|
|
11
12
|
private reporter;
|
|
13
|
+
private benchmarkReporter?;
|
|
14
|
+
private errorStrategy;
|
|
15
|
+
private shouldSetErrorStrategyOnBenchmarks;
|
|
12
16
|
constructor(name: string, options?: SuiteOptions);
|
|
13
17
|
addBenchmark(benchmark: Benchmark): this;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
withVariation(variation: Variation): this;
|
|
19
|
+
withVariations(variations: Variation[]): this;
|
|
20
|
+
withReporter(reporter: SuiteReporter): this;
|
|
21
|
+
withBenchmarkReporter(reporter: BenchmarkReporter): this;
|
|
22
|
+
/**
|
|
23
|
+
* Sets the error strategy for the suite and optionally for the benchmarks.
|
|
24
|
+
* @param errorStrategy Determines what to do when an error occurs during a benchmark run. See {@link ErrorStrategy}
|
|
25
|
+
* @param opts Options for the error strategy. If `shouldSetOnBenchmarks` is true, the error strategy will be set on all benchmarks in the suite.
|
|
26
|
+
*/
|
|
27
|
+
withErrorStrategy(errorStrategy: ErrorStrategy, opts?: {
|
|
28
|
+
shouldSetOnBenchmarks?: boolean;
|
|
29
|
+
}): this;
|
|
30
|
+
run(): Promise<Record<string, Result[]>>;
|
|
17
31
|
}
|
package/dist/suite.js
CHANGED
|
@@ -1,46 +1,74 @@
|
|
|
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.Suite = void 0;
|
|
13
|
-
const
|
|
4
|
+
const api_types_1 = require("./api-types");
|
|
5
|
+
const suite_console_reporter_1 = require("./reporters/suite-console-reporter");
|
|
14
6
|
class Suite {
|
|
7
|
+
name;
|
|
8
|
+
benchmarks = [];
|
|
9
|
+
variations = [];
|
|
10
|
+
reporter;
|
|
11
|
+
benchmarkReporter;
|
|
12
|
+
errorStrategy = api_types_1.ErrorStrategy.Continue;
|
|
13
|
+
shouldSetErrorStrategyOnBenchmarks = false;
|
|
15
14
|
constructor(name, options) {
|
|
16
15
|
this.name = name;
|
|
17
|
-
this.benchmarks = [];
|
|
18
|
-
this.variations = [];
|
|
19
16
|
this.name = name;
|
|
20
17
|
this.benchmarks = [];
|
|
21
|
-
this.reporter =
|
|
18
|
+
this.reporter = options?.reporter || new suite_console_reporter_1.SuiteConsoleReporter();
|
|
22
19
|
}
|
|
23
20
|
addBenchmark(benchmark) {
|
|
24
21
|
this.benchmarks.push(benchmark);
|
|
25
22
|
return this;
|
|
26
23
|
}
|
|
27
|
-
|
|
24
|
+
withVariation(variation) {
|
|
28
25
|
this.variations.push(variation);
|
|
29
26
|
return this;
|
|
30
27
|
}
|
|
31
|
-
|
|
28
|
+
withVariations(variations) {
|
|
32
29
|
this.variations.push(...variations);
|
|
33
30
|
return this;
|
|
34
31
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
withReporter(reporter) {
|
|
33
|
+
this.reporter = reporter;
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
withBenchmarkReporter(reporter) {
|
|
37
|
+
this.benchmarkReporter = reporter;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Sets the error strategy for the suite and optionally for the benchmarks.
|
|
42
|
+
* @param errorStrategy Determines what to do when an error occurs during a benchmark run. See {@link ErrorStrategy}
|
|
43
|
+
* @param opts Options for the error strategy. If `shouldSetOnBenchmarks` is true, the error strategy will be set on all benchmarks in the suite.
|
|
44
|
+
*/
|
|
45
|
+
withErrorStrategy(errorStrategy, opts) {
|
|
46
|
+
this.errorStrategy = errorStrategy;
|
|
47
|
+
if (opts?.shouldSetOnBenchmarks) {
|
|
48
|
+
this.shouldSetErrorStrategyOnBenchmarks = opts?.shouldSetOnBenchmarks;
|
|
49
|
+
}
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
async run() {
|
|
53
|
+
const results = {};
|
|
54
|
+
for (const benchmark of this.benchmarks) {
|
|
55
|
+
benchmark.withVariations(this.variations);
|
|
56
|
+
if (this.benchmarkReporter) {
|
|
57
|
+
benchmark.withReporter(this.benchmarkReporter);
|
|
58
|
+
}
|
|
59
|
+
if (this.shouldSetErrorStrategyOnBenchmarks) {
|
|
60
|
+
benchmark.withErrorStrategy(this.errorStrategy);
|
|
61
|
+
}
|
|
62
|
+
results[benchmark.name] = await benchmark.run();
|
|
63
|
+
}
|
|
64
|
+
this.reporter.report(results);
|
|
65
|
+
if (this.errorStrategy === api_types_1.ErrorStrategy.DelayedThrow) {
|
|
66
|
+
const failedResults = Object.values(results).flatMap((r) => r.filter((r) => r.failed));
|
|
67
|
+
if (failedResults.length > 0) {
|
|
68
|
+
throw new api_types_1.AggregateSuiteError(results);
|
|
41
69
|
}
|
|
42
|
-
|
|
43
|
-
|
|
70
|
+
}
|
|
71
|
+
return results;
|
|
44
72
|
}
|
|
45
73
|
}
|
|
46
74
|
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
|
+
}
|
package/dist/variation.d.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { EnvironmentVariableOptions } from './api-types';
|
|
2
|
+
import { BenchmarkBase } from './shared-api';
|
|
3
|
+
export declare class Variation extends BenchmarkBase {
|
|
3
4
|
name: string;
|
|
4
|
-
setupMethods: SetupMethod[];
|
|
5
|
-
teardownMethods: TeardownMethod[];
|
|
6
5
|
environment: Partial<NodeJS.ProcessEnv>;
|
|
7
|
-
|
|
6
|
+
cliArgs: string[];
|
|
8
7
|
constructor(name: string);
|
|
9
8
|
static FromEnvironmentVariables(variables: EnvironmentVariableOptions): Variation[];
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param args An array of options to pass to the CLI. If an element is an array, they will be treated as alternatives.
|
|
12
|
+
* @returns An array of variations. Can be applied with `withVariations`.
|
|
13
|
+
* @example
|
|
14
|
+
* // Creates 2 variations, both with --flag, but one with --no-daemon and the other with --daemon.
|
|
15
|
+
* const variations = Variation.FromCliArgs([
|
|
16
|
+
* '--flag',
|
|
17
|
+
* ['--no-daemon', '--daemon'],
|
|
18
|
+
* ]);
|
|
19
|
+
*
|
|
20
|
+
* // Creates 4 variations, with combinations of --a and --b.
|
|
21
|
+
* const variations = Variation.FromCliArgs([
|
|
22
|
+
* ['--a', '--b'],
|
|
23
|
+
* ]);
|
|
24
|
+
*/
|
|
25
|
+
static FromCliArgs(args: Array<string | string[]>): Variation[];
|
|
12
26
|
withEnvironmentVariables(env: Partial<NodeJS.ProcessEnv>): this;
|
|
13
27
|
withEnvironmentVariable(name: string, value: string): this;
|
|
14
|
-
|
|
28
|
+
withCliArgs(...args: string[]): this;
|
|
15
29
|
}
|
package/dist/variation.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Variation = void 0;
|
|
4
|
-
|
|
4
|
+
const shared_api_1 = require("./shared-api");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
class Variation extends shared_api_1.BenchmarkBase {
|
|
7
|
+
name;
|
|
8
|
+
environment = {};
|
|
9
|
+
cliArgs = [];
|
|
5
10
|
constructor(name) {
|
|
11
|
+
super();
|
|
6
12
|
this.name = name;
|
|
7
|
-
this.setupMethods = [];
|
|
8
|
-
this.teardownMethods = [];
|
|
9
|
-
this.environment = {};
|
|
10
13
|
}
|
|
11
14
|
static FromEnvironmentVariables(variables) {
|
|
12
|
-
const combinations = variables.
|
|
15
|
+
const combinations = (0, utils_1.findCombinations)(variables.map(([name, values]) => values.map((value) => [name, value])));
|
|
16
|
+
variables.reduce((acc, [name, values]) => {
|
|
13
17
|
return acc.flatMap((accItem) => {
|
|
14
18
|
return values.map((value) => {
|
|
15
19
|
return [...accItem, [name, value]];
|
|
@@ -21,24 +25,44 @@ class Variation {
|
|
|
21
25
|
return new Variation(label).withEnvironmentVariables(Object.fromEntries(combination));
|
|
22
26
|
});
|
|
23
27
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param args An array of options to pass to the CLI. If an element is an array, they will be treated as alternatives.
|
|
31
|
+
* @returns An array of variations. Can be applied with `withVariations`.
|
|
32
|
+
* @example
|
|
33
|
+
* // Creates 2 variations, both with --flag, but one with --no-daemon and the other with --daemon.
|
|
34
|
+
* const variations = Variation.FromCliArgs([
|
|
35
|
+
* '--flag',
|
|
36
|
+
* ['--no-daemon', '--daemon'],
|
|
37
|
+
* ]);
|
|
38
|
+
*
|
|
39
|
+
* // Creates 4 variations, with combinations of --a and --b.
|
|
40
|
+
* const variations = Variation.FromCliArgs([
|
|
41
|
+
* ['--a', '--b'],
|
|
42
|
+
* ]);
|
|
43
|
+
*/
|
|
44
|
+
static FromCliArgs(args) {
|
|
45
|
+
const alternatives = args.filter(Array.isArray);
|
|
46
|
+
const values = (0, utils_1.findCombinations)(alternatives);
|
|
47
|
+
return values.flatMap((alts) => {
|
|
48
|
+
const cliArgs = args.map((arg) => Array.isArray(arg) ? alts.shift() : arg);
|
|
49
|
+
const label = cliArgs.join(' ');
|
|
50
|
+
return new Variation(label).withCliArgs(...cliArgs);
|
|
51
|
+
});
|
|
31
52
|
}
|
|
32
53
|
withEnvironmentVariables(env) {
|
|
33
|
-
this.environment =
|
|
54
|
+
this.environment = {
|
|
55
|
+
...this.environment,
|
|
56
|
+
...env,
|
|
57
|
+
};
|
|
34
58
|
return this;
|
|
35
59
|
}
|
|
36
60
|
withEnvironmentVariable(name, value) {
|
|
37
61
|
this.environment[name] = value;
|
|
38
62
|
return this;
|
|
39
63
|
}
|
|
40
|
-
|
|
41
|
-
this.
|
|
64
|
+
withCliArgs(...args) {
|
|
65
|
+
this.cliArgs = this.cliArgs.concat(args);
|
|
42
66
|
return this;
|
|
43
67
|
}
|
|
44
68
|
}
|
package/package.json
CHANGED
|
@@ -1,35 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flexi-bench",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/AgentEnder/flexi-bench"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
|
-
"test": "
|
|
11
|
+
"test": "node --import tsx --test './src/**/*.spec.ts'",
|
|
12
|
+
"test:watch": "node --import tsx --test --watch './src/**/*.spec.ts'",
|
|
8
13
|
"build": "tsc -p tsconfig.json",
|
|
9
|
-
"format": "prettier --write src"
|
|
14
|
+
"format": "prettier --write src",
|
|
15
|
+
"prepare": "patch-package && nx build flexi-bench"
|
|
10
16
|
},
|
|
11
17
|
"author": "",
|
|
12
|
-
"license": "
|
|
18
|
+
"license": "MIT",
|
|
13
19
|
"devDependencies": {
|
|
20
|
+
"@nx-dotnet/nx-ghpages": "^2.3.0",
|
|
14
21
|
"@nx/js": "^19.4.2",
|
|
15
22
|
"@swc-node/register": "~1.9.1",
|
|
16
23
|
"@swc/core": "~1.5.7",
|
|
17
24
|
"@swc/helpers": "~0.5.11",
|
|
18
|
-
"nx": "19.4.2"
|
|
19
|
-
},
|
|
20
|
-
"nx": {},
|
|
21
|
-
"dependencies": {
|
|
22
25
|
"@types/cli-progress": "^3.11.6",
|
|
23
26
|
"@types/node": "^20.14.10",
|
|
24
|
-
"
|
|
27
|
+
"nx": "19.4.2",
|
|
28
|
+
"patch-package": "^8.0.0",
|
|
25
29
|
"prettier": "^3.3.2",
|
|
26
|
-
"
|
|
30
|
+
"ts-node": "^10.9.2",
|
|
31
|
+
"tsx": "^4.16.2",
|
|
32
|
+
"typescript": "^5.5.3",
|
|
33
|
+
"yaml": "^2.4.5"
|
|
27
34
|
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"cli-progress": "^3.12.0",
|
|
37
|
+
"markdown-factory": "^0.0.6"
|
|
38
|
+
},
|
|
39
|
+
"nx": {},
|
|
28
40
|
"files": [
|
|
29
41
|
"dist",
|
|
30
42
|
"README.md",
|
|
31
43
|
"LICENSE",
|
|
32
44
|
"CHANGELOG.md",
|
|
33
45
|
"package.json"
|
|
46
|
+
],
|
|
47
|
+
"workspaces": [
|
|
48
|
+
".",
|
|
49
|
+
"docs-site",
|
|
50
|
+
"packages/*"
|
|
34
51
|
]
|
|
35
52
|
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BenchmarkConsoleReporter = void 0;
|
|
4
|
-
const cli_progress_1 = require("cli-progress");
|
|
5
|
-
class BenchmarkConsoleReporter {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.bar = new cli_progress_1.SingleBar({
|
|
8
|
-
format: 'Running: {label}\n{bar} {percentage}% | {value}/{total} - ETA: {eta}s',
|
|
9
|
-
barCompleteChar: '\u2588',
|
|
10
|
-
barIncompleteChar: '\u2591',
|
|
11
|
-
hideCursor: true,
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
progress(name, percent, context) {
|
|
15
|
-
var _a;
|
|
16
|
-
if (!this.bar.isActive) {
|
|
17
|
-
this.bar.start((_a = context.totalIterations) !== null && _a !== void 0 ? _a : 100, 0);
|
|
18
|
-
}
|
|
19
|
-
this.bar.update(context.completedIterations, { label: name });
|
|
20
|
-
process.stdout.moveCursor(0, -1);
|
|
21
|
-
// console.log(`Progress: ${name} ${Math.round(percent * 10000) / 100}%`);
|
|
22
|
-
}
|
|
23
|
-
report(benchmark, results) {
|
|
24
|
-
this.bar.stop();
|
|
25
|
-
process.stdout.moveCursor(0, -1);
|
|
26
|
-
process.stdout.clearScreenDown();
|
|
27
|
-
console.log(`Benchmark: ${benchmark.name}`);
|
|
28
|
-
console.table(results);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
exports.BenchmarkConsoleReporter = BenchmarkConsoleReporter;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Result, Reporter, ProgressContext } from './api-types';
|
|
2
|
-
import { Benchmark } from './benchmark';
|
|
3
|
-
export declare class ConsoleReporter implements Reporter {
|
|
4
|
-
private bar;
|
|
5
|
-
constructor();
|
|
6
|
-
progress(name: string, percent: number, context: ProgressContext): void;
|
|
7
|
-
report(benchmark: Benchmark, results: Result[]): void;
|
|
8
|
-
}
|
package/dist/console-reporter.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ConsoleReporter = void 0;
|
|
4
|
-
const cli_progress_1 = require("cli-progress");
|
|
5
|
-
class ConsoleReporter {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.bar = new cli_progress_1.SingleBar({
|
|
8
|
-
format: 'Running: {label}\n{bar} {percentage}% | {value}/{total} - ETA: {eta}s',
|
|
9
|
-
barCompleteChar: '\u2588',
|
|
10
|
-
barIncompleteChar: '\u2591',
|
|
11
|
-
hideCursor: true,
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
progress(name, percent, context) {
|
|
15
|
-
var _a;
|
|
16
|
-
if (!this.bar.isActive) {
|
|
17
|
-
this.bar.start((_a = context.totalIterations) !== null && _a !== void 0 ? _a : 100, 0);
|
|
18
|
-
}
|
|
19
|
-
this.bar.update(context.completedIterations, { label: name });
|
|
20
|
-
process.stdout.moveCursor(0, -1);
|
|
21
|
-
// console.log(`Progress: ${name} ${Math.round(percent * 10000) / 100}%`);
|
|
22
|
-
}
|
|
23
|
-
report(benchmark, results) {
|
|
24
|
-
this.bar.stop();
|
|
25
|
-
process.stdout.moveCursor(0, -1);
|
|
26
|
-
process.stdout.clearScreenDown();
|
|
27
|
-
console.log(`Benchmark: ${benchmark.name}`);
|
|
28
|
-
console.table(results);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
exports.ConsoleReporter = ConsoleReporter;
|
|
@@ -1,15 +0,0 @@
|
|
|
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;
|