use std::sync::OnceLock;
static CONTEXT: OnceLock<EngineContext> = OnceLock::new();
pub struct EngineContext {
pub io_threads: usize,
pub compute_threads: usize,
pub bg_concurrency: usize,
#[cfg(feature = "compute")]
pub(crate) compute_pool: rayon::ThreadPool,
#[cfg(feature = "bg")]
pub(crate) bg_semaphore: tokio::sync::Semaphore,
}
impl EngineContext {
fn build() -> Self {
let logical_cores = num_cpus::get();
let io_threads = logical_cores;
let compute_threads = logical_cores.saturating_sub(1).max(1);
let bg_concurrency = (logical_cores / 2).max(2);
#[cfg(feature = "compute")]
let compute_pool = rayon::ThreadPoolBuilder::new()
.num_threads(compute_threads)
.thread_name(|index| format!("mytheclipse-compute-{index}"))
.build()
.expect("mytheclipse: failed to build rayon compute thread pool");
#[cfg(feature = "bg")]
let bg_semaphore = tokio::sync::Semaphore::new(bg_concurrency);
Self {
io_threads,
compute_threads,
bg_concurrency,
#[cfg(feature = "compute")]
compute_pool,
#[cfg(feature = "bg")]
bg_semaphore,
}
}
}
pub fn context() -> &'static EngineContext {
CONTEXT.get_or_init(EngineContext::build)
}
pub fn init() -> &'static EngineContext {
CONTEXT.get_or_init(EngineContext::build)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn context_numbers_are_sane() {
let ctx = context();
assert!(ctx.io_threads >= 1);
assert!(ctx.compute_threads >= 1);
assert!(ctx.bg_concurrency >= 2);
}
}