Skip to content

Commit fd45354

Browse files
committed
feat(vitest-runner): add first implementation
1 parent 7f00e39 commit fd45354

File tree

10 files changed

+3715
-6353
lines changed

10 files changed

+3715
-6353
lines changed

packages/vitest-runner/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<div align="center">
2+
<h1><code>@codspeed/vitest-runner</code></h1>
3+
4+
Custom [Vitest](https://vitest.dev) runner for [CodSpeed](https://codspeed.io)
5+
6+
[![CI](https://github.com/CodSpeedHQ/codspeed-node/actions/workflows/ci.yml/badge.svg)](https://github.com/CodSpeedHQ/codspeed-node/actions/workflows/ci.yml)
7+
[![npm (scoped)](https://img.shields.io/npm/v/@codspeed/tinybench-plugin)](https://www.npmjs.com/package/@codspeed/tinybench-plugin)
8+
[![Discord](https://img.shields.io/badge/chat%20on-discord-7289da.svg)](https://discord.com/invite/MxpaCfKSqF)
9+
10+
</div>
11+
12+
## Documentation
13+
14+
Coming soon...
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { bench, describe } from "vitest";
2+
3+
describe("sample", () => {
4+
bench("switch 1", () => {
5+
let a = 1;
6+
let b = 2;
7+
const c = a;
8+
a = b;
9+
b = c;
10+
});
11+
12+
bench("switch 2", () => {
13+
let a = 1;
14+
let b = 10;
15+
a = b + a;
16+
b = a - b;
17+
a = b - a;
18+
});
19+
});

packages/vitest-runner/moon.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tasks:
2+
bench:
3+
command: pnpm vitest bench
4+
inputs:
5+
- "benches/**"
6+
local: true
7+
platform: "system"
8+
options:
9+
cache: false
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "@codspeed/vitest-runner",
3+
"version": "2.2.0",
4+
"description": "vitest runner for CodSpeed",
5+
"keywords": [
6+
"codspeed",
7+
"benchmark",
8+
"vitest",
9+
"performance"
10+
],
11+
"main": "dist/index.es5.js",
12+
"type": "module",
13+
"files": [
14+
"dist"
15+
],
16+
"author": "Adrien Cacciaguerra <adrien@codspeed.io>",
17+
"repository": "https://github.com/CodSpeedHQ/codspeed-node",
18+
"homepage": "https://codspeed.io",
19+
"license": "Apache-2.0",
20+
"devDependencies": {
21+
"vitest": "1.0.0-beta.0"
22+
},
23+
"dependencies": {
24+
"@codspeed/core": "workspace:^2.2.0"
25+
},
26+
"peerDependencies": {
27+
"vitest": "^1.0.0-beta.0"
28+
}
29+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { defineConfig } from "rollup";
2+
import { jsPlugins } from "../../rollup.options";
3+
import pkg from "./package.json" assert { type: "json" };
4+
5+
const entrypoint = "src/index.ts";
6+
7+
export default defineConfig([
8+
{
9+
input: entrypoint,
10+
// for some reasons, vitest only wants to require the `main` entrypoint
11+
// but fails when its CJS since it cannot require `vitest/*` modules, as
12+
// they are ESM only 🤷
13+
// we can circumvent this by exposing the `main` entrypoint as ESM
14+
output: [{ file: pkg.main, format: "es", sourcemap: true }],
15+
plugins: jsPlugins(pkg.version),
16+
external: ["@codspeed/core", /^vitest/],
17+
},
18+
]);
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Measurement, setupCore, teardownCore } from "@codspeed/core";
2+
import { Benchmark, Suite } from "vitest";
3+
import { NodeBenchmarkRunner } from "vitest/runners";
4+
import { getBenchFn } from "vitest/suite";
5+
6+
declare const __VERSION__: string;
7+
8+
async function runBenchmarkSuite(
9+
suite: Suite,
10+
runner: NodeBenchmarkRunner,
11+
parentSuiteName?: string
12+
) {
13+
const benchmarkGroup: Benchmark[] = [];
14+
const benchmarkSuiteGroup: Suite[] = [];
15+
for (const task of suite.tasks) {
16+
if (task.mode !== "run") continue;
17+
18+
if (task.meta?.benchmark) benchmarkGroup.push(task as Benchmark);
19+
else if (task.type === "suite") benchmarkSuiteGroup.push(task);
20+
}
21+
22+
const currentSuiteName = parentSuiteName
23+
? parentSuiteName + "::" + suite.name
24+
: suite.name;
25+
26+
// run nested suites first
27+
if (benchmarkSuiteGroup.length) {
28+
await Promise.all(
29+
benchmarkSuiteGroup.map((subSuite) =>
30+
runBenchmarkSuite(subSuite, runner, currentSuiteName)
31+
)
32+
);
33+
}
34+
35+
// return early if there are no benchmarks to run
36+
if (benchmarkGroup.length === 0) {
37+
return;
38+
}
39+
40+
for (const benchmark of benchmarkGroup) {
41+
const uri = `${currentSuiteName}::${benchmark.name}`;
42+
// @ts-expect-error we do not need to bind the function to an instance of tinybench's Bench
43+
const fn = getBenchFn(benchmark).bind(this);
44+
45+
// run optimizations
46+
await fn();
47+
48+
// run instrumented benchmark
49+
await (async function __codspeed_root_frame__() {
50+
Measurement.startInstrumentation();
51+
await fn();
52+
Measurement.stopInstrumentation(uri);
53+
})();
54+
55+
// TODO: try to use something like `updateTask` instead to use the output of vitest instead console.log
56+
console.log(`[CodSpeed] ${uri} done`);
57+
}
58+
}
59+
60+
class CodSpeedRunner extends NodeBenchmarkRunner {
61+
/**
62+
* Called before running all tests in collected paths.
63+
*/
64+
onBeforeRun() {
65+
// TODO: try to use something like `updateTask` instead to use the output of vitest instead console.log
66+
console.log(
67+
`[CodSpeed] running with @codspeed/vitest-runner v${__VERSION__}`
68+
);
69+
setupCore();
70+
}
71+
72+
async runSuite(suite: Suite): Promise<void> {
73+
// TODO: try to use something like `updateTask` instead to use the output of vitest instead console.log
74+
console.log("Running suite", suite.name);
75+
76+
await runBenchmarkSuite(suite, this);
77+
}
78+
79+
/**
80+
* Called right after running all tests in collected paths.
81+
*/
82+
onAfterRun() {
83+
teardownCore();
84+
// TODO: try to use something like `updateTask` instead to use the output of vitest instead console.log
85+
console.log(`[CodSpeed] Done running benches.`);
86+
}
87+
}
88+
89+
export default CodSpeedRunner;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src",
6+
"typeRoots": ["node_modules/@types", "../../node_modules/@types"]
7+
},
8+
"references": [{ "path": "../core" }],
9+
"include": ["src/**/*.ts"]
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"types": ["jest", "node"]
5+
},
6+
"include": ["tests/**/*.ts", "benches/**/*.ts", "jest.config.ts"]
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineConfig } from "vitest/config";
2+
3+
export default defineConfig({
4+
test: {
5+
runner: ".",
6+
},
7+
});

0 commit comments

Comments
 (0)