summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--2018/src/benchmark.rs78
-rw-r--r--2018/src/main.rs18
2 files changed, 82 insertions, 14 deletions
diff --git a/2018/src/benchmark.rs b/2018/src/benchmark.rs
new file mode 100644
index 0000000..76de9e4
--- /dev/null
+++ b/2018/src/benchmark.rs
@@ -0,0 +1,78 @@
+use std::fmt;
+use std::time::{Instant, Duration};
+
+const MIN_DUR: f64 = 1.0;
+const MIN_TIMES: usize = 4;
+
+pub struct Bench {
+ pub executions: usize,
+ pub duration: f64,
+ pub duration_stddev: f64,
+}
+
+impl fmt::Display for Bench {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} secs ± {} ({}%)",
+ self.duration, self.duration_stddev, self.duration_stddev / self.duration * 100.0)
+ }
+}
+
+fn duration_secs(d: Duration) -> f64 {
+ d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9
+}
+
+// Returns estimate of single-iteration time
+fn warmup<A, F: Fn() -> A>(func: F) -> f64 {
+ let mut ntimes = 1;
+ let mut time_taken = 0.0;
+
+ while time_taken < 0.5 {
+ let start = Instant::now();
+ for _ in 0..ntimes {
+ func();
+ }
+ let end = Instant::now();
+ time_taken = duration_secs(end - start);
+
+ ntimes *= 2;
+ }
+
+ time_taken / ntimes as f64
+}
+
+pub fn benchmark<A, F: Fn() -> A>(func: F) -> Bench {
+ let estimate = warmup(&func);
+ let ntimes_guess = if MIN_TIMES as f64 * estimate >= MIN_DUR {
+ MIN_TIMES
+ } else {
+ (MIN_DUR / estimate).ceil() as usize
+ };
+
+ let nparts = if ntimes_guess < 10 {
+ ntimes_guess
+ } else {
+ std::cmp::max(10, ntimes_guess / 10)
+ };
+ let nperpart = (ntimes_guess + nparts - 1) / nparts;
+
+ let ntimes = nparts * nperpart;
+
+ // eprintln!("BENCH: estimate={} ntimes_guess={} nparts={} nperpart={} ntimes={}", estimate, ntimes_guess, nparts, nperpart, ntimes);
+
+ let mut times = vec![0.0; nparts];
+
+ for i in 0..nparts {
+ let start = Instant::now();
+ for _ in 0..nperpart {
+ func();
+ }
+ let end = Instant::now();
+
+ times[i] = duration_secs(end - start);
+ }
+
+ let mean = times.iter().map(|&t| t).sum::<f64>() / ntimes as f64;
+ let stddev = times.iter().map(|t| (t - mean) * (t - mean)).sum::<f64>() / (ntimes - 1) as f64;
+
+ Bench { executions: 0, duration: mean, duration_stddev: stddev }
+}
diff --git a/2018/src/main.rs b/2018/src/main.rs
index 447005e..3e44615 100644
--- a/2018/src/main.rs
+++ b/2018/src/main.rs
@@ -2,7 +2,6 @@ use std::io;
use std::io::{BufRead, BufReader, Error, ErrorKind, Read};
use std::fs::File;
use std::process::exit;
-use std::time::Instant;
use argparse::{ArgumentParser, StoreTrue, Store};
mod day1;
@@ -19,6 +18,7 @@ mod day11;
mod day12;
mod day13;
mod day14;
+mod benchmark;
static NUM_DAYS: i32 = 14;
@@ -50,23 +50,13 @@ fn file_for_day(day: i32) -> io::Result<BufReader<File>> {
}
fn benchmark_day(day: i32) -> io::Result<f64> {
- let num_iters = 100;
-
let mut input = Vec::new();
file_for_day(day)?.read_to_end(&mut input)?;
- let start = Instant::now();
- for _i in 0..num_iters {
- day_switch(day, BufReader::new(&input[..]))?;
- }
- let end = Instant::now();
-
- let dur = (end - start) / num_iters;
- let secs = dur.as_secs() as f64 + dur.subsec_micros() as f64 / 1000000.0;
-
- println!("Day {}: {} secs", day, secs);
+ let res = benchmark::benchmark(|| day_switch(day, BufReader::new(&input[..])).unwrap());
+ println!("Day {}: {}", day, res);
- Ok(secs)
+ Ok(res.duration)
}
fn benchmark_all_days() -> io::Result<()> {