|
12 | 12 | // See the License for the specific language governing permissions and |
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | | -import { Bench } from "tinybench"; |
16 | 15 | import * as console from "node:console"; |
17 | | -import type { DescMessage, Message } from "@bufbuild/protobuf"; |
18 | | -import { createValidator } from "@bufbuild/protovalidate"; |
19 | | -import { cases } from "./cases.js"; |
20 | 16 | import { writeFileSync } from "node:fs"; |
21 | 17 | import { parseArgs } from "node:util"; |
| 18 | +import { createValidator } from "@bufbuild/protovalidate"; |
| 19 | +import { Bench, type Task } from "tinybench"; |
| 20 | +import { cases } from "./cases.js"; |
22 | 21 |
|
23 | | -/* eslint-disable no-console, import/no-named-as-default-member */ |
24 | | - |
25 | | -let outPath = ".tmp/bench"; |
26 | | - |
27 | | -async function main(args: string[]): Promise<void> { |
28 | | - function filterTests(regexp: string): Test[] { |
29 | | - const tests = setupTests(); |
30 | | - const re = new RegExp(regexp); |
31 | | - return tests.filter((test) => re.test(test.name)); |
32 | | - } |
33 | | - |
34 | | - const options = { |
35 | | - dir: { |
36 | | - type: "string", |
37 | | - }, |
38 | | - help: { |
39 | | - type: "boolean", |
40 | | - short: "h", |
41 | | - }, |
42 | | - } as const; |
43 | | - |
44 | | - const { values, positionals } = parseArgs({ |
45 | | - options, |
46 | | - allowPositionals: true, |
47 | | - }); |
48 | | - if (values.help) { |
49 | | - exitUsage(0); |
50 | | - } |
51 | | - if (values.dir) { |
52 | | - outPath = values.dir; |
53 | | - } |
54 | | - if (positionals.length > 1) { |
55 | | - exitUsage(2); |
56 | | - } |
57 | | - |
58 | | - let filter = ".*"; |
59 | | - if (positionals.length == 1) { |
60 | | - filter = positionals[0]; |
61 | | - } |
62 | | - const tests = filterTests(filter); |
63 | | - if (tests.length == 0) { |
64 | | - console.log("No tests match pattern; exiting."); |
65 | | - process.exit(0); |
66 | | - } |
67 | | - await bench(tests); |
68 | | - |
69 | | - function exitUsage(exitCode = 0): never { |
70 | | - const out = exitCode === 0 ? process.stdout : process.stderr; |
71 | | - out.write( |
72 | | - [ |
73 | | - `USAGE: ${process.argv[1]} [regex]`, |
74 | | - ``, |
75 | | - `Run tests with the npm package "tinybench", and print results to standard out.`, |
76 | | - `If no regex is supplied, all benchmarks are run.`, |
77 | | - ``, |
78 | | - ].join("\n"), |
79 | | - ); |
80 | | - process.exit(exitCode); |
81 | | - } |
| 22 | +const usage = `USAGE: ${process.argv[1]} [regex] |
| 23 | +
|
| 24 | +Run tests with the npm package "tinybench", and print results to standard out. |
| 25 | +If no regex is supplied, all benchmarks are run. |
| 26 | +
|
| 27 | +Arguments: |
| 28 | + regex Run only tests whose name matches this regex. |
| 29 | +
|
| 30 | +Options: |
| 31 | + --dir <dir> Directory for JSON results (default: .tmp/bench). |
| 32 | + -h, --help Print this help and exit. |
| 33 | +`; |
| 34 | + |
| 35 | +const options = { |
| 36 | + dir: { |
| 37 | + type: "string", |
| 38 | + }, |
| 39 | + help: { |
| 40 | + type: "boolean", |
| 41 | + short: "h", |
| 42 | + }, |
| 43 | +} as const; |
| 44 | +const { values, positionals } = parseArgs({ |
| 45 | + options, |
| 46 | + allowPositionals: true, |
| 47 | +}); |
| 48 | +if (values.help) { |
| 49 | + console.log(usage); |
| 50 | + process.exit(0); |
82 | 51 | } |
83 | | - |
84 | | -interface Test { |
85 | | - name: string; |
86 | | - schema: DescMessage; |
87 | | - fixture: Message; |
| 52 | +if (positionals.length > 1) { |
| 53 | + console.error(usage); |
| 54 | + process.exit(2); |
| 55 | +} |
| 56 | +const outPath = values.dir ?? ".tmp/bench"; |
| 57 | +const filter = positionals.length > 0 ? new RegExp(positionals[0]) : /.*/; |
| 58 | +const tests = cases.filter((test) => filter.test(test.name)); |
| 59 | +if (tests.length == 0) { |
| 60 | + console.log("No tests match pattern; exiting."); |
| 61 | + process.exit(0); |
88 | 62 | } |
89 | 63 |
|
90 | | -function setupTests(): Test[] { |
91 | | - const tests: Test[] = []; |
92 | | - tests.push(...cases); |
93 | | - return tests; |
| 64 | +const bench = new Bench({ name: "protovalidate benchmarks", time: 100 }); |
| 65 | +const validator = createValidator(); |
| 66 | +for (const test of tests) { |
| 67 | + bench.add(test.name, () => { |
| 68 | + validator.validate(test.schema, test.fixture); |
| 69 | + }); |
94 | 70 | } |
| 71 | +await bench.run(); |
| 72 | +writeOutputJson(outPath, bench.tasks); |
| 73 | +console.log(bench.name); |
| 74 | +console.table(bench.table()); |
95 | 75 |
|
96 | 76 | /** |
97 | | - * Benchmark tests with the npm package "tinybench". Results are printed to |
98 | | - * standard out. |
| 77 | + * JSON output |
99 | 78 | */ |
100 | | -async function bench(tests: Test[]): Promise<void> { |
101 | | - const bench = new Bench({ name: "protovalidate benchmarks", time: 100 }); |
102 | | - const validator = createValidator(); |
103 | | - |
104 | | - for (const test of tests) { |
105 | | - bench.add(test.name, () => { |
106 | | - validator.validate(test.schema, test.fixture); |
107 | | - }); |
108 | | - } |
109 | | - |
110 | | - const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); |
111 | | - |
112 | | - await bench.run(); |
113 | | - |
114 | | - const payload = { |
115 | | - timestamp: timestamp, |
| 79 | +type OutputJson = { |
| 80 | + timestamp: Date; |
| 81 | + /** |
| 82 | + * Node.js version |
| 83 | + */ |
| 84 | + node: string; |
| 85 | + /** |
| 86 | + * Node.js platform / arch |
| 87 | + */ |
| 88 | + platform: string; |
| 89 | + /** |
| 90 | + * tinybench task results |
| 91 | + */ |
| 92 | + tasks: { |
| 93 | + name: string; |
| 94 | + result: Task["result"]; |
| 95 | + }[]; |
| 96 | +}; |
| 97 | + |
| 98 | +function writeOutputJson(outPath: string, tasks: Task[]) { |
| 99 | + const timestamp = new Date(); |
| 100 | + const output: OutputJson = { |
| 101 | + timestamp, |
116 | 102 | node: process.version, |
117 | 103 | platform: `${process.platform}/${process.arch}`, |
118 | | - tasks: bench.tasks.map((t) => ({ |
| 104 | + tasks: tasks.map((t) => ({ |
119 | 105 | name: t.name, |
120 | | - // t.result is undefined if the task errored |
121 | 106 | result: t.result, |
122 | 107 | })), |
123 | 108 | }; |
124 | 109 | writeFileSync( |
125 | | - `${outPath}/${timestamp}.json`, |
126 | | - JSON.stringify(payload, null, 2), |
| 110 | + `${outPath}/${timestamp.toISOString().replace(/[:.]/g, "-")}.json`, |
| 111 | + JSON.stringify(output, null, 2), |
127 | 112 | ); |
128 | | - |
129 | | - console.log(bench.name); |
130 | | - console.table(bench.table()); |
131 | 113 | } |
132 | | - |
133 | | -await main(process.argv.slice(2)); |
0 commit comments