#[cfg(feature = "rayon")]
use std::sync::OnceLock;
#[cfg(feature = "rayon")]
use rayon::ThreadPoolBuilder;
pub const DEFAULT_PAR_CUTOFF: usize = 4096;
pub fn env_usize(key: &str, default: usize) -> usize {
std::env::var(key)
.ok()
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(default)
}
#[cfg(feature = "rayon")]
static EFFECTIVE_THREADS: OnceLock<usize> = OnceLock::new();
pub fn init_global_rayon_pool(mpi_size: usize) -> usize {
#[cfg(not(feature = "rayon"))]
{
let _ = mpi_size; return 1;
}
#[cfg(feature = "rayon")]
{
*EFFECTIVE_THREADS.get_or_init(|| {
let total = std::env::var("KRYST_THREADS")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.or_else(|| {
std::env::var("RAYON_NUM_THREADS")
.ok()
.and_then(|s| s.parse().ok())
})
.unwrap_or_else(num_cpus::get);
let threads = std::cmp::max(1, total / std::cmp::max(1, mpi_size));
let _ = ThreadPoolBuilder::new().num_threads(threads).build_global();
threads
})
}
}
pub fn init_global_rayon_pool_with_threads(threads: usize) -> usize {
#[cfg(not(feature = "rayon"))]
{
let _ = threads;
return 1;
}
#[cfg(feature = "rayon")]
{
*EFFECTIVE_THREADS.get_or_init(|| {
let threads = std::cmp::max(1, threads);
let _ = ThreadPoolBuilder::new().num_threads(threads).build_global();
threads
})
}
}
pub fn current_rayon_threads() -> usize {
#[cfg(feature = "rayon")]
{
EFFECTIVE_THREADS
.get()
.copied()
.unwrap_or_else(rayon::current_num_threads)
}
#[cfg(not(feature = "rayon"))]
{
1
}
}
pub struct ThreadPoolGuard {
threads: usize,
}
impl ThreadPoolGuard {
pub fn new_per_rank(mpi_size: usize) -> Self {
let threads = init_global_rayon_pool(mpi_size);
Self { threads }
}
pub fn threads(&self) -> usize {
self.threads
}
}