overtake 0.1.2 → 1.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +76 -82
  2. package/bin/overtake.js +2 -0
  3. package/build/__tests__/runner.d.ts +1 -0
  4. package/build/benchmark.cjs +237 -0
  5. package/build/benchmark.cjs.map +1 -0
  6. package/build/benchmark.d.ts +64 -0
  7. package/build/benchmark.js +189 -0
  8. package/build/benchmark.js.map +1 -0
  9. package/build/cli.cjs +149 -0
  10. package/build/cli.cjs.map +1 -0
  11. package/build/cli.d.ts +1 -0
  12. package/build/cli.js +104 -0
  13. package/build/cli.js.map +1 -0
  14. package/build/executor.cjs +68 -0
  15. package/build/executor.cjs.map +1 -0
  16. package/build/executor.d.ts +10 -0
  17. package/build/executor.js +58 -0
  18. package/build/executor.js.map +1 -0
  19. package/build/index.cjs +20 -0
  20. package/build/index.cjs.map +1 -0
  21. package/build/index.d.ts +5 -0
  22. package/build/index.js +3 -0
  23. package/build/index.js.map +1 -0
  24. package/build/queue.cjs +48 -0
  25. package/build/queue.cjs.map +1 -0
  26. package/build/queue.d.ts +3 -0
  27. package/build/queue.js +38 -0
  28. package/build/queue.js.map +1 -0
  29. package/build/reporter.cjs +175 -0
  30. package/build/reporter.cjs.map +1 -0
  31. package/build/reporter.d.ts +11 -0
  32. package/build/reporter.js +157 -0
  33. package/build/reporter.js.map +1 -0
  34. package/build/runner.cjs +92 -0
  35. package/build/runner.cjs.map +1 -0
  36. package/build/runner.d.ts +2 -0
  37. package/build/runner.js +82 -0
  38. package/build/runner.js.map +1 -0
  39. package/build/types.cjs +48 -0
  40. package/build/types.cjs.map +1 -0
  41. package/build/types.d.ts +59 -0
  42. package/build/types.js +21 -0
  43. package/build/types.js.map +1 -0
  44. package/build/utils.cjs +100 -0
  45. package/build/utils.cjs.map +1 -0
  46. package/build/utils.d.ts +20 -0
  47. package/build/utils.js +67 -0
  48. package/build/utils.js.map +1 -0
  49. package/build/worker.cjs +29 -0
  50. package/build/worker.cjs.map +1 -0
  51. package/build/worker.d.ts +1 -0
  52. package/build/worker.js +25 -0
  53. package/build/worker.js.map +1 -0
  54. package/package.json +15 -13
  55. package/src/__tests__/runner.ts +34 -0
  56. package/src/benchmark.ts +231 -0
  57. package/src/cli.ts +114 -0
  58. package/src/executor.ts +73 -0
  59. package/src/index.ts +6 -0
  60. package/src/queue.ts +42 -0
  61. package/src/reporter.ts +139 -0
  62. package/src/runner.ts +111 -0
  63. package/src/types.ts +72 -0
  64. package/src/utils.ts +65 -0
  65. package/src/worker.ts +46 -0
  66. package/tsconfig.json +17 -0
  67. package/cli.js +0 -70
  68. package/index.d.ts +0 -56
  69. package/index.js +0 -303
  70. package/runner.js +0 -3
package/README.md CHANGED
@@ -5,16 +5,16 @@ Performance benchmark for NodeJS
5
5
  [![Build Status][github-image]][github-url]
6
6
  [![NPM version][npm-image]][npm-url]
7
7
  [![Downloads][downloads-image]][npm-url]
8
- [![Coverage Status][codecov-image]][codecov-url]
9
- [![Maintainability][codeclimate-image]][codeclimate-url]
10
- [![Snyk][snyk-image]][snyk-url]
8
+
9
+ <!--[![Coverage Status][codecov-image]][codecov-url]-->
10
+ <!--[![Maintainability][codeclimate-image]][codeclimate-url]-->
11
+ <!--[![Snyk][snyk-image]][snyk-url]-->
11
12
 
12
13
  ## Table of Contents
13
14
 
