1
- import { CompileBenchmarkFilter } from "../types" ;
1
+ import { BenchmarkFilter , CompareResponse , StatComparison } from "../types" ;
2
+ import { TestCaseComparison } from "../data" ;
2
3
3
- export const defaultFilter : CompileBenchmarkFilter = {
4
+ export type CompileBenchmarkFilter = {
5
+ profile : {
6
+ check : boolean ;
7
+ debug : boolean ;
8
+ opt : boolean ;
9
+ doc : boolean ;
10
+ } ;
11
+ scenario : {
12
+ full : boolean ;
13
+ incrFull : boolean ;
14
+ incrUnchanged : boolean ;
15
+ incrPatched : boolean ;
16
+ } ;
17
+ category : {
18
+ primary : boolean ;
19
+ secondary : boolean ;
20
+ } ;
21
+ } & BenchmarkFilter ;
22
+ export const defaultCompileFilter : CompileBenchmarkFilter = {
4
23
name : null ,
5
24
nonRelevant : false ,
6
25
showRawData : false ,
@@ -21,3 +40,142 @@ export const defaultFilter: CompileBenchmarkFilter = {
21
40
secondary : true ,
22
41
} ,
23
42
} ;
43
+
44
+ export type Profile = "check" | "debug" | "opt" | "doc" ;
45
+ export type Category = "primary" | "secondary" ;
46
+
47
+ export type CompileBenchmarkMap = Dict < { category : Category } > ;
48
+
49
+ export interface CompileBenchmarkDescription {
50
+ name : string ;
51
+ category : Category ;
52
+ }
53
+
54
+ export interface CompileBenchmarkComparison {
55
+ benchmark : string ;
56
+ profile : Profile ;
57
+ scenario : string ;
58
+ comparison : StatComparison ;
59
+ }
60
+
61
+ export interface CompileTestCase {
62
+ benchmark : string ;
63
+ profile : Profile ;
64
+ scenario : string ;
65
+ category : Category ;
66
+ }
67
+
68
+ export function computeCompileComparisonsWithNonRelevant (
69
+ filter : CompileBenchmarkFilter ,
70
+ data : CompareResponse ,
71
+ benchmarkMap : CompileBenchmarkMap
72
+ ) : TestCaseComparison < CompileTestCase > [ ] {
73
+ function profileFilter ( profile : Profile ) : boolean {
74
+ if ( profile === "check" ) {
75
+ return filter . profile . check ;
76
+ } else if ( profile === "debug" ) {
77
+ return filter . profile . debug ;
78
+ } else if ( profile === "opt" ) {
79
+ return filter . profile . opt ;
80
+ } else if ( profile === "doc" ) {
81
+ return filter . profile . doc ;
82
+ } else {
83
+ return true ;
84
+ }
85
+ }
86
+
87
+ function scenarioFilter ( scenario : string ) : boolean {
88
+ if ( scenario === "full" ) {
89
+ return filter . scenario . full ;
90
+ } else if ( scenario === "incr-full" ) {
91
+ return filter . scenario . incrFull ;
92
+ } else if ( scenario === "incr-unchanged" ) {
93
+ return filter . scenario . incrUnchanged ;
94
+ } else if ( scenario . startsWith ( "incr-patched" ) ) {
95
+ return filter . scenario . incrPatched ;
96
+ } else {
97
+ // Unknown, but by default we should show things
98
+ return true ;
99
+ }
100
+ }
101
+
102
+ function categoryFilter ( category : Category ) {
103
+ if ( category === "primary" && ! filter . category . primary ) return false ;
104
+ if ( category === "secondary" && ! filter . category . secondary ) return false ;
105
+ return true ;
106
+ }
107
+
108
+ function shouldShowTestCase ( comparison : TestCaseComparison < CompileTestCase > ) {
109
+ const name = `${ comparison . testCase . benchmark } ${ comparison . testCase . profile } ${ comparison . testCase . scenario } ` ;
110
+ const nameFilter = filter . name && filter . name . trim ( ) ;
111
+ const nameFiltered = ! nameFilter || name . includes ( nameFilter ) ;
112
+
113
+ return (
114
+ profileFilter ( comparison . testCase . profile ) &&
115
+ scenarioFilter ( comparison . testCase . scenario ) &&
116
+ categoryFilter ( comparison . testCase . category ) &&
117
+ nameFiltered
118
+ ) ;
119
+ }
120
+
121
+ let testCases = data . compile_comparisons
122
+ . map (
123
+ ( c : CompileBenchmarkComparison ) : TestCaseComparison < CompileTestCase > => {
124
+ const datumA = c . comparison . statistics [ 0 ] ;
125
+ const datumB = c . comparison . statistics [ 1 ] ;
126
+
127
+ // In the vast majority of cases, we can do the proportional change calculation. However, some
128
+ // metrics can be zero. If the initial value is 0, we can't compute the new value as a
129
+ // percentage change of the old one. If both values are 0, we can say the change is also 0%.
130
+ // If the new value is not 0, the percentage is not really meaningful, but we can say it's 100%.
131
+ let percent ;
132
+ if ( datumA === 0 ) {
133
+ if ( datumB === 0 ) {
134
+ percent = 0 ;
135
+ } else {
136
+ percent = 100 ;
137
+ }
138
+ } else {
139
+ percent = 100 * ( ( datumB - datumA ) / datumA ) ;
140
+ }
141
+
142
+ return {
143
+ testCase : {
144
+ benchmark : c . benchmark ,
145
+ profile : c . profile ,
146
+ scenario : c . scenario ,
147
+ category : ( benchmarkMap [ c . benchmark ] || { } ) . category || "secondary" ,
148
+ } ,
149
+ isRelevant : c . comparison . is_relevant ,
150
+ significanceFactor : c . comparison . significance_factor ,
151
+ significanceThreshold : c . comparison . significance_threshold * 100.0 , // ensure the threshold is in %
152
+ datumA,
153
+ datumB,
154
+ percent,
155
+ } ;
156
+ }
157
+ )
158
+ . filter ( ( tc ) => shouldShowTestCase ( tc ) ) ;
159
+
160
+ // Sort by name first, so that there is a canonical ordering
161
+ // of test cases. This ensures the overall order is stable, even if
162
+ // individual benchmarks have the same largestChange value.
163
+ testCases . sort ( ( a , b ) =>
164
+ a . testCase . benchmark . localeCompare ( b . testCase . benchmark )
165
+ ) ;
166
+ testCases . sort ( ( a , b ) => Math . abs ( b . percent ) - Math . abs ( a . percent ) ) ;
167
+
168
+ return testCases ;
169
+ }
170
+
171
+ export function createCompileBenchmarkMap (
172
+ data : CompareResponse
173
+ ) : CompileBenchmarkMap {
174
+ const benchmarks = { } ;
175
+ for ( const benchmark of data . compile_benchmark_data ) {
176
+ benchmarks [ benchmark . name ] = {
177
+ category : benchmark . category ,
178
+ } ;
179
+ }
180
+ return benchmarks ;
181
+ }
0 commit comments