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" ;
3
12
import { NodeBenchmarkRunner } from "vitest/runners" ;
4
13
import { patchRootSuiteWithFullFilePath } from "../common" ;
5
14
import { extractBenchmarkResults } from "./utils" ;
@@ -10,10 +19,13 @@ import { extractBenchmarkResults } from "./utils";
10
19
*/
11
20
export class WalltimeRunner extends NodeBenchmarkRunner {
12
21
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 ;
14
25
15
26
async runSuite ( suite : RunnerTestSuite ) : Promise < void > {
16
27
patchRootSuiteWithFullFilePath ( suite ) ;
28
+ this . populateBenchmarkUris ( suite ) ;
17
29
18
30
setupCore ( ) ;
19
31
@@ -32,6 +44,72 @@ export class WalltimeRunner extends NodeBenchmarkRunner {
32
44
) ;
33
45
}
34
46
}
47
+
48
+ private populateBenchmarkUris ( suite : RunnerTestSuite , parentPath = "" ) : void {
49
+ const currentPath =
50
+ parentPath !== "" ? `${ parentPath } ::${ suite . name } ` : suite . name ;
51
+
52
+ for ( const task of suite . tasks ) {
53
+ if ( task . type === "suite" ) {
54
+ this . suiteUris . set ( task . id , `${ currentPath } ::${ task . name } ` ) ;
55
+ this . populateBenchmarkUris ( task , currentPath ) ;
56
+ }
57
+ }
58
+ }
59
+
60
+ async importTinybench ( ) : Promise < typeof import ( "tinybench" ) > {
61
+ const tinybench = await super . importTinybench ( ) ;
62
+
63
+ if ( this . isTinybenchHookedWithCodspeed ) {
64
+ return tinybench ;
65
+ }
66
+ this . isTinybenchHookedWithCodspeed = true ;
67
+
68
+ const originalRun = tinybench . Task . prototype . run ;
69
+
70
+ const getSuiteUri = ( ) : string => {
71
+ if ( this . currentSuiteId === null ) {
72
+ throw new Error ( "currentSuiteId is null - something went wrong" ) ;
73
+ }
74
+ return this . suiteUris . get ( this . currentSuiteId ) || "" ;
75
+ } ;
76
+
77
+ tinybench . Task . prototype . run = async function ( ) {
78
+ const { fn } = this as { fn : Fn } ;
79
+ const suiteUri = getSuiteUri ( ) ;
80
+
81
+ function __codspeed_root_frame__ ( ) {
82
+ return fn ( ) ;
83
+ }
84
+ ( this as { fn : Fn } ) . fn = __codspeed_root_frame__ ;
85
+
86
+ InstrumentHooks . startBenchmark ( ) ;
87
+ await originalRun . call ( this ) ;
88
+ InstrumentHooks . stopBenchmark ( ) ;
89
+
90
+ // Look up the URI by task name
91
+ const uri = `${ suiteUri } ::${ this . name } ` ;
92
+ InstrumentHooks . setExecutedBenchmark ( process . pid , uri ) ;
93
+
94
+ return this ;
95
+ } ;
96
+
97
+ return tinybench ;
98
+ }
99
+
100
+ // Allow tinybench to retrieve the path to the currently running suite
101
+ async onTaskUpdate (
102
+ _ : RunnerTaskResultPack [ ] ,
103
+ events : RunnerTaskEventPack [ ]
104
+ ) : Promise < void > {
105
+ events . map ( ( event ) => {
106
+ const [ id , eventName ] = event ;
107
+
108
+ if ( eventName === "suite-prepare" ) {
109
+ this . currentSuiteId = id ;
110
+ }
111
+ } ) ;
112
+ }
35
113
}
36
114
37
115
export default WalltimeRunner ;
0 commit comments