14
15
  - [Features](#features)
15
16
  - [Installing](#installing)
16
17
  - [Examples](#examples)
17
- - [Showcase](#showcase)
18
18
  - [License](#license)
19
19
 
20
20
  ## Features
@@ -25,10 +25,10 @@ Performance benchmark for NodeJS
25
25
 
26
26
  ## Installing
27
27
 
28
- Using yarn:
28
+ Using pnpm:
29
29
 
30
30
  ```bash
31
- $ yarn add -D overtake
31
+ $ pnpm add -D overtake
32
32
  ```
33
33
 
34
34
  Using npm:
@@ -39,101 +39,95 @@ $ npm install -D overtake
39
39
 
40
40
  ## Examples
41
41
 
42
- ### Public interface
43
-
44
- Create a benchmark in `__benchmarks__` folder
45
-
46
- ```javascript
47
- benchmark('mongodb vs postgres', () => {
48
- // initialize a context for benchmark
49
- setup(async () => {
50
- const { Client } = await import('pg');
51
- const postgres = new Client();
52
- await postgres.connect();
53
-
54
- const { MongoClient } = await import('mongob');
55
- const mongo = new MongoClient(uri);
56
- await mongo.connect();
57
-
58
- return { postgres, mongo };
59
- });
60
-
61
- measure('mongodb inserts', ({ mongo } /* context */, next) => {
62
- // prepare a collection
63
- const database = mongo.db('overtake');
64
- const test = database.collection('test');
42
+ ### From command line
65
43
 
66
- return (data) => test.insertOne(data).then(next);
67
- });
44
+ Create a benchmark file
68
45
 
69
- measure('postgres inserts', ({ postgres } /* context */, next) => {
70
- // prepare a query
71
- const query = 'INSERT INTO overtake(value) VALUES($1) RETURNING *';
46
+ ```typescript
47
+ // src/__bench__/array-copy.ts
48
+ const suite = benchmark('1M array of strings', () => Array.from({ length: 1_000_000 }, (_, idx) => `${idx}`))
49
+ .feed('1M array of numbers', () => Array.from({ length: 1_000_000 }, (_, idx) => idx))
50
+ .feed('1M typed array', () => new Uint32Array(1_000_000).map((_, idx) => idx));
72
51
 
73
- return (data) => postgres.query(query, [data.value]).then(next);
74
- });
75
-
76
- teardown(async ({ mongo, postgres }) => {
77
- await postgres.end();
78
- await mongo.end();
79
- });
52
+ suite.target('for loop').measure('copy half', (_, input) => {
53
+ const n = input?.length ?? 0;
54
+ const mid = n / 2;
55
+ for (let i = 0; i < mid; i++) {
56
+ input[i + mid] = input[i];
57
+ }
58
+ });
80
59
 
81
- perform('simple test', 100000, [[{ value: 'test' }]]);
60
+ suite.target('copyWithin').measure('copy half', (_, input) => {
61
+ const n = input?.length ?? 0;
62
+ const mid = n / 2;
63
+ input.copyWithin(mid, 0, mid);
82
64
  });
83
65
  ```
84
66
 
85
- Make sure you have installed used modules and run
67
+ Run the command
86
68
 
87
69
  ```bash
88
- yarn overtake
70
+ npx overtake src/__bench__/array-copy.ts -f table -r ops mode mean p99
89
71
  ```
90
72
 
91
- or
92
-
93
- ```bash
94
- npx overtake
73
+ ```
74
+ for loop copy half
75
+ ┌─────────────────────┬──────────────────────┬─────────────┬─────────────┬─────────────────────┬────────┐
76
+ (index) │ ops │ mode │ mean │ p99 │ count │
77
+ ├─────────────────────┼──────────────────────┼─────────────┼─────────────┼─────────────────────┼────────┤
78
+ │ 1M typed array │ '3698 ops/s ± 0.81%' │ '256.65 µs' │ '270.38 µs' │ '574.7 µs ± 0.19%' │ '1000' │
79
+ │ 1M array of numbers │ '2902 ops/s ± 0.3%' │ '343.92 µs' │ '344.51 µs' │ '429.24 µs ± 0.2%' │ '1000' │
80
+ │ 1M array of strings │ '2277 ops/s ± 0.46%' │ '397.15 µs' │ '438.99 µs' │ '569.15 µs ± 0.12%' │ '1000' │
81
+ └─────────────────────┴──────────────────────┴─────────────┴─────────────┴─────────────────────┴────────┘
82
+
83
+ copyWithin copy half
84
+ ┌─────────────────────┬───────────────────────┬────────────┬────────────┬────────────────────┬────────┐
85
+ │ (index) │ ops │ mode │ mean │ p99 │ count │
86
+ ├─────────────────────┼───────────────────────┼────────────┼────────────┼────────────────────┼────────┤
87
+ │ 1M typed array │ '17454 ops/s ± 0.67%' │ '53.11 µs' │ '57.29 µs' │ '81.18 µs ± 1.54%' │ '1000' │
88
+ │ 1M array of numbers │ '103 ops/s ± 0.02%' │ '9.49 ms' │ '9.64 ms' │ '9.91 ms ± 0.38%' │ '50' │
89
+ │ 1M array of strings │ '101 ops/s ± 0.06%' │ '9.55 ms' │ '9.87 ms' │ '10.87 ms ± 2.67%' │ '98' │
90
+ └─────────────────────┴───────────────────────┴────────────┴────────────┴────────────────────┴────────┘
95
91
  ```
96
92
 
97
- ### Inline support
93
+ ### From a standalone module
98
94
 
99
- ```bash
100
- npx overtake -i "class A{}" -i "function A() {}" -i "A = () => {};" -c 20000
101
- ```
95
+ Create a benchmark file
102
96
 
103
- ```
104
- Script
105
- Suite
106
- ➤ Perform
107
- Measure class A{}
108
- ┌─────────┬──────────┬──────────┬──────────┬───────────┬───────┐
109
- (index) │ med │ p95 │ p99 │ total │ count
110
- ├─────────┼──────────┼──────────┼──────────┼───────────┼───────┤
111
- │ 0.0005 │ 0.000551 0.001493 0.002344 │ 16.506385 │ 20000 │
112
- └─────────┴──────────┴──────────┴──────────┴───────────┴───────┘
113
- Measure function A() {}
114
- ┌─────────┬─────────┬────────┬──────────┬──────────┬───────┐
115
- (index) │ med │ p95 │ p99 │ total │ count
116
- ├─────────┼─────────┼────────┼──────────┼──────────┼───────┤
117
- │ 0.00008 │ 0.00009 │ 0.0003 │ 0.000441 │ 2.875578 │ 20000 │
118
- └─────────┴─────────┴────────┴──────────┴──────────┴───────┘
119
- ✓ Measure A = () => {};
120
- ┌─────────┬─────────┬──────────┬──────────┬─────────┬───────┐
121
- │ (index) │ med │ p95 │ p99 │ total │ count │
122
- ├─────────┼─────────┼──────────┼──────────┼─────────┼───────┤
123
- │ 0.00008 │ 0.00012 │ 0.000331 │ 0.000601 │ 3.42556 │ 20000 │
124
- └─────────┴─────────┴──────────┴──────────┴─────────┴───────┘
125
- ```
97
+ ```typescript
98
+ // src/__bench__/array-copy.js
99
+ import { Benchmark, printTableReports } from 'overtake';
100
+
101
+ const benchmark = Benchmark.create('1M array of strings', () => Array.from({ length: 1_000_000 }, (_, idx) => `${idx}`))
102
+ .feed('1M array of numbers', () => Array.from({ length: 1_000_000 }, (_, idx) => idx))
103
+ .feed('1M typed array', () => new Uint32Array(1_000_000).map((_, idx) => idx));
104
+
105
+ benchmark.target('for loop').measure('copy half', (_, input) => {
106
+ const n = input?.length ?? 0;
107
+ const mid = n / 2;
108
+ for (let i = 0; i < mid; i++) {
109
+ input[i + mid] = input[i];
110
+ }
111
+ });
126
112
 
127
- Please take a look at [benchmarks](__benchmarks__) to see more examples
113
+ benchmark.target('copyWithin').measure('copy half', (_, input) => {
114
+ const n = input?.length ?? 0;
115
+ const mid = n / 2;
116
+ input.copyWithin(mid, 0, mid);
117
+ });
118
+
119
+ const reports = await benchmark.execute({
120
+ reportTypes: ['ops', 'mode', 'mean', 'p99'],
121
+ });
128
122
 
129
- ## Showcase
123
+ printTableReports(reports);
124
+ ```
130
125
 
131
- Already measured performance
126
+ And run the command
132
127
 
133
- - [Class vs Function](./overtakes/class-vs-function.md)
134
- - [Postgres vs MongoDB](./overtakes/postgres-vs-mongo.md)
135
- - [Array Copy](./overtakes/array-copy.md)
136
- - [Array Delete Element](./overtakes/array-delete-element.md)
128
+ ```bash
129
+ node src/__bench__/array-copy.js
130
+ ```
137
131
 
138
132
  ## License
139
133
 
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env -S node --experimental-vm-modules --no-warnings
2
+ import '../build/cli.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ AsyncFunction: function() {
13
+ return AsyncFunction;
14
+ },
15
+ Benchmark: function() {
16
+ return Benchmark;
17
+ },
18
+ DEFAULT_REPORT_TYPES: function() {
19
+ return DEFAULT_REPORT_TYPES;
20
+ },
21
+ DEFAULT_WORKERS: function() {
22
+ return DEFAULT_WORKERS;
23
+ },
24
+ FeedContext: function() {
25
+ return FeedContext;
26
+ },
27
+ Measure: function() {
28
+ return Measure;
29
+ },
30
+ MeasureContext: function() {
31
+ return MeasureContext;
32
+ },
33
+ Target: function() {
34
+ return Target;
35
+ },
36
+ TargetContext: function() {
37
+ return TargetContext;
38
+ },
39
+ printJSONReports: function() {
40
+ return printJSONReports;
41
+ },
42
+ printSimpleReports: function() {
43
+ return printSimpleReports;
44
+ },
45
+ printTableReports: function() {
46
+ return printTableReports;
47
+ }
48
+ });
49
+ const _nodeos = require("node:os");
50
+ const _executorcjs = require("./executor.cjs");
51
+ const _typescjs = require("./types.cjs");
52
+ const DEFAULT_WORKERS = (0, _nodeos.cpus)().length;
53
+ const AsyncFunction = (async ()=>{}).constructor;
54
+ const DEFAULT_REPORT_TYPES = [
55
+ 'ops'
56
+ ];
57
+ class MeasureContext {
58
+ title;
59
+ run;
60
+ pre;
61
+ post;
62
+ constructor(title, run){
63
+ this.title = title;
64
+ this.run = run;
65
+ }
66
+ }
67
+ class Measure {
68
+ #ctx;
69
+ constructor(ctx){
70
+ this.#ctx = ctx;
71
+ }
72
+ pre(fn) {
73
+ this.#ctx.pre = fn;
74
+ return this;
75
+ }
76
+ post(fn) {
77
+ this.#ctx.post = fn;
78
+ return this;
79
+ }
80
+ }
81
+ class TargetContext {
82
+ title;
83
+ setup;
84
+ teardown;
85
+ measures;
86
+ constructor(title, setup){
87
+ this.title = title;
88
+ this.setup = setup;
89
+ this.measures = [];
90
+ }
91
+ }
92
+ class Target {
93
+ #ctx;
94
+ constructor(ctx){
95
+ this.#ctx = ctx;
96
+ }
97
+ teardown(fn) {
98
+ this.#ctx.teardown = fn;
99
+ return this;
100
+ }
101
+ measure(title, run) {
102
+ const measure = new MeasureContext(title, run);
103
+ this.#ctx.measures.push(measure);
104
+ return new Measure(measure);
105
+ }
106
+ }
107
+ class FeedContext {
108
+ title;
109
+ fn;
110
+ constructor(title, fn){
111
+ this.title = title;
112
+ this.fn = fn;
113
+ }
114
+ }
115
+ class Benchmark {
116
+ #targets = [];
117
+ #feeds = [];
118
+ #executed = false;
119
+ static create(title, fn) {
120
+ if (fn) {
121
+ return new Benchmark(title, fn);
122
+ } else {
123
+ return new Benchmark(title);
124
+ }
125
+ }
126
+ constructor(title, fn){
127
+ if (fn) {
128
+ this.feed(title, fn);
129
+ } else {
130
+ this.feed(title);
131
+ }
132
+ }
133
+ feed(title, fn) {
134
+ const self = this;
135
+ self.#feeds.push(fn ? new FeedContext(title, fn) : new FeedContext(title));
136
+ return self;
137
+ }
138
+ target(title, setup) {
139
+ const target = new TargetContext(title, setup);
140
+ this.#targets.push(target);
141
+ return new Target(target);
142
+ }
143
+ async execute({ workers = DEFAULT_WORKERS, warmupCycles = 20, maxCycles = _typescjs.DEFAULT_CYCLES, minCycles = 50, absThreshold = 1_000, relThreshold = 0.02, reportTypes = DEFAULT_REPORT_TYPES }) {
144
+ if (this.#executed) {
145
+ throw new Error("Benchmark is executed and can't be reused");
146
+ }
147
+ this.#executed = true;
148
+ const executor = (0, _executorcjs.createExecutor)({
149
+ workers,
150
+ warmupCycles,
151
+ maxCycles,
152
+ minCycles,
153
+ absThreshold,
154
+ relThreshold,
155
+ reportTypes
156
+ });
157
+ const reports = [];
158
+ for (const target of this.#targets){
159
+ const targetReport = {
160
+ target: target.title,
161
+ measures: []
162
+ };
163
+ for (const measure of target.measures){
164
+ const measureReport = {
165
+ measure: measure.title,
166
+ feeds: []
167
+ };
168
+ for (const feed of this.#feeds){
169
+ const data = await feed.fn?.();
170
+ executor.push({
171
+ setup: target.setup,
172
+ teardown: target.teardown,
173
+ pre: measure.pre,
174
+ run: measure.run,
175
+ post: measure.post,
176
+ data
177
+ }).then((data)=>{
178
+ measureReport.feeds.push({
179
+ feed: feed.title,
180
+ data
181
+ });
182
+ });
183
+ }
184
+ targetReport.measures.push(measureReport);
185
+ }
186
+ reports.push(targetReport);
187
+ }
188
+ await executor.drain();
189
+ executor.kill();
190
+ return reports;
191
+ }
192
+ }
193
+ const printSimpleReports = (reports)=>{
194
+ for (const report of reports){
195
+ for (const { measure, feeds } of report.measures){
196
+ console.group('\n', report.target, measure);
197
+ for (const { feed, data } of feeds){
198
+ const output = Object.entries(data).map(([key, report])=>`${key}: ${report.toString()}`).join('; ');
199
+ console.log(feed, output);
200
+ }
201
+ console.groupEnd();
202
+ }
203
+ }
204
+ };
205
+ const printTableReports = (reports)=>{
206
+ for (const report of reports){
207
+ for (const { measure, feeds } of report.measures){
208
+ console.log('\n', report.target, measure);
209
+ const table = {};
210
+ for (const { feed, data } of feeds){
211
+ table[feed] = Object.fromEntries(Object.entries(data).map(([key, report])=>[
212
+ key,
213
+ report.toString()
214
+ ]));
215
+ }
216
+ console.table(table);
217
+ }
218
+ }
219
+ };
220
+ const printJSONReports = (reports, padding)=>{
221
+ const output = {};
222
+ for (const report of reports){
223
+ for (const { measure, feeds } of report.measures){
224
+ const row = {};
225
+ for (const { feed, data } of feeds){
226
+ row[feed] = Object.fromEntries(Object.entries(data).map(([key, report])=>[
227
+ key,
228
+ report.toString()
229
+ ]));
230
+ }
231
+ output[`${report.target} ${measure}`] = row;
232
+ }
233
+ }
234
+ console.log(JSON.stringify(output, null, padding));
235
+ };
236
+
237
+ //# sourceMappingURL=benchmark.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/benchmark.ts"],"sourcesContent":["import { cpus } from 'node:os';\nimport { createExecutor, ExecutorOptions, ExecutorReport } from './executor.js';\nimport { MaybePromise, StepFn, SetupFn, TeardownFn, FeedFn, ReportType, ReportTypeList, DEFAULT_CYCLES } from './types.js';\n\nexport const DEFAULT_WORKERS = cpus().length;\n\nexport const AsyncFunction = (async () => {}).constructor;\n\nexport interface TargetReport<R extends ReportTypeList> {\n target: string;\n measures: MeasureReport<R>[];\n}\n\nexport interface MeasureReport<R extends ReportTypeList> {\n measure: string;\n feeds: FeedReport<R>[];\n}\n\nexport interface FeedReport<R extends ReportTypeList> {\n feed: string;\n data: ExecutorReport<R>;\n}\n\nexport const DEFAULT_REPORT_TYPES = ['ops'] as const;\nexport type DefaultReportTypes = (typeof DEFAULT_REPORT_TYPES)[number];\n\nexport class MeasureContext<TContext, TInput> {\n public pre?: StepFn<TContext, TInput>;\n public post?: StepFn<TContext, TInput>;\n\n constructor(\n public title: string,\n public run: StepFn<TContext, TInput>,\n ) {}\n}\n\nexport class Measure<TContext, TInput> {\n #ctx: MeasureContext<TContext, TInput>;\n\n constructor(ctx: MeasureContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n\n pre(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.pre = fn;\n return this;\n }\n post(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.post = fn;\n return this;\n }\n}\n\nexport class TargetContext<TContext, TInput> {\n public teardown?: TeardownFn<TContext>;\n public measures: MeasureContext<TContext, TInput>[] = [];\n\n constructor(\n readonly title: string,\n readonly setup?: SetupFn<MaybePromise<TContext>>,\n ) {}\n}\n\nexport class Target<TContext, TInput> {\n #ctx: TargetContext<TContext, TInput>;\n\n constructor(ctx: TargetContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n teardown(fn: TeardownFn<TContext>): Target<TContext, TInput> {\n this.#ctx.teardown = fn;\n\n return this;\n }\n measure(title: string, run: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n const measure = new MeasureContext(title, run);\n this.#ctx.measures.push(measure);\n\n return new Measure(measure);\n }\n}\n\nexport class FeedContext<TInput> {\n constructor(\n readonly title: string,\n readonly fn?: FeedFn<TInput>,\n ) {}\n}\n\nexport class Benchmark<TInput> {\n #targets: TargetContext<unknown, TInput>[] = [];\n #feeds: FeedContext<TInput>[] = [];\n #executed = false;\n\n static create(title: string): Benchmark<void>;\n static create<I>(title: string, fn: FeedFn<I>): Benchmark<I>;\n static create<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<I> {\n if (fn) {\n return new Benchmark(title, fn);\n } else {\n return new Benchmark(title);\n }\n }\n\n constructor(title: string);\n constructor(title: string, fn: FeedFn<TInput>);\n constructor(title: string, fn?: FeedFn<TInput> | undefined) {\n if (fn) {\n this.feed(title, fn);\n } else {\n this.feed(title);\n }\n }\n\n feed(title: string): Benchmark<TInput | void>;\n feed<I>(title: string, fn: FeedFn<I>): Benchmark<TInput | I>;\n feed<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<TInput | I> {\n const self = this as Benchmark<TInput | I>;\n self.#feeds.push(fn ? new FeedContext(title, fn) : new FeedContext(title));\n\n return self;\n }\n\n target<TContext>(title: string): Target<void, TInput>;\n target<TContext>(title: string, setup: SetupFn<Awaited<TContext>>): Target<TContext, TInput>;\n target<TContext>(title: string, setup?: SetupFn<Awaited<TContext>> | undefined): Target<TContext, TInput> {\n const target = new TargetContext<TContext, TInput>(title, setup);\n this.#targets.push(target as TargetContext<unknown, TInput>);\n\n return new Target<TContext, TInput>(target);\n }\n\n async execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>({\n workers = DEFAULT_WORKERS,\n warmupCycles = 20,\n maxCycles = DEFAULT_CYCLES,\n minCycles = 50,\n absThreshold = 1_000,\n relThreshold = 0.02,\n reportTypes = DEFAULT_REPORT_TYPES as unknown as R,\n }: ExecutorOptions<R>): Promise<TargetReport<R>[]> {\n if (this.#executed) {\n throw new Error(\"Benchmark is executed and can't be reused\");\n }\n this.#executed = true;\n\n const executor = createExecutor<unknown, TInput, R>({\n workers,\n warmupCycles,\n maxCycles,\n minCycles,\n absThreshold,\n relThreshold,\n reportTypes,\n });\n\n const reports: TargetReport<R>[] = [];\n for (const target of this.#targets) {\n const targetReport: TargetReport<R> = { target: target.title, measures: [] };\n for (const measure of target.measures) {\n const measureReport: MeasureReport<R> = { measure: measure.title, feeds: [] };\n for (const feed of this.#feeds) {\n const data = await feed.fn?.();\n executor\n .push<ExecutorReport<R>>({\n setup: target.setup,\n teardown: target.teardown,\n pre: measure.pre,\n run: measure.run,\n post: measure.post,\n data,\n })\n .then((data) => {\n measureReport.feeds.push({\n feed: feed.title,\n data,\n });\n });\n }\n targetReport.measures.push(measureReport);\n }\n reports.push(targetReport);\n }\n await executor.drain();\n executor.kill();\n\n return reports;\n }\n}\n\nexport const printSimpleReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.group('\\n', report.target, measure);\n for (const { feed, data } of feeds) {\n const output = Object.entries(data)\n .map(([key, report]) => `${key}: ${report.toString()}`)\n .join('; ');\n console.log(feed, output);\n }\n console.groupEnd();\n }\n }\n};\n\nexport const printTableReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.log('\\n', report.target, measure);\n const table: Record<string, unknown> = {};\n for (const { feed, data } of feeds) {\n table[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n console.table(table);\n }\n }\n};\n\nexport const printJSONReports = <R extends ReportTypeList>(reports: TargetReport<R>[], padding?: number) => {\n const output = {} as Record<string, Record<string, Record<string, string>>>;\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n const row = {} as Record<string, Record<string, string>>;\n for (const { feed, data } of feeds) {\n row[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n output[`${report.target} ${measure}`] = row;\n }\n }\n console.log(JSON.stringify(output, null, padding));\n};\n"],"names":["AsyncFunction","Benchmark","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","FeedContext","Measure","MeasureContext","Target","TargetContext","printJSONReports","printSimpleReports","printTableReports","cpus","length","constructor","pre","post","title","run","ctx","fn","teardown","measures","setup","measure","push","create","feed","self","target","execute","workers","warmupCycles","maxCycles","DEFAULT_CYCLES","minCycles","absThreshold","relThreshold","reportTypes","Error","executor","createExecutor","reports","targetReport","measureReport","feeds","data","then","drain","kill","report","console","group","output","Object","entries","map","key","toString","join","log","groupEnd","table","fromEntries","padding","row","JSON","stringify"],"mappings":";;;;;;;;;;;IAMaA,aAAa;eAAbA;;IAmFAC,SAAS;eAATA;;IAlEAC,oBAAoB;eAApBA;;IAnBAC,eAAe;eAAfA;;IA8EAC,WAAW;eAAXA;;IA9CAC,OAAO;eAAPA;;IAVAC,cAAc;eAAdA;;IAqCAC,MAAM;eAANA;;IAVAC,aAAa;eAAbA;;IAqKAC,gBAAgB;eAAhBA;;IA5BAC,kBAAkB;eAAlBA;;IAeAC,iBAAiB;eAAjBA;;;wBA7MQ;6BAC2C;0BAC8C;AAEvG,MAAMR,kBAAkBS,IAAAA,YAAI,IAAGC,MAAM;AAErC,MAAMb,gBAAgB,AAAC,CAAA,WAAa,CAAA,EAAGc,WAAW;AAiBlD,MAAMZ,uBAAuB;IAAC;CAAM;AAGpC,MAAMI;;;IACJS,IAA+B;IAC/BC,KAAgC;IAEvCF,YACE,AAAOG,KAAa,EACpB,AAAOC,GAA6B,CACpC;aAFOD,QAAAA;aACAC,MAAAA;IACN;AACL;AAEO,MAAMb;IACX,CAAA,GAAI,CAAmC;IAEvCS,YAAYK,GAAqC,CAAE;QACjD,IAAI,CAAC,CAAA,GAAI,GAAGA;IACd;IAEAJ,IAAIK,EAA4B,EAA6B;QAC3D,IAAI,CAAC,CAAA,GAAI,CAACL,GAAG,GAAGK;QAChB,OAAO,IAAI;IACb;IACAJ,KAAKI,EAA4B,EAA6B;QAC5D,IAAI,CAAC,CAAA,GAAI,CAACJ,IAAI,GAAGI;QACjB,OAAO,IAAI;IACb;AACF;AAEO,MAAMZ;;;IACJa,SAAgC;IAChCC,SAAkD;IAEzDR,YACE,AAASG,KAAa,EACtB,AAASM,KAAuC,CAChD;aAFSN,QAAAA;aACAM,QAAAA;aAJJD,WAA+C,EAAE;IAKrD;AACL;AAEO,MAAMf;IACX,CAAA,GAAI,CAAkC;IAEtCO,YAAYK,GAAoC,CAAE;QAChD,IAAI,CAAC,CAAA,GAAI,GAAGA;IACd;IACAE,SAASD,EAAwB,EAA4B;QAC3D,IAAI,CAAC,CAAA,GAAI,CAACC,QAAQ,GAAGD;QAErB,OAAO,IAAI;IACb;IACAI,QAAQP,KAAa,EAAEC,GAA6B,EAA6B;QAC/E,MAAMM,UAAU,IAAIlB,eAAeW,OAAOC;QAC1C,IAAI,CAAC,CAAA,GAAI,CAACI,QAAQ,CAACG,IAAI,CAACD;QAExB,OAAO,IAAInB,QAAQmB;IACrB;AACF;AAEO,MAAMpB;;;IACXU,YACE,AAASG,KAAa,EACtB,AAASG,EAAmB,CAC5B;aAFSH,QAAAA;aACAG,KAAAA;IACR;AACL;AAEO,MAAMnB;IACX,CAAA,OAAQ,GAAqC,EAAE,CAAC;IAChD,CAAA,KAAM,GAA0B,EAAE,CAAC;IACnC,CAAA,QAAS,GAAG,MAAM;IAIlB,OAAOyB,OAAUT,KAAa,EAAEG,EAA0B,EAAgB;QACxE,IAAIA,IAAI;YACN,OAAO,IAAInB,UAAUgB,OAAOG;QAC9B,OAAO;YACL,OAAO,IAAInB,UAAUgB;QACvB;IACF;IAIAH,YAAYG,KAAa,EAAEG,EAA+B,CAAE;QAC1D,IAAIA,IAAI;YACN,IAAI,CAACO,IAAI,CAACV,OAAOG;QACnB,OAAO;YACL,IAAI,CAACO,IAAI,CAACV;QACZ;IACF;IAIAU,KAAQV,KAAa,EAAEG,EAA0B,EAAyB;QACxE,MAAMQ,OAAO,IAAI;QACjBA,KAAK,CAAA,KAAM,CAACH,IAAI,CAACL,KAAK,IAAIhB,YAAYa,OAAOG,MAAM,IAAIhB,YAAYa;QAEnE,OAAOW;IACT;IAIAC,OAAiBZ,KAAa,EAAEM,KAA8C,EAA4B;QACxG,MAAMM,SAAS,IAAIrB,cAAgCS,OAAOM;QAC1D,IAAI,CAAC,CAAA,OAAQ,CAACE,IAAI,CAACI;QAEnB,OAAO,IAAItB,OAAyBsB;IACtC;IAEA,MAAMC,QAAuE,EAC3EC,UAAU5B,eAAe,EACzB6B,eAAe,EAAE,EACjBC,YAAYC,wBAAc,EAC1BC,YAAY,EAAE,EACdC,eAAe,KAAK,EACpBC,eAAe,IAAI,EACnBC,cAAcpC,oBAAoC,EAC/B,EAA8B;QACjD,IAAI,IAAI,CAAC,CAAA,QAAS,EAAE;YAClB,MAAM,IAAIqC,MAAM;QAClB;QACA,IAAI,CAAC,CAAA,QAAS,GAAG;QAEjB,MAAMC,WAAWC,IAAAA,2BAAc,EAAqB;YAClDV;YACAC;YACAC;YACAE;YACAC;YACAC;YACAC;QACF;QAEA,MAAMI,UAA6B,EAAE;QACrC,KAAK,MAAMb,UAAU,IAAI,CAAC,CAAA,OAAQ,CAAE;YAClC,MAAMc,eAAgC;gBAAEd,QAAQA,OAAOZ,KAAK;gBAAEK,UAAU,EAAE;YAAC;YAC3E,KAAK,MAAME,WAAWK,OAAOP,QAAQ,CAAE;gBACrC,MAAMsB,gBAAkC;oBAAEpB,SAASA,QAAQP,KAAK;oBAAE4B,OAAO,EAAE;gBAAC;gBAC5E,KAAK,MAAMlB,QAAQ,IAAI,CAAC,CAAA,KAAM,CAAE;oBAC9B,MAAMmB,OAAO,MAAMnB,KAAKP,EAAE;oBAC1BoB,SACGf,IAAI,CAAoB;wBACvBF,OAAOM,OAAON,KAAK;wBACnBF,UAAUQ,OAAOR,QAAQ;wBACzBN,KAAKS,QAAQT,GAAG;wBAChBG,KAAKM,QAAQN,GAAG;wBAChBF,MAAMQ,QAAQR,IAAI;wBAClB8B;oBACF,GACCC,IAAI,CAAC,CAACD;wBACLF,cAAcC,KAAK,CAACpB,IAAI,CAAC;4BACvBE,MAAMA,KAAKV,KAAK;4BAChB6B;wBACF;oBACF;gBACJ;gBACAH,aAAarB,QAAQ,CAACG,IAAI,CAACmB;YAC7B;YACAF,QAAQjB,IAAI,CAACkB;QACf;QACA,MAAMH,SAASQ,KAAK;QACpBR,SAASS,IAAI;QAEb,OAAOP;IACT;AACF;AAEO,MAAMhC,qBAAqB,CAA2BgC;IAC3D,KAAK,MAAMQ,UAAUR,QAAS;QAC5B,KAAK,MAAM,EAAElB,OAAO,EAAEqB,KAAK,EAAE,IAAIK,OAAO5B,QAAQ,CAAE;YAChD6B,QAAQC,KAAK,CAAC,MAAMF,OAAOrB,MAAM,EAAEL;YACnC,KAAK,MAAM,EAAEG,IAAI,EAAEmB,IAAI,EAAE,IAAID,MAAO;gBAClC,MAAMQ,SAASC,OAAOC,OAAO,CAACT,MAC3BU,GAAG,CAAC,CAAC,CAACC,KAAKP,OAAO,GAAK,GAAGO,IAAI,EAAE,EAAEP,OAAOQ,QAAQ,IAAI,EACrDC,IAAI,CAAC;gBACRR,QAAQS,GAAG,CAACjC,MAAM0B;YACpB;YACAF,QAAQU,QAAQ;QAClB;IACF;AACF;AAEO,MAAMlD,oBAAoB,CAA2B+B;IAC1D,KAAK,MAAMQ,UAAUR,QAAS;QAC5B,KAAK,MAAM,EAAElB,OAAO,EAAEqB,KAAK,EAAE,IAAIK,OAAO5B,QAAQ,CAAE;YAChD6B,QAAQS,GAAG,CAAC,MAAMV,OAAOrB,MAAM,EAAEL;YACjC,MAAMsC,QAAiC,CAAC;YACxC,KAAK,MAAM,EAAEnC,IAAI,EAAEmB,IAAI,EAAE,IAAID,MAAO;gBAClCiB,KAAK,CAACnC,KAAK,GAAG2B,OAAOS,WAAW,CAACT,OAAOC,OAAO,CAACT,MAAMU,GAAG,CAAC,CAAC,CAACC,KAAKP,OAAO,GAAK;wBAACO;wBAAKP,OAAOQ,QAAQ;qBAAG;YACvG;YACAP,QAAQW,KAAK,CAACA;QAChB;IACF;AACF;AAEO,MAAMrD,mBAAmB,CAA2BiC,SAA4BsB;IACrF,MAAMX,SAAS,CAAC;IAChB,KAAK,MAAMH,UAAUR,QAAS;QAC5B,KAAK,MAAM,EAAElB,OAAO,EAAEqB,KAAK,EAAE,IAAIK,OAAO5B,QAAQ,CAAE;YAChD,MAAM2C,MAAM,CAAC;YACb,KAAK,MAAM,EAAEtC,IAAI,EAAEmB,IAAI,EAAE,IAAID,MAAO;gBAClCoB,GAAG,CAACtC,KAAK,GAAG2B,OAAOS,WAAW,CAACT,OAAOC,OAAO,CAACT,MAAMU,GAAG,CAAC,CAAC,CAACC,KAAKP,OAAO,GAAK;wBAACO;wBAAKP,OAAOQ,QAAQ;qBAAG;YACrG;YACAL,MAAM,CAAC,GAAGH,OAAOrB,MAAM,CAAC,CAAC,EAAEL,SAAS,CAAC,GAAGyC;QAC1C;IACF;IACAd,QAAQS,GAAG,CAACM,KAAKC,SAAS,CAACd,QAAQ,MAAMW;AAC3C"}
@@ -0,0 +1,64 @@
1
+ import { ExecutorOptions, ExecutorReport } from './executor.js';
2
+ import { MaybePromise, StepFn, SetupFn, TeardownFn, FeedFn, ReportType, ReportTypeList } from './types.js';
3
+ export declare const DEFAULT_WORKERS: number;
4
+ export declare const AsyncFunction: Function;
5
+ export interface TargetReport<R extends ReportTypeList> {
6
+ target: string;
7
+ measures: MeasureReport<R>[];
8
+ }
9
+ export interface MeasureReport<R extends ReportTypeList> {
10
+ measure: string;
11
+ feeds: FeedReport<R>[];
12
+ }
13
+ export interface FeedReport<R extends ReportTypeList> {
14
+ feed: string;
15
+ data: ExecutorReport<R>;
16
+ }
17
+ export declare const DEFAULT_REPORT_TYPES: readonly ["ops"];
18
+ export type DefaultReportTypes = (typeof DEFAULT_REPORT_TYPES)[number];
19
+ export declare class MeasureContext<TContext, TInput> {
20
+ title: string;
21
+ run: StepFn<TContext, TInput>;
22
+ pre?: StepFn<TContext, TInput>;
23
+ post?: StepFn<TContext, TInput>;
24
+ constructor(title: string, run: StepFn<TContext, TInput>);
25
+ }
26
+ export declare class Measure<TContext, TInput> {
27
+ #private;
28
+ constructor(ctx: MeasureContext<TContext, TInput>);
29
+ pre(fn: StepFn<TContext, TInput>): Measure<TContext, TInput>;
30
+ post(fn: StepFn<TContext, TInput>): Measure<TContext, TInput>;
31
+ }
32
+ export declare class TargetContext<TContext, TInput> {
33
+ readonly title: string;
34
+ readonly setup?: SetupFn<MaybePromise<TContext>> | undefined;
35
+ teardown?: TeardownFn<TContext>;
36
+ measures: MeasureContext<TContext, TInput>[];
37
+ constructor(title: string, setup?: SetupFn<MaybePromise<TContext>> | undefined);
38
+ }
39
+ export declare class Target<TContext, TInput> {
40
+ #private;
41
+ constructor(ctx: TargetContext<TContext, TInput>);
42
+ teardown(fn: TeardownFn<TContext>): Target<TContext, TInput>;
43
+ measure(title: string, run: StepFn<TContext, TInput>): Measure<TContext, TInput>;
44
+ }
45
+ export declare class FeedContext<TInput> {
46
+ readonly title: string;
47
+ readonly fn?: FeedFn<TInput> | undefined;
48
+ constructor(title: string, fn?: FeedFn<TInput> | undefined);
49
+ }
50
+ export declare class Benchmark<TInput> {
51
+ #private;
52
+ static create(title: string): Benchmark<void>;
53
+ static create<I>(title: string, fn: FeedFn<I>): Benchmark<I>;
54
+ constructor(title: string);
55
+ constructor(title: string, fn: FeedFn<TInput>);
56
+ feed(title: string): Benchmark<TInput | void>;
57
+ feed<I>(title: string, fn: FeedFn<I>): Benchmark<TInput | I>;
58
+ target<TContext>(title: string): Target<void, TInput>;
59
+ target<TContext>(title: string, setup: SetupFn<Awaited<TContext>>): Target<TContext, TInput>;
60
+ execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>({ workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, reportTypes, }: ExecutorOptions<R>): Promise<TargetReport<R>[]>;
61
+ }
62
+ export declare const printSimpleReports: <R extends ReportTypeList>(reports: TargetReport<R>[]) => void;
63
+ export declare const printTableReports: <R extends ReportTypeList>(reports: TargetReport<R>[]) => void;
64
+ export declare const printJSONReports: <R extends ReportTypeList>(reports: TargetReport<R>[], padding?: number) => void;