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 }
libpt = "0.4.2"
rand = "0.8.5"
rayon = "1.10.0"
regex = "1.10.3"
serde = { version = "1.0.197", optional = true, features = ["serde_derive"] }
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 rayon::prelude::*;
use crate::error::WResult;
use crate::game::response::GuessResponse;
@ -17,7 +19,7 @@ pub mod builtin;
/// Default amount of games to play for a [Benchmark]
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
WL: WordList,
WL: 'wl,
@ -40,21 +42,26 @@ where
// TODO: add some interface to get reports while the benchmark runs
// TODO: make the benchmark optionally multithreaded
fn bench(&'wl self, n: usize) -> WResult<Report> {
// PERF: it would be better to make this multithreaded
let part = match n / 20 {
0 => 19,
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 {
report.add(self.play()?);
if i % part == part - 1 {
// TODO: add the report to the struct so that users can poll it to print the status
// TODO: update the report in the struct
}
}
(0..n)
.into_par_iter()
.for_each_with(report.clone(), |outside_data, _i| {
let report = outside_data;
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();
Ok(report)

View File

@ -1,5 +1,6 @@
use thiserror::Error;
use crate::bench::report::Report;
use crate::wlist::word::Word;
pub type WResult<T> = std::result::Result<T, Error>;
@ -25,6 +26,11 @@ pub enum Error {
#[from]
source: regex::Error,
},
#[error("Error sharing the benchmark data over multiple threads")]
Mutex {
#[from]
source: std::sync::PoisonError<Report>
}
}
#[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
/// [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]
fn build(wordlist: &'wl WL) -> WResult<Self>;
/// Calculate the next guess for a [Game]

View File

@ -15,7 +15,7 @@ use crate::error::WResult;
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 {
let wmap = self.wordmap().clone();
let threshold = wmap.threshold();