@@ -114,7 +114,7 @@ pub async fn handle_compare(
114
114
scenario : comparison. scenario . to_string ( ) ,
115
115
is_dodgy : comparison. is_dodgy ( ) ,
116
116
is_significant : comparison. is_significant ( ) ,
117
- significance_threshold : comparison. signifcance_threshold ( ) * 100.0 ,
117
+ significance_factor : comparison. significance_factor ( ) ,
118
118
historical_statistics : comparison. variance . map ( |v| v. data ) ,
119
119
statistics : comparison. results ,
120
120
} )
@@ -658,7 +658,30 @@ impl BenchmarkVariance {
658
658
deltas
659
659
}
660
660
661
- fn upper_fence ( & self ) -> f64 {
661
+ // This is an absolute value indicating the noise barrier for changes on
662
+ // this benchmark.
663
+ //
664
+ // A number line could be divded like this:
665
+ //
666
+ // ------o-------o----------
667
+ // ^ ^ ^
668
+ // | | |
669
+ // | | |
670
+ // | | ---- +significance_threshold
671
+ // | |
672
+ // | - not significant, includes zero
673
+ // |
674
+ // ---- -significance_threshold()
675
+ fn significance_threshold ( & self ) -> f64 {
676
+ let ( q1, median, q3) = self . quartiles ( ) ;
677
+
678
+ // Changes that are IQR_MULTIPLIER away from the median are considered
679
+ // significant (i.e. outliers).
680
+ median + ( q3 - q1) * Self :: IQR_MULTIPLIER
681
+ }
682
+
683
+ // (q1, q2=median, q3)
684
+ fn quartiles ( & self ) -> ( f64 , f64 , f64 ) {
662
685
let pcs = self . percent_changes ( ) ;
663
686
fn median ( data : & [ f64 ] ) -> f64 {
664
687
if data. len ( ) % 2 == 0 {
@@ -674,12 +697,11 @@ impl BenchmarkVariance {
674
697
} else {
675
698
( len / 2 - 1 , len / 2 + 1 )
676
699
} ;
677
- // significance is determined by the upper
678
- // interquartile range fence
679
700
let q1 = median ( & pcs[ ..=h1_end] ) ;
701
+ let q2 = median ( & pcs[ ..] ) ;
680
702
let q3 = median ( & pcs[ h2_begin..] ) ;
681
- let iqr = q3 - q1 ;
682
- q3 + ( iqr * Self :: IQR_MULTIPLIER )
703
+
704
+ ( q1 , q2 , q3 )
683
705
}
684
706
685
707
fn calculate_description ( & mut self ) {
@@ -727,7 +749,9 @@ impl BenchmarkVariance {
727
749
BenchmarkVarianceDescription :: Noisy | BenchmarkVarianceDescription :: HighlyVariable
728
750
)
729
751
} else {
730
- self . upper_fence ( ) > 0.002
752
+ // If changes are judged significant only exceeding 0.2%, then the
753
+ // benchmark as a whole is dodgy.
754
+ self . significance_threshold ( ) * 100.0 > 0.2
731
755
}
732
756
}
733
757
}
@@ -805,10 +829,11 @@ impl TestResultComparison {
805
829
}
806
830
807
831
fn is_significant ( & self ) -> bool {
808
- self . relative_change ( ) . abs ( ) > self . signifcance_threshold ( )
832
+ self . relative_change ( ) . abs ( ) >= self . significance_threshold ( )
809
833
}
810
834
811
- fn signifcance_threshold ( & self ) -> f64 {
835
+ // Magnitude of change considered significant
836
+ fn significance_threshold ( & self ) -> f64 {
812
837
if !self . calc_new_sig {
813
838
if self . is_dodgy ( ) {
814
839
Self :: SIGNIFICANT_RELATIVE_CHANGE_THRESHOLD_DODGY
@@ -818,14 +843,22 @@ impl TestResultComparison {
818
843
} else {
819
844
self . variance
820
845
. as_ref ( )
821
- . map ( |s| s . upper_fence ( ) )
846
+ . map ( |v| v . significance_threshold ( ) )
822
847
. unwrap_or ( Self :: SIGNIFICANT_RELATIVE_CHANGE_THRESHOLD )
823
848
}
824
849
}
825
850
851
+ /// This is a numeric magnitude of a particular change.
852
+ fn significance_factor ( & self ) -> Option < f64 > {
853
+ let change = self . relative_change ( ) ;
854
+ let threshold = self . significance_threshold ( ) ;
855
+ // How many times the treshold this change is.
856
+ Some ( change. abs ( ) / threshold)
857
+ }
858
+
826
859
fn magnitude ( & self ) -> Magnitude {
827
860
let change = self . relative_change ( ) . abs ( ) ;
828
- let threshold = self . signifcance_threshold ( ) ;
861
+ let threshold = self . significance_threshold ( ) ;
829
862
let over_threshold = if change < threshold * 1.5 {
830
863
Magnitude :: VerySmall
831
864
} else if change < threshold * 3.0 {
0 commit comments