Skip to main content

steel_utils/
threading.rs

1//! Thread-count selection helpers.
2
3use std::num::NonZero;
4use std::thread;
5
6/// Assumed parallelism when `available_parallelism` is unavailable.
7pub const AVAILABLE_PARALLELISM_FALLBACK: usize = 4;
8
9/// Stack size for debug-build threads with deep density-function call chains.
10pub const DEBUG_STACK_SIZE: usize = 8 * 1024 * 1024;
11
12/// Returns the host's available parallelism, or [`AVAILABLE_PARALLELISM_FALLBACK`].
13#[must_use]
14pub fn available_worker_threads() -> usize {
15    thread::available_parallelism().map_or(AVAILABLE_PARALLELISM_FALLBACK, NonZero::get)
16}
17
18/// Caps an explicit positive worker count to available parallelism, or uses
19/// half the available threads with a minimum target of two.
20#[must_use]
21pub fn worker_threads_for_available(
22    configured_threads: Option<usize>,
23    available_threads: usize,
24) -> usize {
25    let available_threads = available_threads.max(1);
26    if let Some(configured_threads) = configured_threads.filter(|&threads| threads > 0) {
27        return configured_threads.min(available_threads);
28    }
29
30    ((available_threads / 2).max(2)).min(available_threads)
31}
32
33#[cfg(test)]
34mod tests {
35    use super::worker_threads_for_available;
36
37    #[test]
38    fn explicit_worker_count_is_capped_to_available_threads() {
39        assert_eq!(worker_threads_for_available(Some(16), 8), 8);
40        assert_eq!(worker_threads_for_available(Some(4), 8), 4);
41    }
42
43    #[test]
44    fn zero_or_missing_worker_count_uses_auto_default() {
45        assert_eq!(worker_threads_for_available(Some(0), 8), 4);
46        assert_eq!(worker_threads_for_available(None, 8), 4);
47        assert_eq!(worker_threads_for_available(None, 1), 1);
48    }
49}