@@ -219,56 +219,9 @@ const app = Vue.createApp({
219
219
stat ( ) {
220
220
return findQueryParam ( "stat" ) || "instructions:u" ;
221
221
} ,
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
-
222
+ // Returns summary of currently filtered data
223
+ filteredSummary ( ) {
224
+ return computeSummary ( this . testCases ) ;
272
225
} ,
273
226
benchmarkMap ( ) {
274
227
if ( ! this . data ) return { } ;
@@ -289,12 +242,6 @@ const app = Vue.createApp({
289
242
prLink ( pr ) {
290
243
return `https://github.com/rust-lang/rust/pull/${ pr } ` ;
291
244
} ,
292
- signIfPositive ( pct ) {
293
- if ( pct >= 0 ) {
294
- return "+" ;
295
- }
296
- return "" ;
297
- } ,
298
245
diffClass ( diff ) {
299
246
let klass = "" ;
300
247
if ( diff > 1 ) {
@@ -433,6 +380,77 @@ app.component('test-cases-table', {
433
380
</div>
434
381
`
435
382
} ) ;
383
+
384
+ const SummaryPercentValue = {
385
+ props : {
386
+ value : Number ,
387
+ } ,
388
+ template : `
389
+ <span>{{ value.toFixed(2) }}%</span>
390
+ `
391
+ } ;
392
+ const SummaryRange = {
393
+ props : {
394
+ range : Array ,
395
+ } ,
396
+ template : `
397
+ <div v-if="range.length > 0">
398
+ [<SummaryPercentValue :value="range[0]" />, <SummaryPercentValue :value="range[1]" />]
399
+ </div>
400
+ <div v-else>-</div>
401
+ ` , components : { SummaryPercentValue}
402
+ } ;
403
+ const SummaryCount = {
404
+ props : {
405
+ cases : Number ,
406
+ benchmarks : Number
407
+ } ,
408
+ template : `
409
+ <span :title="cases + ' test case(s), ' + benchmarks + ' unique benchmark(s)'">{{ cases }} ({{ benchmarks }})</span>
410
+ `
411
+ } ;
412
+
413
+ app . component ( 'summary-table' , {
414
+ props : [ 'cases' ] ,
415
+ template : `
416
+ <table class="summary-table">
417
+ <thead>
418
+ <th>Range</th>
419
+ <th>Mean</th>
420
+ <th>Count</th>
421
+ <th><!-- icon --></th>
422
+ </thead>
423
+ <tbody>
424
+ <tr class="positive">
425
+ <td><SummaryRange :range="cases.regressions.range" /></td>
426
+ <td><SummaryPercentValue :value="cases.regressions.average" /></td>
427
+ <td><SummaryCount :cases="cases.regressions.count" :benchmarks="cases.regressions.benchmarks" /></td>
428
+ <td>
429
+ <svg style="width:16px;height:16px" viewBox="0 0 24 24">
430
+ <path d="M16,6L18.29,8.29L13.41,13.17L9.41,9.17L2,16.59L3.41,18L9.41,12L13.41,16L19.71,9.71L22,12V6H16Z"></path>
431
+ </svg>
432
+ </td>
433
+ </tr>
434
+ <tr class="negative">
435
+ <td><SummaryRange :range="cases.improvements.range" /></td>
436
+ <td><SummaryPercentValue :value="cases.improvements.average" /></td>
437
+ <td><SummaryCount :cases="cases.improvements.count" :benchmarks="cases.improvements.benchmarks" /></td>
438
+ <td>
439
+ <svg style="width:16px;height:16px" viewBox="0 0 24 24">
440
+ <path d="M16,18L18.29,15.71L13.41,10.83L9.41,14.83L2,7.41L3.41,6L9.41,12L13.41,8L19.71,14.29L22,12V18H16Z"></path>
441
+ </svg>
442
+ </td>
443
+ </tr>
444
+ <tr>
445
+ <td><SummaryRange :range="cases.all.range" /></td>
446
+ <td><SummaryPercentValue :value="cases.all.average" /></td>
447
+ <td><SummaryCount :cases="cases.all.count" :benchmarks="cases.all.benchmarks" /></td>
448
+ </tr>
449
+ </tbody>
450
+ </table>
451
+ ` ,
452
+ components : { SummaryRange, SummaryPercentValue, SummaryCount}
453
+ } ) ;
436
454
app . mixin ( {
437
455
methods : {
438
456
percentClass ( pct ) {
@@ -448,6 +466,12 @@ app.mixin({
448
466
}
449
467
return klass ;
450
468
} ,
469
+ signIfPositive ( pct ) {
470
+ if ( pct >= 0 ) {
471
+ return "+" ;
472
+ }
473
+ return "" ;
474
+ } ,
451
475
}
452
476
} ) ;
453
477
@@ -470,6 +494,72 @@ function testCaseString(testCase) {
470
494
return testCase . benchmark + "-" + testCase . profile + "-" + testCase . scenario ;
471
495
}
472
496
497
+ /**
498
+ * Computes summaries of improvements, regressions and all changes from the given `comparisons`.
499
+ * Returns a dictionary {improvements, regressions, all}.
500
+ */
501
+ function computeSummary ( testCases ) {
502
+ const regressions = {
503
+ values : [ ] ,
504
+ benchmarks : new Set ( ) ,
505
+ } ;
506
+ const improvements = {
507
+ values : [ ] ,
508
+ benchmarks : new Set ( ) ,
509
+ } ;
510
+ const all = {
511
+ values : [ ] ,
512
+ benchmarks : new Set ( ) ,
513
+ } ;
514
+
515
+ const handleTestCase = ( items , testCase ) => {
516
+ items . benchmarks . add ( testCase . benchmark ) ;
517
+ items . values . push ( testCase . percent ) ;
518
+ } ;
519
+
520
+ for ( const testCase of testCases ) {
521
+ if ( testCase . percent > 0 ) {
522
+ handleTestCase ( regressions , testCase ) ;
523
+ } else if ( testCase . percent < 0 ) {
524
+ handleTestCase ( improvements , testCase ) ;
525
+ }
526
+ handleTestCase ( all , testCase ) ;
527
+ }
528
+
529
+ const computeSummary = ( data ) => {
530
+ const values = data . values ;
531
+ const benchmarks = data . benchmarks ;
532
+
533
+ const count = values . length ;
534
+ let range = [ ] ;
535
+ if ( count > 0 ) {
536
+ range = [
537
+ Math . min . apply ( null , values ) ,
538
+ Math . max . apply ( null , values ) ,
539
+ ] ;
540
+ if ( Math . abs ( range [ 0 ] ) > Math . abs ( range [ 1 ] ) ) {
541
+ range = [ range [ 1 ] , range [ 0 ] ] ;
542
+ }
543
+ }
544
+
545
+ const sum = values . reduce ( ( acc , item ) => acc + item , 0 ) ;
546
+ const average = sum / Math . max ( count , 1 ) ;
547
+
548
+ return {
549
+ count,
550
+ benchmarks : benchmarks . size ,
551
+ average,
552
+ range,
553
+ }
554
+ } ;
555
+
556
+ return {
557
+ improvements : computeSummary ( improvements ) ,
558
+ regressions : computeSummary ( regressions ) ,
559
+ all : computeSummary ( all )
560
+ } ;
561
+ }
562
+
473
563
function unique ( arr ) {
474
564
return arr . filter ( ( value , idx ) => arr . indexOf ( value ) == idx ) ;
475
565
}
0 commit comments