switchyard/
threads.rs

1//! Helper functions for creating iterators of [`ThreadAllocationOutput`] for spawning on the [`Switchyard`](crate::Switchyard).
2
3/// Information about threads on the system
4// TODO: Detect and expose big.LITTLE
5#[derive(Debug, Clone, PartialEq)]
6pub struct ThreadAllocationInput {
7    /// Amount of physical cores in the system.
8    pub physical: usize,
9    /// Amount of logical cores in the system. Must be greater than `physical`.
10    pub logical: usize,
11}
12
13/// Spawn information for a worker thread.
14#[derive(Debug, Clone, PartialEq)]
15pub struct ThreadAllocationOutput {
16    /// Name.
17    pub name: Option<String>,
18    /// Identifier.
19    pub ident: usize,
20    /// Size of spawned thread's stack. Will use system default if `None`.
21    pub stack_size: Option<usize>,
22    /// Core index to pin thread to. If a platform doesn't support affinity, will have
23    /// no effect. Currently only windows and linux support affinities.
24    pub affinity: Option<usize>,
25}
26
27/// System thread information to pass into other functions in this module.
28pub fn thread_info() -> ThreadAllocationInput {
29    ThreadAllocationInput {
30        logical: num_cpus::get(),
31        physical: num_cpus::get_physical(),
32    }
33}
34
35/// A single thread configuration.
36///
37/// - Creates a single thread.
38pub fn single_thread(
39    thread_name: Option<String>,
40    affinity: Option<usize>,
41) -> impl Iterator<Item = ThreadAllocationOutput> {
42    std::iter::once(ThreadAllocationOutput {
43        name: thread_name,
44        ident: 0,
45        stack_size: None,
46        affinity,
47    })
48}
49
50/// A single thread per core configuration.
51///
52/// - One thread per logical core.
53/// - Each thread assigned to a different core.
54///
55/// `input` is the result of calling [`thread_info`].
56#[allow(clippy::needless_lifetimes)]
57pub fn one_to_one<'a>(
58    input: ThreadAllocationInput,
59    thread_name: Option<&'a str>,
60) -> impl Iterator<Item = ThreadAllocationOutput> + 'a {
61    (0..input.logical).map(move |idx| ThreadAllocationOutput {
62        name: thread_name.map(ToOwned::to_owned),
63        ident: idx,
64        stack_size: None,
65        affinity: Some(idx),
66    })
67}
68
69/// A two thread per core, single pool thread configuration.
70///
71/// - Two threads per logical core.
72/// - Each set of two threads assigned to a different core.
73///
74/// `input` is the result of calling [`thread_info`].
75#[allow(clippy::needless_lifetimes)]
76pub fn two_to_one<'a>(
77    input: ThreadAllocationInput,
78    thread_name: Option<&'a str>,
79) -> impl Iterator<Item = ThreadAllocationOutput> + 'a {
80    (0..(input.logical * 2)).map(move |idx| ThreadAllocationOutput {
81        name: thread_name.map(ToOwned::to_owned),
82        ident: idx,
83        stack_size: None,
84        affinity: Some(idx / 2),
85    })
86}