bench with multithreading
cargo devel CI / cargo CI (push) Successful in 1m46s Details

This commit is contained in:
Christoph J. Scherr 2024-04-05 10:04:57 +02:00
parent 966f73efef
commit 88d388807f
Signed by: PlexSheep
GPG Key ID: 7CDD0B14851A08EF
5 changed files with 27 additions and 13 deletions

View File

@ -29,6 +29,7 @@ clap = { version = "4.5.3", features = ["derive"], optional = true }
colored = { version = "2.1.0", optional = false } colored = { version = "2.1.0", optional = false }
libpt = "0.4.2" libpt = "0.4.2"
rand = "0.8.5" rand = "0.8.5"
rayon = "1.10.0"
regex = "1.10.3" regex = "1.10.3"
serde = { version = "1.0.197", optional = true, features = ["serde_derive"] } serde = { version = "1.0.197", optional = true, features = ["serde_derive"] }
serde_json = { version = "1.0.114", optional = true } serde_json = { version = "1.0.114", optional = true }

View File

@ -1,6 +1,8 @@
use std::fmt::{Debug, Display}; use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use libpt::log::debug; use libpt::log::debug;
use rayon::prelude::*;
use crate::error::WResult; use crate::error::WResult;
use crate::game::response::GuessResponse; use crate::game::response::GuessResponse;
@ -17,7 +19,7 @@ pub mod builtin;
/// Default amount of games to play for a [Benchmark] /// Default amount of games to play for a [Benchmark]
pub const DEFAULT_N: usize = 50; pub const DEFAULT_N: usize = 50;
pub trait Benchmark<'wl, WL, SL>: Clone + Sized + Debug pub trait Benchmark<'wl, WL, SL>: Clone + Sized + Debug + Sync
where where
WL: WordList, WL: WordList,
WL: 'wl, WL: 'wl,
@ -40,21 +42,26 @@ where
// TODO: add some interface to get reports while the benchmark runs // TODO: add some interface to get reports while the benchmark runs
// TODO: make the benchmark optionally multithreaded // TODO: make the benchmark optionally multithreaded
fn bench(&'wl self, n: usize) -> WResult<Report> { fn bench(&'wl self, n: usize) -> WResult<Report> {
// PERF: it would be better to make this multithreaded
let part = match n / 20 { let part = match n / 20 {
0 => 19, 0 => 19,
other => other, other => other,
}; };
let mut report = Report::new(); let report = Arc::new(Mutex::new(Report::new()));
let this = std::sync::Arc::new(self);
for i in 0..n { (0..n)
report.add(self.play()?); .into_par_iter()
if i % part == part - 1 { .for_each_with(report.clone(), |outside_data, _i| {
// TODO: add the report to the struct so that users can poll it to print the status let report = outside_data;
// TODO: update the report in the struct let r = this
} .play()
} .expect("error playing the game during benchmark");
report.lock().expect("lock is poisoned").add(r);
});
// FIXME: find some way to take the Report from the Mutex
// Mutex::into_inner() does not work
let mut report: Report = report.lock().unwrap().clone();
report.finalize(); report.finalize();
Ok(report) Ok(report)

View File

@ -1,5 +1,6 @@
use thiserror::Error; use thiserror::Error;
use crate::bench::report::Report;
use crate::wlist::word::Word; use crate::wlist::word::Word;
pub type WResult<T> = std::result::Result<T, Error>; pub type WResult<T> = std::result::Result<T, Error>;
@ -25,6 +26,11 @@ pub enum Error {
#[from] #[from]
source: regex::Error, source: regex::Error,
}, },
#[error("Error sharing the benchmark data over multiple threads")]
Mutex {
#[from]
source: std::sync::PoisonError<Report>
}
} }
#[derive(Debug, Clone, Error)] #[derive(Debug, Clone, Error)]

View File

@ -37,7 +37,7 @@ pub use stupid::StupidSolver;
/// ///
/// If you want to have the user select a model, create an enum with it's variants containing your /// If you want to have the user select a model, create an enum with it's variants containing your
/// [Solvers][Solver] and have this enum implement [Solver], see [AnyBuiltinSolver]. /// [Solvers][Solver] and have this enum implement [Solver], see [AnyBuiltinSolver].
pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized { pub trait Solver<'wl, WL: WordList>: Clone + std::fmt::Debug + Sized + Sync {
/// Build and initialize a [Solver] /// Build and initialize a [Solver]
fn build(wordlist: &'wl WL) -> WResult<Self>; fn build(wordlist: &'wl WL) -> WResult<Self>;
/// Calculate the next guess for a [Game] /// Calculate the next guess for a [Game]

View File

@ -15,7 +15,7 @@ use crate::error::WResult;
pub type AnyWordlist = Box<dyn WordList>; pub type AnyWordlist = Box<dyn WordList>;
pub trait WordList: Clone + std::fmt::Debug + Default { pub trait WordList: Clone + std::fmt::Debug + Default + Sync {
fn solutions(&self) -> ManyWordDatas { fn solutions(&self) -> ManyWordDatas {
let wmap = self.wordmap().clone(); let wmap = self.wordmap().clone();
let threshold = wmap.threshold(); let threshold = wmap.threshold();