1use anyhow::Result;
5use scx_utils::{CoreType, Topology};
6
7pub const MAX_CPUS: usize = 64;
9pub const MAX_LLCS: usize = 8;
11
12#[derive(Debug, Clone)]
14pub struct TopologyInfo {
15 pub nr_cpus: usize,
17
18 pub has_dual_ccd: bool,
20
21 pub has_hybrid_cores: bool,
23
24 pub smt_enabled: bool,
26 pub cpu_sibling_map: [u8; MAX_CPUS],
28
29 pub cpu_llc_id: [u8; MAX_CPUS],
31 pub cpu_is_big: [u8; MAX_CPUS],
32 pub cpu_core_id: [u8; MAX_CPUS],
33 pub cpu_thread_bit: [u8; MAX_CPUS],
34 pub cpu_dsq_id: [u32; MAX_CPUS],
35 pub core_cpu_mask: [u64; 32],
37 pub core_thread_mask: [u8; 32],
39 pub llc_cpu_mask: [u64; MAX_LLCS],
40 pub big_cpu_mask: u64,
41
42 pub cpus_per_ccd: u32,
44}
45
46pub fn detect() -> Result<TopologyInfo> {
47 let topo = Topology::new()?;
49
50 let nr_cpus = topo.all_cpus.len();
51 let nr_llcs = topo.all_llcs.len();
52
53 let siblings = topo.sibling_cpus();
55 let mut cpu_sibling_map = [0u8; MAX_CPUS];
56
57 for (i, sibling) in cpu_sibling_map.iter_mut().enumerate().take(MAX_CPUS) {
59 *sibling = i as u8;
60 }
61
62 for (cpu, &sibling) in siblings.iter().enumerate() {
64 if cpu < MAX_CPUS && sibling >= 0 {
65 let sib = sibling as usize;
66 if sib < MAX_CPUS {
67 cpu_sibling_map[cpu] = sib as u8;
68 }
69 }
70 }
71
72 let mut info = TopologyInfo {
73 nr_cpus,
74 has_dual_ccd: nr_llcs > 1,
75 has_hybrid_cores: false, smt_enabled: topo.smt_enabled,
77 cpu_sibling_map,
78 cpu_llc_id: [0; MAX_CPUS],
79 cpu_is_big: [1; MAX_CPUS], cpu_core_id: [0; MAX_CPUS],
81 cpu_thread_bit: [0; MAX_CPUS],
82 cpu_dsq_id: [0; MAX_CPUS],
83 core_cpu_mask: [0; 32],
84 core_thread_mask: [0; 32],
85 llc_cpu_mask: [0; MAX_LLCS],
86 big_cpu_mask: 0,
87 cpus_per_ccd: 0,
88 };
89
90 let mut llc_idx = 0;
94
95 for llc in topo.all_llcs.values() {
96 if llc_idx >= MAX_LLCS {
97 break;
98 }
99
100 let mut mask = 0u64;
101 let mut core_count = 0;
102
103 for cpu_id in llc.all_cpus.keys() {
104 let cpu = *cpu_id;
105 if cpu < MAX_CPUS {
106 info.cpu_llc_id[cpu] = llc_idx as u8;
107 mask |= 1u64 << cpu;
108 core_count += 1;
109 }
110 }
111
112 info.llc_cpu_mask[llc_idx] = mask;
113 if info.cpus_per_ccd == 0 {
114 info.cpus_per_ccd = core_count;
115 } llc_idx += 1;
118 }
119
120 info.cpu_is_big = [0; MAX_CPUS];
123 info.big_cpu_mask = 0;
124
125 let mut p_cores_found = 0;
126 let mut e_cores_found = 0;
127
128 for (core_id_usize, core) in &topo.all_cores {
129 let core_id = *core_id_usize;
130
131 let is_big = match core.core_type {
135 CoreType::Little => 0,
136 _ => 1,
137 };
138
139 if is_big == 1 {
140 p_cores_found += 1;
141 } else {
142 e_cores_found += 1;
143 }
144
145 if core_id < 32 {
147 info.core_thread_mask[core_id] = ((1u16 << core.cpus.len()) - 1) as u8;
148 }
149
150 let mut thread_idx = 0;
152 let mut sorted_cpus: Vec<_> = core.cpus.keys().collect();
153 sorted_cpus.sort();
154
155 for cpu_id in sorted_cpus {
156 let cpu = *cpu_id;
157 if cpu < MAX_CPUS {
158 info.cpu_is_big[cpu] = is_big;
159 info.cpu_core_id[cpu] = core_id as u8;
160 info.cpu_thread_bit[cpu] = 1 << thread_idx;
161 info.cpu_dsq_id[cpu] = 1000 + cpu as u32;
162
163 if core_id < 32 {
164 info.core_cpu_mask[core_id] |= 1u64 << cpu;
165 }
166
167 if is_big == 1 {
168 info.big_cpu_mask |= 1u64 << cpu;
169 }
170 thread_idx += 1;
171 }
172 }
173 }
174
175 if p_cores_found > 0 && e_cores_found > 0 {
177 info.has_hybrid_cores = true;
178 } else {
179 info.has_hybrid_cores = false;
180 if p_cores_found == 0 && e_cores_found > 0 {
182 }
185 }
186
187 log::debug!("Topology detected:");
189 log::debug!(" CPUs: {}", info.nr_cpus);
190 log::debug!(" SMT Enabled: {}", info.smt_enabled);
191 log::debug!(" Dual CCD: {}", info.has_dual_ccd);
192 if info.has_dual_ccd {
193 log::debug!(" Masks: {:x?}", &info.llc_cpu_mask[..llc_idx]);
194 }
195 log::debug!(" Hybrid cores: {}", info.has_hybrid_cores);
196 if info.has_hybrid_cores {
197 log::debug!(" P-core mask: {:016x}", info.big_cpu_mask);
198 }
199
200 Ok(info)
201}