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" ;
312import { NodeBenchmarkRunner } from "vitest/runners" ;
413import { patchRootSuiteWithFullFilePath } from "../common" ;
514import { extractBenchmarkResults } from "./utils" ;
@@ -10,10 +19,13 @@ import { extractBenchmarkResults } from "./utils";
1019 */
1120export 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
37116export default WalltimeRunner ;
0 commit comments