use std::env;
use std::sync::OnceLock;
#[derive(Debug)]
pub struct ThreadPool {
pool: Option<rayon::ThreadPool>,
}
impl ThreadPool {
pub fn run<R: Send, Op: FnOnce() -> R + Send>(&self, op: Op) -> R {
if let Some(pool) = self.pool.as_ref() {
pool.install(op)
} else {
op()
}
}
pub fn with_num_threads(num_threads: usize) -> ThreadPool {
let pool = rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.thread_name(|index| format!("rten-{}", index))
.build();
ThreadPool { pool: pool.ok() }
}
}
fn optimal_core_count() -> u32 {
#[allow(unused_mut)]
let mut core_count = num_cpus::get_physical().max(1) as u32;
#[cfg(target_os = "macos")]
{
use rten_simd::isa_detection::macos::sysctl_int;
if let Ok(perf_core_count) = sysctl_int(c"hw.perflevel0.physicalcpu") {
core_count = core_count.clamp(1, perf_core_count as u32);
}
}
core_count
}
pub fn thread_pool() -> &'static ThreadPool {
static THREAD_POOL: OnceLock<ThreadPool> = OnceLock::new();
THREAD_POOL.get_or_init(|| {
let physical_cpus = optimal_core_count();
let num_threads = if let Some(threads_var) = env::var_os("RTEN_NUM_THREADS") {
let requested_threads: Result<u32, _> = threads_var.to_string_lossy().parse();
match requested_threads {
Ok(n_threads) => n_threads.clamp(1, num_cpus::get() as u32),
Err(_) => physical_cpus,
}
} else {
physical_cpus
};
ThreadPool::with_num_threads(num_threads as usize)
})
}
#[cfg(test)]
mod tests {
use super::optimal_core_count;
#[test]
fn test_optimal_core_count() {
let max_cores = num_cpus::get_physical() as u32;
let opt_cores = optimal_core_count();
assert!(opt_cores >= 1 && opt_cores <= max_cores);
}
}