binius_utils/rayon/
config.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use cfg_if::cfg_if;
4
5use super::{ThreadPoolBuildError, current_num_threads};
6
7/// In case when number of threads is set to 1, use rayon thread pool with
8/// `use_current_thread` set to true. This is solves two problems:
9/// 1. The performance is almost the same as if rayon wasn't used at all
10/// 2. Makes profiling and debugging results less noisy
11///
12/// NOTE: rayon doesn't allow initializing global thread pool several times, so
13/// in case when it was initialized before this function returns an error.
14/// The typical usage of the function is to place it's call in the beginning of the `main`.
15/// The function returns reference to the result because `ThreadPoolBuildError`
16/// doesn't implement `Clone`.
17pub fn adjust_thread_pool() -> &'static Result<(), ThreadPoolBuildError> {
18	cfg_if! {
19		if #[cfg(feature = "rayon")] {
20			use std::sync::OnceLock;
21
22			static ONCE_GUARD: OnceLock<Result<(), ThreadPoolBuildError>> = OnceLock::new();
23
24			ONCE_GUARD.get_or_init(|| {
25				// We cannot use `binius_maybe_rayon::get_current_threads` because it would force the global thread pool
26				// to initialize, so we won't be able to override it.
27				match std::env::var("RAYON_NUM_THREADS") {
28					Ok(v) if v == "1" => super::ThreadPoolBuilder::new()
29						.num_threads(1)
30						.use_current_thread()
31						.build_global(),
32					_ => Ok(()),
33				}
34			})
35		}
36		else {
37			static RESULT: Result<(), ThreadPoolBuildError> = Ok(());
38
39			&RESULT
40		}
41	}
42}
43
44/// Returns the base-2 logarithm of the number of threads that should be used for the task
45pub fn get_log_max_threads() -> usize {
46	(2 * current_num_threads() - 1).ilog2() as _
47}