18
18
19
19
use getopts;
20
20
use sort;
21
+ use stats;
21
22
use stats:: Stats ;
22
23
use term;
23
24
use time:: precise_time_ns;
24
25
25
26
use std:: comm:: { stream, SharedChan } ;
26
27
use std:: either;
27
28
use std:: io;
28
- use std:: num;
29
29
use std:: option;
30
- use std:: rand:: RngUtil ;
31
- use std:: rand;
32
30
use std:: result;
33
31
use std:: task;
34
32
use std:: to_str:: ToStr ;
35
33
use std:: u64;
36
34
use std:: uint;
37
- use std:: vec;
38
35
39
36
40
37
// The name of a test. By convention this follows the rules for rust
@@ -184,7 +181,7 @@ pub fn parse_opts(args: &[~str]) -> OptRes {
184
181
185
182
#[ deriving( Eq ) ]
186
183
pub struct BenchSamples {
187
- ns_iter_samples : ~ [ f64 ] ,
184
+ ns_iter_summ : stats :: Summary ,
188
185
mb_s : uint
189
186
}
190
187
@@ -299,16 +296,15 @@ pub fn run_tests_console(opts: &TestOpts,
299
296
return success;
300
297
301
298
fn fmt_bench_samples ( bs : & BenchSamples ) -> ~str {
302
- use stats:: Stats ;
303
299
if bs. mb_s != 0 {
304
300
fmt ! ( "%u ns/iter (+/- %u) = %u MB/s" ,
305
- bs. ns_iter_samples . median( ) as uint,
306
- 3 * ( bs. ns_iter_samples . median_abs_dev ( ) as uint) ,
301
+ bs. ns_iter_summ . median as uint,
302
+ ( bs . ns_iter_summ . max - bs. ns_iter_summ . min ) as uint,
307
303
bs. mb_s)
308
304
} else {
309
305
fmt ! ( "%u ns/iter (+/- %u)" ,
310
- bs. ns_iter_samples . median( ) as uint,
311
- 3 * ( bs. ns_iter_samples . median_abs_dev ( ) as uint) )
306
+ bs. ns_iter_summ . median as uint,
307
+ ( bs . ns_iter_summ . max - bs. ns_iter_summ . min ) as uint)
312
308
}
313
309
}
314
310
@@ -688,54 +684,48 @@ impl BenchHarness {
688
684
}
689
685
}
690
686
691
- // This is a more statistics-driven benchmark algorithm.
692
- // It stops as quickly as 50ms , so long as the statistical
693
- // properties are satisfactory. If those properties are
694
- // not met, it may run as long as the Go algorithm.
695
- pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> ~[f64] {
687
+ // This is a more statistics-driven benchmark algorithm. It stops as
688
+ // quickly as 100ms , so long as the statistical properties are
689
+ // satisfactory. If those properties are not met, it may run as long as
690
+ // the Go algorithm.
691
+ pub fn auto_bench(&mut self, f: &fn(&mut BenchHarness)) -> stats::Summary {
696
692
697
- let mut rng = rand::rng();
698
- let mut magnitude = 10;
699
- let mut prev_madp = 0.0;
693
+ let mut magnitude = 1000;
700
694
695
+ let samples : &mut [f64] = [0.0_f64, ..100];
701
696
loop {
702
- let n_samples = rng.gen_uint_range(50, 60);
703
- let n_iter = rng.gen_uint_range(magnitude,
704
- magnitude * 2);
697
+ let loop_start = precise_time_ns();
705
698
706
- let samples = do vec::from_fn(n_samples) |_ | {
707
- self.bench_n(n_iter as u64, |x| f(x));
708
- self.ns_per_iter() as f64
699
+ for samples.mut_iter().advance() |p | {
700
+ self.bench_n(magnitude as u64, |x| f(x));
701
+ *p = self.ns_per_iter() as f64;
709
702
};
710
703
711
- // Eliminate outliers
712
- let med = samples.median();
713
- let mad = samples.median_abs_dev();
714
- let samples = do samples.consume_iter().filter |f| {
715
- num::abs(*f - med) <= 3.0 * mad
716
- }.collect::<~[f64]>();
717
-
718
- debug!(" %u samples, median %f, MAD =%f, %u survived filter",
719
- n_samples, med as float, mad as float,
720
- samples.len());
721
-
722
- if samples.len() != 0 {
723
- // If we have _any_ cluster of signal...
724
- let curr_madp = samples.median_abs_dev_pct();
725
- if self.ns_elapsed() > 1_000_000 &&
726
- (curr_madp < 1.0 ||
727
- num::abs(curr_madp - prev_madp) < 0.1) {
728
- return samples;
729
- }
730
- prev_madp = curr_madp;
704
+ // Clip top 10% and bottom 10% of outliers
705
+ stats::winsorize(samples, 10.0);
706
+ let summ = stats::Summary::new(samples);
731
707
732
- if n_iter > 20_000_000 ||
733
- self.ns_elapsed() > 20_000_000 {
734
- return samples;
735
- }
708
+ debug!(" %u samples, median %f, MAD =%f, MADP =%f",
709
+ samples.len(),
710
+ summ.median as float,
711
+ summ.median_abs_dev as float,
712
+ summ.median_abs_dev_pct as float);
713
+
714
+ let now = precise_time_ns();
715
+ let loop_run = now - loop_start;
716
+
717
+ // Stop early if we have a good signal after a 100ms loop.
718
+ if loop_run > 100_000_000 && summ.median_abs_dev_pct < 5.0 {
719
+ return summ;
720
+ }
721
+
722
+ // Longest we ever run for is 1s.
723
+ if loop_run > 1_000_000_000 {
724
+ return summ;
736
725
}
737
726
738
- magnitude *= 2;
727
+ magnitude *= 3;
728
+ magnitude /= 2;
739
729
}
740
730
}
741
731
}
@@ -752,13 +742,13 @@ pub mod bench {
752
742
bytes: 0
753
743
};
754
744
755
- let ns_iter_samples = bs.auto_bench(f);
745
+ let ns_iter_summ = bs.auto_bench(f);
756
746
757
- let iter_s = 1_000_000_000 / (ns_iter_samples .median() as u64);
747
+ let iter_s = 1_000_000_000 / (ns_iter_summ .median as u64);
758
748
let mb_s = (bs.bytes * iter_s) / 1_000_000;
759
749
760
750
BenchSamples {
761
- ns_iter_samples: ns_iter_samples ,
751
+ ns_iter_summ: ns_iter_summ ,
762
752
mb_s: mb_s as uint
763
753
}
764
754
}
0 commit comments