@@ -6,6 +6,29 @@ function findQueryParam(name) {
6
6
}
7
7
}
8
8
9
+ function createDefaultFilter ( ) {
10
+ return {
11
+ name : null ,
12
+ nonRelevant : false ,
13
+ profile : {
14
+ check : true ,
15
+ debug : true ,
16
+ opt : true ,
17
+ doc : true
18
+ } ,
19
+ scenario : {
20
+ full : true ,
21
+ incrFull : true ,
22
+ incrUnchanged : true ,
23
+ incrPatched : true
24
+ } ,
25
+ category : {
26
+ primary : true ,
27
+ secondary : true
28
+ }
29
+ } ;
30
+ }
31
+
9
32
const app = Vue . createApp ( {
10
33
mounted ( ) {
11
34
const app = this ;
@@ -20,26 +43,7 @@ const app = Vue.createApp({
20
43
} ,
21
44
data ( ) {
22
45
return {
23
- filter : {
24
- name : null ,
25
- showNonRelevant : false ,
26
- profile : {
27
- check : true ,
28
- debug : true ,
29
- opt : true ,
30
- doc : true
31
- } ,
32
- scenario : {
33
- full : true ,
34
- incrFull : true ,
35
- incrUnchanged : true ,
36
- incrPatched : true
37
- } ,
38
- category : {
39
- primary : true ,
40
- secondary : true
41
- }
42
- } ,
46
+ filter : createDefaultFilter ( ) ,
43
47
showRawData : false ,
44
48
data : null ,
45
49
dataLoading : false
@@ -103,7 +107,7 @@ const app = Vue.createApp({
103
107
let nameFilter = filter . name && filter . name . trim ( ) ;
104
108
nameFilter = ! nameFilter || name . includes ( nameFilter ) ;
105
109
106
- const relevanceFilter = filter . showNonRelevant ? true : testCase . isRelevant ;
110
+ const relevanceFilter = filter . nonRelevant ? true : testCase . isRelevant ;
107
111
108
112
return (
109
113
profileFilter ( testCase . profile ) &&
@@ -219,56 +223,9 @@ const app = Vue.createApp({
219
223
stat ( ) {
220
224
return findQueryParam ( "stat" ) || "instructions:u" ;
221
225
} ,
222
- summary ( ) {
223
- // Create object with each test case that is not filtered out as a key
224
- const filtered = this . testCases . reduce ( ( sum , next ) => {
225
- sum [ testCaseString ( next ) ] = true ;
226
- return sum ;
227
- } , { } ) ;
228
- const newCount = {
229
- regressions : 0 ,
230
- regressions_avg : 0 ,
231
- improvements : 0 ,
232
- improvements_avg : 0 ,
233
- unchanged : 0 ,
234
- average : 0
235
- } ;
236
-
237
- const addDatum = ( result , datum , percent ) => {
238
- if ( percent > 0 && datum . is_relevant ) {
239
- result . regressions += 1 ;
240
- result . regressions_avg += percent ;
241
- } else if ( percent < 0 && datum . is_relevant ) {
242
- result . improvements += 1 ;
243
- result . improvements_avg += percent ;
244
- } else {
245
- result . unchanged += 1 ;
246
- }
247
- result . average += percent ;
248
- } ;
249
-
250
- let result = { all : { ...newCount } , filtered : { ...newCount } }
251
- for ( let d of this . data . comparisons ) {
252
- const testCase = testCaseString ( d )
253
- const datumA = d . statistics [ 0 ] ;
254
- const datumB = d . statistics [ 1 ] ;
255
- let percent = 100 * ( ( datumB - datumA ) / datumA ) ;
256
- addDatum ( result . all , d , percent ) ;
257
- if ( filtered [ testCase ] ) {
258
- addDatum ( result . filtered , d , percent ) ;
259
- }
260
- }
261
-
262
- const computeAvg = ( result ) => {
263
- result . improvements_avg /= Math . max ( result . improvements , 1 ) ;
264
- result . regressions_avg /= Math . max ( result . regressions , 1 ) ;
265
- result . average /= Math . max ( result . regressions + result . improvements + result . unchanged , 1 ) ;
266
- } ;
267
- computeAvg ( result . all ) ;
268
- computeAvg ( result . filtered ) ;
269
-
270
- return result ;
271
-
226
+ // Returns summary of currently filtered data
227
+ filteredSummary ( ) {
228
+ return computeSummary ( this . testCases ) ;
272
229
} ,
273
230
benchmarkMap ( ) {
274
231
if ( ! this . data ) return { } ;
@@ -289,12 +246,6 @@ const app = Vue.createApp({
289
246
prLink ( pr ) {
290
247
return `https://github.com/rust-lang/rust/pull/${ pr } ` ;
291
248
} ,
292
- signIfPositive ( pct ) {
293
- if ( pct >= 0 ) {
294
- return "+" ;
295
- }
296
- return "" ;
297
- } ,
298
249
diffClass ( diff ) {
299
250
let klass = "" ;
300
251
if ( diff > 1 ) {
@@ -433,6 +384,86 @@ app.component('test-cases-table', {
433
384
</div>
434
385
`
435
386
} ) ;
387
+
388
+ const SummaryPercentValue = {
389
+ props : {
390
+ value : Number ,
391
+ padWidth : {
392
+ type : Number ,
393
+ default : null
394
+ }
395
+ } ,
396
+ template : `
397
+ <span><span v-html="padSpaces" />{{ formattedValue }}%</span>
398
+ ` ,
399
+ computed : {
400
+ formattedValue ( ) {
401
+ return `${ this . signIfPositive ( this . value ) } ${ this . value . toFixed ( 2 ) } ` ;
402
+ } ,
403
+ padSpaces ( ) {
404
+ let value = this . formattedValue ;
405
+ if ( value . length < this . padWidth ) {
406
+ return " " . repeat ( this . padWidth - value . length ) ;
407
+ }
408
+ return "" ;
409
+ }
410
+ }
411
+ } ;
412
+ const SummaryRange = {
413
+ props : {
414
+ range : Array ,
415
+ } ,
416
+ template : `
417
+ <div v-if="range.length > 0">
418
+ [<SummaryPercentValue :value="range[0]" :padWidth="6" />, <SummaryPercentValue :value="range[1]" :padWidth="6" />]
419
+ </div>
420
+ <div v-else>-</div>
421
+ ` , components : { SummaryPercentValue}
422
+ } ;
423
+ const SummaryCount = {
424
+ props : {
425
+ cases : Number ,
426
+ benchmarks : Number
427
+ } ,
428
+ template : `
429
+ <span :title="cases + ' test case(s), ' + benchmarks + ' unique benchmark(s)'">{{ cases }} ({{ benchmarks }})</span>
430
+ `
431
+ } ;
432
+
433
+ app . component ( 'summary-table' , {
434
+ props : [ 'cases' ] ,
435
+ template : `
436
+ <table class="summary-table">
437
+ <thead>
438
+ <th><!-- icon --></th>
439
+ <th>Range</th>
440
+ <th>Mean</th>
441
+ <th>Count</th>
442
+ </thead>
443
+ <tbody>
444
+ <tr class="positive">
445
+ <td title="Regresions">❌</td>
446
+ <td><SummaryRange :range="cases.regressions.range" /></td>
447
+ <td><SummaryPercentValue :value="cases.regressions.average" /></td>
448
+ <td><SummaryCount :cases="cases.regressions.count" :benchmarks="cases.regressions.benchmarks" /></td>
449
+ </tr>
450
+ <tr class="negative">
451
+ <td title="Improvements">✅</td>
452
+ <td><SummaryRange :range="cases.improvements.range" /></td>
453
+ <td><SummaryPercentValue :value="cases.improvements.average" /></td>
454
+ <td><SummaryCount :cases="cases.improvements.count" :benchmarks="cases.improvements.benchmarks" /></td>
455
+ </tr>
456
+ <tr>
457
+ <td title="All changes">❌,✅</td>
458
+ <td><SummaryRange :range="cases.all.range" /></td>
459
+ <td><SummaryPercentValue :value="cases.all.average" /></td>
460
+ <td><SummaryCount :cases="cases.all.count" :benchmarks="cases.all.benchmarks" /></td>
461
+ </tr>
462
+ </tbody>
463
+ </table>
464
+ ` ,
465
+ components : { SummaryRange, SummaryPercentValue, SummaryCount}
466
+ } ) ;
436
467
app . mixin ( {
437
468
methods : {
438
469
percentClass ( pct ) {
@@ -448,6 +479,12 @@ app.mixin({
448
479
}
449
480
return klass ;
450
481
} ,
482
+ signIfPositive ( pct ) {
483
+ if ( pct >= 0 ) {
484
+ return "+" ;
485
+ }
486
+ return "" ;
487
+ } ,
451
488
}
452
489
} ) ;
453
490
@@ -470,6 +507,69 @@ function testCaseString(testCase) {
470
507
return testCase . benchmark + "-" + testCase . profile + "-" + testCase . scenario ;
471
508
}
472
509
510
+ /**
511
+ * Computes summaries of improvements, regressions and all changes from the given `comparisons`.
512
+ * Returns a dictionary {improvements, regressions, all}.
513
+ */
514
+ function computeSummary ( testCases ) {
515
+ const regressions = {
516
+ values : [ ] ,
517
+ benchmarks : new Set ( ) ,
518
+ } ;
519
+ const improvements = {
520
+ values : [ ] ,
521
+ benchmarks : new Set ( ) ,
522
+ } ;
523
+ const all = {
524
+ values : [ ] ,
525
+ benchmarks : new Set ( ) ,
526
+ } ;
527
+
528
+ const handleTestCase = ( items , testCase ) => {
529
+ items . benchmarks . add ( testCase . benchmark ) ;
530
+ items . values . push ( testCase . percent ) ;
531
+ } ;
532
+
533
+ for ( const testCase of testCases ) {
534
+ if ( testCase . percent > 0 ) {
535
+ handleTestCase ( regressions , testCase ) ;
536
+ } else if ( testCase . percent < 0 ) {
537
+ handleTestCase ( improvements , testCase ) ;
538
+ }
539
+ handleTestCase ( all , testCase ) ;
540
+ }
541
+
542
+ const computeSummary = ( data ) => {
543
+ const values = data . values ;
544
+ const benchmarks = data . benchmarks ;
545
+
546
+ const count = values . length ;
547
+ let range = [ ] ;
548
+ if ( count > 0 ) {
549
+ range = [
550
+ Math . min . apply ( null , values ) ,
551
+ Math . max . apply ( null , values ) ,
552
+ ] ;
553
+ }
554
+
555
+ const sum = values . reduce ( ( acc , item ) => acc + item , 0 ) ;
556
+ const average = sum / Math . max ( count , 1 ) ;
557
+
558
+ return {
559
+ count,
560
+ benchmarks : benchmarks . size ,
561
+ average,
562
+ range,
563
+ }
564
+ } ;
565
+
566
+ return {
567
+ improvements : computeSummary ( improvements ) ,
568
+ regressions : computeSummary ( regressions ) ,
569
+ all : computeSummary ( all )
570
+ } ;
571
+ }
572
+
473
573
function unique ( arr ) {
474
574
return arr . filter ( ( value , idx ) => arr . indexOf ( value ) == idx ) ;
475
575
}
0 commit comments