From 8441cb2fdeb70bbafdd4159cc609744459e1d247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sp=C3=B6ttel?= <1682504+fspoettel@users.noreply.github.com> Date: Wed, 29 Dec 2021 19:14:40 +0100 Subject: [PATCH] feat: add `total` timing --- README.md | 17 +++++++++- scripts/scaffold.sh | 4 +-- src/lib.rs | 83 ++++++++++++++++++++++++++++++++++++++++++--- src/main.rs | 45 ++++++++++++++---------- 4 files changed, 123 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index cc97d6d..29904e7 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,25 @@ cargo run --bin To run an optimized version for benchmarking, use the `--release` flag or the alias `cargo rr --bin `. -### Run all solutions +### Run solutions for all days ```sh cargo run + +# output: +# Running `target/release/aoc` +# ---------- +# | Day 01 | +# ---------- +# ๐ŸŽ„ Part 1 ๐ŸŽ„ +# +# 0 (elapsed: 170.00ยตs) +# +# ๐ŸŽ„ Part 2 ๐ŸŽ„ +# +# 0 (elapsed: 30.00ยตs) +# <...other days...> +# Total: 0.20ms ``` To run an optimized version for benchmarking, use the `--release` flag or the alias `cargo rr`. diff --git a/scripts/scaffold.sh b/scripts/scaffold.sh index aeb73ca..05b2ee6 100755 --- a/scripts/scaffold.sh +++ b/scripts/scaffold.sh @@ -19,8 +19,6 @@ module_path="src/bin/$filename.rs"; touch $module_path; cat > $module_path < u32 { 0 } @@ -30,7 +28,7 @@ pub fn part_two(input: &str) -> u32 { } fn main() { - solve_day!(&read_file("inputs", DAYNUM), part_one, part_two) + aoc::solve!(&aoc::read_file("inputs", DAYNUM), part_one, part_two) } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index bf1e997..c6e5548 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,12 @@ use std::env; use std::fs; -pub static ANSI_ITALIC: &str = "\x1b[3m"; -pub static ANSI_BOLD: &str = "\x1b[1m"; -pub static ANSI_RESET: &str = "\x1b[0m"; +pub const ANSI_ITALIC: &str = "\x1b[3m"; +pub const ANSI_BOLD: &str = "\x1b[1m"; +pub const ANSI_RESET: &str = "\x1b[0m"; #[macro_export] -macro_rules! solve_day { +macro_rules! solve { ($input:expr, $part_one:ident, $part_two:ident) => {{ use aoc::{ANSI_BOLD, ANSI_ITALIC, ANSI_RESET}; use std::fmt::Display; @@ -40,3 +40,78 @@ pub fn read_file(folder: &str, day: u8) -> String { let f = fs::read_to_string(filepath); f.expect("could not open input file") } + +fn parse_time(val: &str, postfix: &str) -> f64 { + val.split(postfix).next().unwrap().parse().unwrap() +} + +pub fn parse_exec_time(output: &str) -> f64 { + output.lines().fold(0_f64, |acc, l| { + if !l.contains("elapsed:") { + acc + } else { + let timing = l + .split("(elapsed: ") + .last() + .unwrap(); + + // see [rust/library/core/src/time.rs](https://git.io/Jy1rI) + if timing.ends_with("ns)") { + acc // range below rounding precision. + } else if timing.ends_with("ยตs)") { + acc + parse_time(timing, "ยตs") / 1000_f64 + } else if timing.ends_with("ms)") { + acc + parse_time(timing, "ms") + } else if timing.ends_with("s)") { + acc + parse_time(timing, "s") * 1000_f64 + } else { + acc + } + } + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// copied from: [rust/library/std/src/macros.rs](https://git.io/Jy1r7) + macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ + let (a, b) = (&$a, &$b); + assert!( + (*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", + *a, + *b + ); + }}; + } + + #[test] + fn test_parse_exec_time() { + assert_approx_eq!( + parse_exec_time( + "๐ŸŽ„ Part 1 ๐ŸŽ„\n0 (elapsed: 74.13ns)\n๐ŸŽ„ Part 2 ๐ŸŽ„\n0 (elapsed: 50.00ns)" + ), + 0_f64 + ); + + assert_approx_eq!( + parse_exec_time("๐ŸŽ„ Part 1 ๐ŸŽ„\n0 (elapsed: 755ยตs)\n๐ŸŽ„ Part 2 ๐ŸŽ„\n0 (elapsed: 700ยตs)"), + 1.455_f64 + ); + + assert_approx_eq!( + parse_exec_time("๐ŸŽ„ Part 1 ๐ŸŽ„\n0 (elapsed: 70ยตs)\n๐ŸŽ„ Part 2 ๐ŸŽ„\n0 (elapsed: 1.45ms)"), + 1.52_f64 + ); + + assert_approx_eq!( + parse_exec_time( + "๐ŸŽ„ Part 1 ๐ŸŽ„\n0 (elapsed: 10.3s)\n๐ŸŽ„ Part 2 ๐ŸŽ„\n0 (elapsed: 100.50ms)" + ), + 10400.50_f64 + ); + } +} diff --git a/src/main.rs b/src/main.rs index fb92954..540279e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,35 @@ -use aoc::{ANSI_BOLD, ANSI_RESET}; +use aoc::{ANSI_BOLD, ANSI_ITALIC, ANSI_RESET}; use std::process::Command; fn main() { - (1..=25).for_each(|day| { - let day = format!("{:02}", day); + let total: f64 = (1..=25) + .map(|day| { + let day = format!("{:02}", day); - let cmd = Command::new("cargo") - .args(&["run", "--release", "--bin", &day]) - .output() - .unwrap(); + let cmd = Command::new("cargo") + .args(&["run", "--release", "--bin", &day]) + .output() + .unwrap(); - let output = String::from_utf8(cmd.stdout).unwrap(); - println!("----------"); - println!("{}| Day {} |{}", ANSI_BOLD, day, ANSI_RESET); - println!("----------"); - println!( - "{}", - if !output.is_empty() { - output + println!("----------"); + println!("{}| Day {} |{}", ANSI_BOLD, day, ANSI_RESET); + println!("----------"); + + let output = String::from_utf8(cmd.stdout).unwrap(); + let is_empty = output.is_empty(); + + println!("{}", if is_empty { "Not solved." } else { &output }); + + if is_empty { + 0_f64 } else { - "Not solved.".to_string() + aoc::parse_exec_time(&output) } - ); - }); + }) + .sum(); + + println!( + "{}Total:{} {}{:.2}ms{}", + ANSI_BOLD, ANSI_RESET, ANSI_ITALIC, total, ANSI_RESET + ); }