From cfad77a0fd6098f7617ab91dd78750e392337052 Mon Sep 17 00:00:00 2001 From: Lucas Resch Date: Tue, 5 Dec 2023 19:15:55 +0100 Subject: [PATCH] 2023-05: ~8.9x speedup through parallelization Needed to split up the time ranges into batches for this to work. Will take up 100% of CPU for >25s on a pretty good rig. Still not optimized enough, but not unexpected for such a naive implementation. --- 2023-rust/Cargo.lock | 81 +++++++++++++++++++++++++++++++++++++++++ 2023-rust/Cargo.toml | 1 + 2023-rust/README.md | 12 +++--- 2023-rust/src/bin/05.rs | 44 ++++++++++++++++------ 4 files changed, 121 insertions(+), 17 deletions(-) diff --git a/2023-rust/Cargo.lock b/2023-rust/Cargo.lock index bdc08bb..78dfc80 100644 --- a/2023-rust/Cargo.lock +++ b/2023-rust/Cargo.lock @@ -8,6 +8,7 @@ version = "0.9.3" dependencies = [ "itertools", "pico-args", + "rayon", "regex", ] @@ -20,6 +21,51 @@ dependencies = [ "memchr", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + [[package]] name = "either" version = "1.9.0" @@ -41,12 +87,41 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "pico-args" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "regex" version = "1.10.2" @@ -75,3 +150,9 @@ name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" diff --git a/2023-rust/Cargo.toml b/2023-rust/Cargo.toml index f43ec78..71ca834 100644 --- a/2023-rust/Cargo.toml +++ b/2023-rust/Cargo.toml @@ -16,4 +16,5 @@ test_lib = [] [dependencies] itertools = "0.12.0" pico-args = "0.5.0" +rayon = "1.8.0" regex = "1.10.2" diff --git a/2023-rust/README.md b/2023-rust/README.md index 7520678..c34ec55 100644 --- a/2023-rust/README.md +++ b/2023-rust/README.md @@ -9,13 +9,13 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www. | Day | Part 1 | Part 2 | | :---: | :---: | :---: | -| [Day 1](./src/bin/01.rs) | `64.7µs` | `659.1µs` | -| [Day 2](./src/bin/02.rs) | `41.4µs` | `48.5µs` | -| [Day 3](./src/bin/03.rs) | `467.4µs` | `428.0µs` | -| [Day 4](./src/bin/04.rs) | `95.3µs` | `19.7ms` | -| [Day 5](./src/bin/05.rs) | `31.2µs` | `236.6s` | +| [Day 1](./src/bin/01.rs) | `63.6µs` | `634.3µs` | +| [Day 2](./src/bin/02.rs) | `41.3µs` | `47.2µs` | +| [Day 3](./src/bin/03.rs) | `429.8µs` | `421.7µs` | +| [Day 4](./src/bin/04.rs) | `97.3µs` | `19.2ms` | +| [Day 5](./src/bin/05.rs) | `30.3µs` | `26.5s` | -**Total: 236.62s** +**Total: 26520.97ms** ## Usage diff --git a/2023-rust/src/bin/05.rs b/2023-rust/src/bin/05.rs index d79da15..9d33e80 100644 --- a/2023-rust/src/bin/05.rs +++ b/2023-rust/src/bin/05.rs @@ -1,6 +1,10 @@ -use std::collections::{HashMap, VecDeque}; +use std::{ + collections::{HashMap, VecDeque}, + time::SystemTime, +}; use itertools::Itertools; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; advent_of_code::solution!(5); @@ -48,20 +52,38 @@ fn solve_part_one(seeds: Vec, maps: &Vec>) -> O pub fn part_two(input: &str) -> Option { let (seeds, maps) = parse_input(input); - let mut min: u64 = std::u64::MAX; + let max_seed_range_length = 10_000_000; + let mut seed_ranges: Vec<(u64, u64)> = Vec::new(); for mut chunk in &seeds.iter().chunks(2) { - let start = chunk.next().unwrap(); - let length = chunk.next().unwrap(); - let current_seeds = (*start..*start + *length).collect_vec(); - - let current_min = solve_part_one(current_seeds, &maps).unwrap(); - println!("{start}-{length}, current min: {current_min}, last min: {min}"); - if current_min < min { - min = current_min; + let mut start = *chunk.next().unwrap(); + let length = *chunk.next().unwrap(); + let stop = start + length; + + loop { + if start + max_seed_range_length < stop { + seed_ranges.push((start, start + max_seed_range_length)); + start += max_seed_range_length; + } else { + seed_ranges.push((start, stop)); + break; + } } } - Some(min) + seed_ranges + .into_par_iter() + .filter_map(|(start, stop)| { + let timer = SystemTime::now(); + let current_seeds = (start..stop).collect_vec(); + let result = solve_part_one(current_seeds, &maps); + println!( + "[{start}-{stop}] in {:?} => {:?}", + timer.elapsed().unwrap(), + result + ); + result + }) + .min() } fn find_map_entry(map: &HashMap, value: u64) -> Option {