Skip to content

Commit 7545857

Browse files
feat(vitest-plugin): add perf profiling for vitest plugin
1 parent bee409e commit 7545857

3 files changed

Lines changed: 87 additions & 4 deletions

File tree

packages/vitest-plugin/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"bench": "vitest bench"
2929
},
3030
"dependencies": {
31-
"@codspeed/core": "workspace:^5.0.0"
31+
"@codspeed/core": "workspace:^5.0.0",
32+
"tinybench": "^2.9.0"
3233
},
3334
"peerDependencies": {
3435
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0",

packages/vitest-plugin/src/walltime/index.ts

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
import { setupCore, writeWalltimeResults } from "@codspeed/core";
2-
import { type RunnerTestSuite } from "vitest";
1+
import {
2+
InstrumentHooks,
3+
setupCore,
4+
writeWalltimeResults,
5+
} from "@codspeed/core";
6+
import { Fn } from "tinybench";
7+
import {
8+
RunnerTaskEventPack,
9+
RunnerTaskResultPack,
10+
type RunnerTestSuite,
11+
} from "vitest";
312
import { NodeBenchmarkRunner } from "vitest/runners";
413
import { patchRootSuiteWithFullFilePath } from "../common";
514
import { extractBenchmarkResults } from "./utils";
@@ -10,10 +19,13 @@ import { extractBenchmarkResults } from "./utils";
1019
*/
1120
export class WalltimeRunner extends NodeBenchmarkRunner {
1221
private isTinybenchHookedWithCodspeed = false;
13-
private benchmarkUris = new Map<string, string>();
22+
private suiteUris = new Map<string, string>();
23+
/// Suite ID of the currently running suite, to allow constructing the URI in the context of tinybench tasks
24+
private currentSuiteId: string | null = null;
1425

1526
async runSuite(suite: RunnerTestSuite): Promise<void> {
1627
patchRootSuiteWithFullFilePath(suite);
28+
this.populateBenchmarkUris(suite);
1729

1830
setupCore();
1931

@@ -32,6 +44,73 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
3244
);
3345
}
3446
}
47+
48+
private populateBenchmarkUris(suite: RunnerTestSuite, parentPath = ""): void {
49+
const currentPath = parentPath
50+
? `${parentPath}::${suite.name}`
51+
: suite.name;
52+
53+
for (const task of suite.tasks) {
54+
if (task.type === "suite") {
55+
this.populateBenchmarkUris(task, currentPath);
56+
this.suiteUris.set(task.id, currentPath);
57+
}
58+
}
59+
}
60+
61+
async importTinybench(): Promise<typeof import("tinybench")> {
62+
const tinybench = await super.importTinybench();
63+
64+
if (this.isTinybenchHookedWithCodspeed) {
65+
return tinybench;
66+
}
67+
this.isTinybenchHookedWithCodspeed = true;
68+
69+
const originalRun = tinybench.Task.prototype.run;
70+
71+
const getSuiteUri = (): string => {
72+
if (this.currentSuiteId === null) {
73+
throw new Error("currentSuiteId is null - something went wrong");
74+
}
75+
return this.suiteUris.get(this.currentSuiteId) || "";
76+
};
77+
78+
tinybench.Task.prototype.run = async function () {
79+
const { fn } = this as { fn: Fn };
80+
const suiteUri = getSuiteUri();
81+
82+
function __codspeed_root_frame__() {
83+
return fn();
84+
}
85+
(this as { fn: Fn }).fn = __codspeed_root_frame__;
86+
87+
InstrumentHooks.startBenchmark();
88+
await originalRun.call(this);
89+
InstrumentHooks.stopBenchmark();
90+
91+
// Look up the URI by task name
92+
const uri = `${suiteUri}::${this.name}`;
93+
InstrumentHooks.setExecutedBenchmark(process.pid, uri);
94+
95+
return this;
96+
};
97+
98+
return tinybench;
99+
}
100+
101+
// Allow tinybench to retrieve the path to the currently running suite
102+
async onTaskUpdate(
103+
_: RunnerTaskResultPack[],
104+
events: RunnerTaskEventPack[]
105+
): Promise<void> {
106+
events.map((event) => {
107+
const [id, eventName] = event;
108+
109+
if (eventName === "suite-prepare") {
110+
this.currentSuiteId = id;
111+
}
112+
});
113+
}
35114
}
36115

37116
export default WalltimeRunner;

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)