binaries!

This commit is contained in:
nora 2023-12-03 13:58:31 +01:00
parent 13ac9a70ce
commit 5dff963dc2
8 changed files with 286 additions and 69 deletions

View file

@ -4,27 +4,27 @@ benchmarks:
Ensure that `input.txt` contains many, many copies of the actual input, the actual input is way too small.
`cargo build --release && hyperfine 'target/release/day1 naive' 'target/release/day1 zero_alloc' 'target/release/day1 branchless' 'target/release/day1 vectorized'`
`cargo build --release && hyperfine 'target/release/day1 part2 naive' 'target/release/day1 part2 zero_alloc' 'target/release/day1 part2 branchless' 'target/release/day1 part2 vectorized'`
```
Benchmark 1: target/release/day1 naive
Time (mean ± σ): 4.735 s ± 0.061 s [User: 4.663 s, System: 0.072 s]
Range (min … max): 4.643 s … 4.798 s 10 runs
Benchmark 1: target/release/day1 part2 naive
Time (mean ± σ): 1.066 s ± 0.017 s [User: 1.048 s, System: 0.018 s]
Range (min … max): 1.049 s … 1.099 s 10 runs
Benchmark 2: target/release/day1 zero_alloc
Time (mean ± σ): 880.1 ms ± 10.7 ms [User: 807.9 ms, System: 72.1 ms]
Range (min … max): 858.3 ms … 891.4 ms 10 runs
Benchmark 2: target/release/day1 part2 zero_alloc
Time (mean ± σ): 212.7 ms ± 3.5 ms [User: 195.0 ms, System: 17.6 ms]
Range (min … max): 206.9 ms … 219.0 ms 14 runs
Benchmark 3: target/release/day1 branchless
Time (mean ± σ): 587.1 ms ± 4.4 ms [User: 515.0 ms, System: 72.1 ms]
Range (min … max): 578.3 ms … 594.1 ms 10 runs
Benchmark 3: target/release/day1 part2 branchless
Time (mean ± σ): 137.2 ms ± 1.8 ms [User: 117.5 ms, System: 19.6 ms]
Range (min … max): 133.5 ms … 142.2 ms 21 runs
Benchmark 4: target/release/day1 vectorized
Time (mean ± σ): 394.3 ms ± 5.2 ms [User: 322.2 ms, System: 71.9 ms]
Range (min … max): 386.4 ms … 400.0 ms 10 runs
Benchmark 4: target/release/day1 part2 vectorized
Time (mean ± σ): 87.9 ms ± 0.9 ms [User: 68.6 ms, System: 19.1 ms]
Range (min … max): 86.5 ms … 90.6 ms 33 runs
Summary
target/release/day1 vectorized ran
1.49 ± 0.02 times faster than target/release/day1 branchless
2.23 ± 0.04 times faster than target/release/day1 zero_alloc
12.01 ± 0.22 times faster than target/release/day1 naive
target/release/day1 part2 vectorized ran
1.56 ± 0.03 times faster than target/release/day1 part2 branchless
2.42 ± 0.05 times faster than target/release/day1 part2 zero_alloc
12.13 ± 0.22 times faster than target/release/day1 part2 naive
```

View file

@ -9,30 +9,7 @@ mod vectorized;
mod zero_alloc;
fn main() {
let kind = std::env::args().nth(1).unwrap_or("naive".into());
let mut input = std::hint::black_box(include_str!("../input.txt")).to_owned();
input.reserve(10); // enough to read u64
unsafe {
input
.as_mut_vec()
.spare_capacity_mut()
.fill(MaybeUninit::new(0))
};
match kind.as_str() {
"part1" => part1(&input),
"naive" => naive::part2(&input),
"zero_alloc" => zero_alloc::part2(&input),
"branchless" => unsafe { branchless::part2(&input) },
"no_lines" => unsafe { no_lines::part2(&input) },
"vectorized" => unsafe { vectorized::part2(&input) },
_ => {
eprintln!("error: invalid mode, must be part1,naive,zero_alloc,branchless");
std::process::exit(1);
}
};
helper::main::<Day1>(include_str!("../input.txt"));
}
struct Day1;

View file

@ -9,20 +9,7 @@ use nom::{
};
fn main() {
let kind = std::env::args().nth(1).unwrap_or("naive".into());
let input = std::hint::black_box(include_str!("../input.txt")).to_owned();
let result = match kind.as_str() {
"part1" => part1(&input),
"part2" => part2(&input),
_ => {
eprintln!("error: invalid mode, must be part1");
std::process::exit(1);
}
};
println!("result: {result}");
helper::main::<Day2>(include_str!("../input.txt"));
}
struct Day2;

