From 84d133cad5915793c886c5a9ff34014bb69dc76c Mon Sep 17 00:00:00 2001 From: Juniper Tyree Date: Sun, 26 May 2024 16:04:51 +0000 Subject: [PATCH] Integrate threads partitioning with rustcoalescence --- Cargo.lock | 1 + README.md | 1 + docs/simulate.ron | 13 +++++++++ rustcoalescence/Cargo.toml | 7 +++++ .../src/args/config/partitioning.rs | 27 ++++++++++--------- .../simulate/dispatch/valid/partitioning.rs | 22 +++++++++++++-- .../src/cli/simulate/dispatch/valid/rng.rs | 8 ++++-- rustcoalescence/src/cli/simulate/mod.rs | 2 +- 8 files changed, 63 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f594996f1..73ddd3aa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1663,6 +1663,7 @@ dependencies = [ "necsim-partitioning-core", "necsim-partitioning-monolithic", "necsim-partitioning-mpi", + "necsim-partitioning-threads", "necsim-plugins-core", "ron", "rustcoalescence-algorithms", diff --git a/README.md b/README.md index 5075156e3..db03861a9 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ necsim-rust consists of the following crates: - core/: `necsim-partitioning-core` declares the core partitioning traits - monolithic/: `necsim-partitioning-monolithic` implements monolithic, i.e. non-parallel partitioning - mpi/: `necsim-partitioning-mpi` implements the MPI-based partitioning backend + - threads/: `necsim-partitioning-threads` implements the multithreading partitioning backend - rustcoalescence/: `rustcoalescence` provides the command-line interface. - scenarios/: `rustcoalescence-scenarios` contains the glue code to put together the cogs for the built-in scenarios. It is specifically built only for reducing code duplication in rustcoalescence, not for giving a minimal example of how to construct a simulation. - algorithms/: diff --git a/docs/simulate.ron b/docs/simulate.ron index a56667b88..e3f19cfe5 100644 --- a/docs/simulate.ron +++ b/docs/simulate.ron @@ -676,6 +676,19 @@ * optional, default = "100ms" */ progress: (DurationString), ) + /* the simulation is divided up across multiple threads + * multi-threaded, single-process + * requires the `threads-partitioning` feature */ + | Threads( + /* number of threads to distribute the simulation across */ + threads: (1 < u32), + /* minimum time interval between migration messages + * optional, default = "100ms" */ + migration: (DurationString), + /* minimum time interval between progress messages + * optional, default = "100ms" */ + progress: (DurationString), + ) ), /* selection of the event persistence strategy diff --git a/rustcoalescence/Cargo.toml b/rustcoalescence/Cargo.toml index 2215b6e02..64778e42d 100644 --- a/rustcoalescence/Cargo.toml +++ b/rustcoalescence/Cargo.toml @@ -56,6 +56,12 @@ all-scenarios = [ ] mpi-partitioning = ["dep:necsim-partitioning-mpi"] +threads-partitioning = ["dep:necsim-partitioning-threads"] + +all-partitioning = [ + "mpi-partitioning", + "threads-partitioning", +] [dependencies] necsim-core = { path = "../necsim/core" } @@ -70,6 +76,7 @@ rustcoalescence-scenarios = { path = "scenarios" } rustcoalescence-algorithms = { path = "algorithms" } necsim-partitioning-mpi = { path = "../necsim/partitioning/mpi", optional = true } +necsim-partitioning-threads = { path = "../necsim/partitioning/threads", optional = true } rustcoalescence-algorithms-gillespie = { path = "algorithms/gillespie", optional = true } rustcoalescence-algorithms-independent = { path = "algorithms/independent", optional = true } diff --git a/rustcoalescence/src/args/config/partitioning.rs b/rustcoalescence/src/args/config/partitioning.rs index 1a33a0130..8dbf81ea1 100644 --- a/rustcoalescence/src/args/config/partitioning.rs +++ b/rustcoalescence/src/args/config/partitioning.rs @@ -5,42 +5,43 @@ use necsim_partitioning_core::partition::PartitionSize; #[derive(Debug, Serialize, Deserialize)] pub enum Partitioning { Monolithic(necsim_partitioning_monolithic::MonolithicPartitioning), - #[cfg(feature = "necsim-partitioning-mpi")] + #[cfg(feature = "mpi-partitioning")] #[serde(alias = "MPI")] Mpi(necsim_partitioning_mpi::MpiPartitioning), + #[cfg(feature = "threads-partitioning")] + Threads(necsim_partitioning_threads::ThreadsPartitioning), } impl Partitioning { - // pub fn is_root(&self) -> bool { - // use necsim_partitioning_core::Partitioning; - - // match self { - // Self::Monolithic(partitioning) => partitioning.is_root(), - // #[cfg(feature = "necsim-partitioning-mpi")] - // Self::Mpi(partitioning) => partitioning.is_root(), - // } - // } - pub fn get_size(&self) -> PartitionSize { use necsim_partitioning_core::Partitioning; match self { Self::Monolithic(partitioning) => partitioning.get_size(), - #[cfg(feature = "necsim-partitioning-mpi")] + #[cfg(feature = "mpi-partitioning")] Self::Mpi(partitioning) => partitioning.get_size(), + #[cfg(feature = "threads-partitioning")] + Self::Threads(partitioning) => partitioning.get_size(), } } pub fn get_event_log_check(&self) -> (anyhow::Result<()>, anyhow::Result<()>) { match self { Self::Monolithic(_) => (Ok(()), Ok(())), - #[cfg(feature = "necsim-partitioning-mpi")] + #[cfg(feature = "mpi-partitioning")] Self::Mpi(_) => ( Err(anyhow::anyhow!( necsim_partitioning_mpi::MpiLocalPartitionError::MissingEventLog )), Ok(()), ), + #[cfg(feature = "threads-partitioning")] + Self::Threads(_) => ( + Err(anyhow::anyhow!( + necsim_partitioning_mpi::MpiLocalPartitionError::MissingEventLog + )), + Ok(()), + ), } } } diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/partitioning.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/partitioning.rs index b29c66451..a0dcf4e4d 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/partitioning.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/partitioning.rs @@ -7,7 +7,7 @@ use necsim_impls_std::event_log::recorder::EventLogRecorder; use necsim_partitioning_core::{context::ReporterContext, LocalPartition, Partitioning as _}; use necsim_partitioning_monolithic::MonolithicLocalPartition; -#[cfg(feature = "necsim-partitioning-mpi")] +#[cfg(feature = "mpi-partitioning")] use necsim_partitioning_mpi::MpiLocalPartition; use rustcoalescence_algorithms::{result::SimulationOutcome, Algorithm, AlgorithmDispatch}; use rustcoalescence_scenarios::Scenario; @@ -83,7 +83,7 @@ where }, fold, ), - #[cfg(feature = "necsim-partitioning-mpi")] + #[cfg(feature = "mpi-partitioning")] Partitioning::Mpi(partitioning) => partitioning.with_local_partition( reporter_context, event_log, @@ -116,6 +116,24 @@ where }, fold, ), + #[cfg(feature = "threads-partitioning")] + Partitioning::Threads(partitioning) => partitioning.with_local_partition( + reporter_context, + event_log, + args, + |partition, (sample, rng, scenario, algorithm_args, pause_before, normalised_args)| { + wrap::, O, R, _>( + partition, + sample, + rng, + scenario, + algorithm_args, + pause_before, + normalised_args, + ) + }, + fold, + ), } .and_then(|result| result.map_err(anyhow::Error::msg)) } diff --git a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs index 5683360a9..fcb448271 100644 --- a/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs +++ b/rustcoalescence/src/cli/simulate/dispatch/valid/rng.rs @@ -59,8 +59,12 @@ where Partitioning::Monolithic(partitioning) => { A::get_logical_partition_size(&algorithm_args, partitioning) }, - #[cfg(feature = "necsim-partitioning-mpi")] - Partitioning::MPI(partitioning) => { + #[cfg(feature = "mpi-partitioning")] + Partitioning::Mpi(partitioning) => { + A::get_logical_partition_size(&algorithm_args, partitioning) + }, + #[cfg(feature = "threads-partitioning")] + Partitioning::Threads(partitioning) => { A::get_logical_partition_size(&algorithm_args, partitioning) }, }, diff --git a/rustcoalescence/src/cli/simulate/mod.rs b/rustcoalescence/src/cli/simulate/mod.rs index 58128f524..604f8c0ce 100644 --- a/rustcoalescence/src/cli/simulate/mod.rs +++ b/rustcoalescence/src/cli/simulate/mod.rs @@ -36,7 +36,7 @@ pub fn simulate_with_logger(simulate_args: CommandArgs) -> anyhow::Result<()> { let partitioning = parse::partitioning::parse_and_normalise(&ron_args, &mut normalised_args)?; - #[cfg(feature = "necsim-partitioning-mpi")] + #[cfg(feature = "mpi-partitioning")] if let crate::args::config::partitioning::Partitioning::Mpi(partitioning) = &partitioning { // Only log to stdout/stderr in the MPI root partition if !partitioning.peek_is_root() {