use std::sync::{PoisonError, RwLock};
use crate::{Backend, Precision};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct AutoThresholds {
pub parallel_min_points: usize,
pub gpu_min_points: usize,
pub gpu_f32_min_points: usize,
}
impl AutoThresholds {
pub const DEFAULT: Self = Self { parallel_min_points: 65_536, gpu_min_points: usize::MAX, gpu_f32_min_points: usize::MAX };
#[must_use]
pub const fn new(parallel_min_points: usize, gpu_min_points: usize) -> Self {
Self { parallel_min_points, gpu_min_points, gpu_f32_min_points: gpu_min_points }
}
#[must_use]
pub const fn with_gpu_f32(mut self, gpu_f32_min_points: usize) -> Self {
self.gpu_f32_min_points = gpu_f32_min_points;
self
}
#[must_use]
pub const fn gpu_min_points_for(&self, precision: Precision) -> usize {
match precision {
Precision::F64 => self.gpu_min_points,
Precision::F32 => self.gpu_f32_min_points,
}
}
}
impl Default for AutoThresholds {
fn default() -> Self {
Self::DEFAULT
}
}
static THRESHOLDS: RwLock<AutoThresholds> = RwLock::new(AutoThresholds::DEFAULT);
#[must_use]
pub fn auto_thresholds() -> AutoThresholds {
*THRESHOLDS.read().unwrap_or_else(PoisonError::into_inner)
}
pub fn set_auto_thresholds(thresholds: AutoThresholds) {
*THRESHOLDS.write().unwrap_or_else(PoisonError::into_inner) = thresholds;
}
#[cfg(test)]
thread_local! {
pub static FORCE_GPU: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
}
pub fn choose(points: usize, precision: Precision) -> Backend {
#[cfg(test)]
if FORCE_GPU.get() {
return Backend::Gpu;
}
let t = auto_thresholds();
if points >= t.gpu_min_points_for(precision) && crate::gpu::ready(precision) {
Backend::Gpu
} else if points >= t.parallel_min_points {
Backend::Parallel
} else {
Backend::Cpu
}
}