1#![allow(clippy::allow_attributes, reason = "Needed for conditional compilation")]
7
8#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
13pub enum MemoryAffinity {
14 Unknown,
16 Pinned(PinnedAffinity),
18}
19
20impl From<PinnedAffinity> for MemoryAffinity {
21 fn from(pinned: PinnedAffinity) -> Self {
22 Self::Pinned(pinned)
23 }
24}
25
26impl MemoryAffinity {
27 #[must_use]
29 pub const fn unknown() -> Self {
30 Self::Unknown
31 }
32
33 #[must_use]
35 pub const fn is_unknown(self) -> bool {
36 matches!(self, Self::Unknown)
37 }
38}
39
40#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
42pub struct PinnedAffinity {
43 processor_index: u16,
44 memory_region_index: u16,
45
46 processor_count: u16,
47 memory_region_count: u16,
48}
49
50impl PinnedAffinity {
51 #[must_use]
53 pub(crate) const fn new(processor_index: u16, memory_region_index: u16, processor_count: u16, memory_region_count: u16) -> Self {
54 Self {
55 processor_index,
56 memory_region_index,
57 processor_count,
58 memory_region_count,
59 }
60 }
61
62 #[must_use]
64 pub const fn processor_index(self) -> usize {
65 self.processor_index as _
66 }
67
68 #[must_use]
70 pub const fn memory_region_index(self) -> usize {
71 self.memory_region_index as _
72 }
73
74 #[must_use]
76 pub const fn processor_count(self) -> usize {
77 self.processor_count as _
78 }
79
80 #[must_use]
82 pub const fn memory_region_count(self) -> usize {
83 self.memory_region_count as _
84 }
85}
86
87#[must_use]
97#[expect(clippy::needless_range_loop, reason = "clearer in this case")]
98pub fn pinned_affinities(counts: &[usize]) -> Vec<PinnedAffinity> {
99 let numa_count = counts.len();
100 let core_count = counts.iter().sum();
101 let mut affinities = Vec::with_capacity(core_count);
102 let mut processor_index = 0;
103
104 for numa_index in 0..numa_count {
105 for _ in 0..counts[numa_index] {
106 affinities.push(PinnedAffinity::new(
107 processor_index.try_into().expect("Too many processors"),
108 numa_index.try_into().expect("Too many memory regions"),
109 core_count.try_into().expect("Too many processors"),
110 numa_count.try_into().expect("Too many memory regions"),
111 ));
112 processor_index += 1;
113 }
114 }
115
116 affinities
117}
118
119#[must_use]
131pub fn memory_affinities(counts: &[usize]) -> Vec<MemoryAffinity> {
132 pinned_affinities(counts).into_iter().map(MemoryAffinity::Pinned).collect()
133}
134
135#[cfg(test)]
136mod tests {
137 use super::{MemoryAffinity, PinnedAffinity};
138
139 #[test]
140 fn test_pinned_affinity() {
141 let affinity = PinnedAffinity::new(2, 1, 4, 2);
142
143 assert_eq!(affinity.processor_index(), 2);
144 assert_eq!(affinity.processor_count(), 4);
145
146 assert_eq!(affinity.memory_region_index(), 1);
147 assert_eq!(affinity.memory_region_count(), 2);
148 }
149
150 #[test]
151 fn test_memory_affinity_unknown() {
152 let affinity = MemoryAffinity::unknown();
153 assert!(affinity.is_unknown());
154 }
155
156 #[test]
157 fn test_memory_affinity_pinned() {
158 let affinity = PinnedAffinity::new(2, 1, 4, 2);
159 let affinity = MemoryAffinity::from(affinity);
160 assert!(!affinity.is_unknown());
161 }
162}