View file

@ -3,20 +3,7 @@ use std::collections::HashMap;
use helper::{Day, Variants};
fn main() {
let kind = std::env::args().nth(1).unwrap_or("naive".into());
let input = std::hint::black_box(include_str!("../input.txt")).to_owned();
let result = match kind.as_str() {
"part1" => part1(&input),
"part2" => part2(&input),
_ => {
eprintln!("error: invalid mode, must be part1");
std::process::exit(1);
}
};
println!("result: {result}");
helper::main::<Day3>(include_str!("../input.txt"));
}
struct Day3;

160
Cargo.lock generated
View file

@ -2,6 +2,87 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "clap"
version = "4.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fffed7514f420abec6d183b1d3acfd9099c79c3a10a06ade4f8203f1411272"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63361bae7eef3771745f02d8d892bec2fee5f6e34af316ba556e7f97a7069ff1"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "day1"
version = "0.1.0"
@ -29,6 +110,7 @@ dependencies = [
name = "helper"
version = "0.1.0"
dependencies = [
"clap",
"nom",
]
@ -53,3 +135,81 @@ dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -6,4 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.4.10", features = ["string"] }
nom.workspace = true

101
helper/src/cmd.rs Normal file
View file

@ -0,0 +1,101 @@
use std::{borrow::Cow, process};
use clap::{Arg, ArgMatches, Command};
use crate::{Day, Variant};
pub fn main<D: Day>(default_input: &str) -> ! {
let mut part1 = Command::new("part1").about("Runs the part 1 program");
let mut part2 = Command::new("part2").about("Runs the part 2 program");
part1 = create_variant_subcommands(part1, &D::part1().variants);
part2 = create_variant_subcommands(part2, &D::part2().variants);
let mut typename = std::any::type_name::<D>().split("::").collect::<Vec<_>>();
let typename = typename.pop().unwrap();
let cmd = Command::new(typename.to_lowercase())
.about(format!(
"Program to run the AOC answer for day {}",
typename.strip_prefix("Day").unwrap()
))
.subcommand_required(true)
.subcommand(part1)
.subcommand(part2);
let matches = cmd.clone().get_matches();
match matches.subcommand() {
Some(("part1", matches)) => {
let variants = D::part1().variants;
dispatch_root_subcommand::<D>(default_input, &variants, matches);
}
Some(("part2", matches)) => {
let variants = D::part2().variants;
dispatch_root_subcommand::<D>(default_input, &variants, matches);
}
_ => {
unreachable!("subcommand_required")
}
}
}
fn create_variant_subcommands(mut part: Command, variants: &[Variant]) -> Command {
if variants.len() > 1 {
part = part.subcommand_required(true);
variants
.iter()
.map(|v| {
Command::new(v.name)
.about(format!("Run the {} variant", v.name))
.arg(Arg::new("input").short('i').long("input"))
})
.for_each(|cmd| part = part.clone().subcommand(cmd));
} else {
part = part.arg(Arg::new("input").short('i').long("input"));
}
part
}
fn dispatch_root_subcommand<D: Day>(
default_input: &str,
variants: &[Variant],
matches: &ArgMatches,
) -> ! {
if variants.len() > 1 {
let subcommand = matches.subcommand().unwrap();
let variant = variants.iter().find(|v| v.name == subcommand.0).unwrap();
let input = get_input(subcommand.1, default_input);
execute::<D>(variant, &input);
} else {
let input = get_input(matches, default_input);
execute::<D>(&variants[0], &input);
}
}
fn execute<D: Day>(variant: &Variant, input: &str) -> ! {
use std::io::Write;
let input = D::pad_input(input);
let result = (variant.f)(&input);
let err = write!(std::io::stdout(), "{result}\n");
if let Err(err) = err {
if err.kind() != std::io::ErrorKind::BrokenPipe {
eprintln!("error: {err}");
process::exit(1);
}
}
process::exit(0);
}
fn get_input<'a>(matches: &ArgMatches, default: &'a str) -> Cow<'a, str> {
matches
.get_one::<String>("input")
.map(|input| {
Cow::Owned(std::fs::read_to_string(input).unwrap_or_else(|err| {
eprintln!("error: failed to read file {input}: {err}");
process::exit(1);
}))
})
.unwrap_or(Cow::Borrowed(default))
}

View file

@ -1,7 +1,11 @@
mod cmd;
use std::borrow::Cow;
use nom::{character::complete::digit1, combinator::map, IResult};
pub use self::cmd::main;
pub type Solution = fn(&str) -> u64;
pub trait Day {