@@ -163,19 +163,36 @@ async fn populate_report(
163
163
}
164
164
}
165
165
166
+ /// A summary of a given comparison
167
+ ///
168
+ /// This summary only includes changes that are significant and relevant (as determined by a changes magnitude).
166
169
pub struct ComparisonSummary {
167
170
/// Significant comparisons of magnitude small and above
168
171
/// and ordered by magnitude from largest to smallest
169
172
comparisons : Vec < TestResultComparison > ,
173
+ /// The cached number of comparisons that are improvements
174
+ num_improvements : usize ,
175
+ /// The cached number of comparisons that are regressions
176
+ num_regressions : usize ,
170
177
}
171
178
172
179
impl ComparisonSummary {
173
180
pub fn summarize_comparison ( comparison : & Comparison ) -> Option < ComparisonSummary > {
181
+ let mut num_improvements = 0 ;
182
+ let mut num_regressions = 0 ;
183
+
174
184
let mut comparisons = comparison
175
185
. statistics
176
186
. iter ( )
177
187
. filter ( |c| c. is_significant ( ) )
178
188
. filter ( |c| c. magnitude ( ) . is_small_or_above ( ) )
189
+ . inspect ( |c| {
190
+ if c. is_improvement ( ) {
191
+ num_improvements += 1 ;
192
+ } else {
193
+ num_regressions += 1
194
+ }
195
+ } )
179
196
. cloned ( )
180
197
. collect :: < Vec < _ > > ( ) ;
181
198
// Skip empty commits, sometimes happens if there's a compiler bug or so.
@@ -191,18 +208,15 @@ impl ComparisonSummary {
191
208
} ;
192
209
comparisons. sort_by ( cmp) ;
193
210
194
- Some ( ComparisonSummary { comparisons } )
195
- }
196
-
197
- /// Gets the overall direction and magnitude of the changes
198
- ///
199
- /// Returns `None` if there are no relevant changes.
200
- pub fn direction_and_magnitude ( & self ) -> Option < ( Direction , Magnitude ) > {
201
- self . direction ( ) . zip ( self . magnitude ( ) )
211
+ Some ( ComparisonSummary {
212
+ comparisons,
213
+ num_improvements,
214
+ num_regressions,
215
+ } )
202
216
}
203
217
204
218
/// The direction of the changes
205
- fn direction ( & self ) -> Option < Direction > {
219
+ pub fn direction ( & self ) -> Option < Direction > {
206
220
if self . comparisons . len ( ) == 0 {
207
221
return None ;
208
222
}
@@ -258,17 +272,18 @@ impl ComparisonSummary {
258
272
}
259
273
}
260
274
261
- /// Get the largest magnitude of any change in the comparison.
262
- ///
263
- /// Returns `None` if there are no relevant_changes
264
- fn magnitude ( & self ) -> Option < Magnitude > {
265
- [ self . largest_improvement ( ) , self . largest_regression ( ) ]
266
- . iter ( )
267
- . filter_map ( |c| c . map ( |c| c . magnitude ( ) ) )
268
- . max_by ( |c1 , c2| c1 . cmp ( c2 ) )
275
+ /// The number of improvements that were found to be significant and relevant
276
+ pub fn number_of_improvements ( & self ) -> usize {
277
+ self . num_improvements
278
+ }
279
+
280
+ /// The number of regressions that were found to be significant and relevant
281
+ pub fn number_of_regressions ( & self ) -> usize {
282
+ self . num_regressions
269
283
}
270
284
271
- pub fn relevant_changes < ' a > ( & ' a self ) -> [ Option < & TestResultComparison > ; 2 ] {
285
+ /// The most relevant changes (based on size)
286
+ pub fn most_relevant_changes < ' a > ( & ' a self ) -> [ Option < & TestResultComparison > ; 2 ] {
272
287
match self . direction ( ) {
273
288
Some ( Direction :: Improvement ) => [ self . largest_improvement ( ) , None ] ,
274
289
Some ( Direction :: Regression ) => [ self . largest_regression ( ) , None ] ,
@@ -277,6 +292,35 @@ impl ComparisonSummary {
277
292
}
278
293
}
279
294
295
+ /// The average improvement as a percent
296
+ pub fn average_improvement ( & self ) -> f64 {
297
+ self . average ( self . improvements ( ) )
298
+ }
299
+
300
+ /// The average regression as a percent
301
+ pub fn average_regression ( & self ) -> f64 {
302
+ self . average ( self . regressions ( ) )
303
+ }
304
+
305
+ fn average < ' a > ( & ' a self , changes : impl Iterator < Item = & ' a TestResultComparison > ) -> f64 {
306
+ let mut count = 0 ;
307
+ let mut sum = 0.0 ;
308
+ for r in changes {
309
+ sum += r. relative_change ( ) ;
310
+ count += 1 ;
311
+ }
312
+
313
+ ( sum / count as f64 ) * 100.0
314
+ }
315
+
316
+ fn improvements ( & self ) -> impl Iterator < Item = & TestResultComparison > {
317
+ self . comparisons . iter ( ) . filter ( |c| c. is_improvement ( ) )
318
+ }
319
+
320
+ fn regressions ( & self ) -> impl Iterator < Item = & TestResultComparison > {
321
+ self . comparisons . iter ( ) . filter ( |c| c. is_regression ( ) )
322
+ }
323
+
280
324
fn largest_improvement ( & self ) -> Option < & TestResultComparison > {
281
325
self . comparisons . iter ( ) . find ( |s| s. is_improvement ( ) )
282
326
}
@@ -322,10 +366,7 @@ impl ComparisonSummary {
322
366
let end = & comparison. b . artifact ;
323
367
let link = & compare_link ( start, end) ;
324
368
325
- for change in self . relevant_changes ( ) . iter ( ) . filter_map ( |s| * s) {
326
- write ! ( result, "- " ) . unwrap ( ) ;
327
- change. summary_line ( & mut result, Some ( link) )
328
- }
369
+ self . write_summary_lines ( & mut result, Some ( link) ) ;
329
370
330
371
if !comparison. new_errors . is_empty ( ) {
331
372
write ! (
@@ -343,6 +384,30 @@ impl ComparisonSummary {
343
384
344
385
result
345
386
}
387
+
388
+ pub fn write_summary_lines ( & self , result : & mut String , link : Option < & str > ) {
389
+ use std:: fmt:: Write ;
390
+ if self . num_regressions > 1 {
391
+ writeln ! (
392
+ result,
393
+ "- Average relevant regression: {:.1}%" ,
394
+ self . average_regression( )
395
+ )
396
+ . unwrap ( ) ;
397
+ }
398
+ if self . num_improvements > 1 {
399
+ writeln ! (
400
+ result,
401
+ "- Average relevant improvement: {:.1}%" ,
402
+ self . average_improvement( )
403
+ )
404
+ . unwrap ( ) ;
405
+ }
406
+ for change in self . most_relevant_changes ( ) . iter ( ) . filter_map ( |s| * s) {
407
+ write ! ( result, "- " ) . unwrap ( ) ;
408
+ change. summary_line ( result, link)
409
+ }
410
+ }
346
411
}
347
412
348
413
/// The amount of confidence we have that a comparison actually represents a real
@@ -884,11 +949,12 @@ impl TestResultComparison {
884
949
!self . is_regression ( )
885
950
}
886
951
887
- fn is_significant ( & self ) -> bool {
952
+ /// Whther the comparison yielded a statistically significant result
953
+ pub fn is_significant ( & self ) -> bool {
888
954
self . relative_change ( ) . abs ( ) >= self . significance_threshold ( )
889
955
}
890
956
891
- // Magnitude of change considered significant
957
+ /// Magnitude of change considered significant
892
958
fn significance_threshold ( & self ) -> f64 {
893
959
if !self . calc_new_sig {
894
960
if self . is_dodgy ( ) {
@@ -984,24 +1050,19 @@ impl TestResultComparison {
984
1050
985
1051
pub fn summary_line ( & self , summary : & mut String , link : Option < & str > ) {
986
1052
use std:: fmt:: Write ;
987
- let magnitude = self . magnitude ( ) ;
988
-
989
1053
let percent = self . relative_change ( ) * 100.0 ;
990
- write ! (
1054
+ writeln ! (
991
1055
summary,
992
- "{} {} in {}" ,
993
- magnitude. display_as_title( ) ,
1056
+ "Largest {} in {}: {:.1}% on `{}` builds of `{} {}`" ,
994
1057
self . direction( ) ,
995
1058
match link {
996
1059
Some ( l) => format!( "[instruction counts]({})" , l) ,
997
1060
None => "instruction counts" . into( ) ,
998
- }
999
- )
1000
- . unwrap ( ) ;
1001
- writeln ! (
1002
- summary,
1003
- " (up to {:.1}% on `{}` builds of `{} {}`)" ,
1004
- percent, self . scenario, self . benchmark, self . profile
1061
+ } ,
1062
+ percent,
1063
+ self . scenario,
1064
+ self . benchmark,
1065
+ self . profile
1005
1066
)
1006
1067
. unwrap ( ) ;
1007
1068
}
@@ -1063,16 +1124,6 @@ impl Magnitude {
1063
1124
* self >= Self :: Medium
1064
1125
}
1065
1126
1066
- pub fn display_as_title ( & self ) -> & ' static str {
1067
- match self {
1068
- Self :: VerySmall => "Very small" ,
1069
- Self :: Small => "Small" ,
1070
- Self :: Medium => "Moderate" ,
1071
- Self :: Large => "Large" ,
1072
- Self :: VeryLarge => "Very large" ,
1073
- }
1074
- }
1075
-
1076
1127
pub fn display ( & self ) -> & ' static str {
1077
1128
match self {
1078
1129
Self :: VerySmall => "very small" ,
0 commit comments