quantrs2_core/platform/
detector.rs1use super::capabilities::*;
4use std::env;
5
6pub fn detect_platform_capabilities() -> PlatformCapabilities {
8 PlatformCapabilities {
13 cpu: detect_cpu_capabilities(),
14 gpu: detect_gpu_capabilities(),
15 memory: detect_memory_capabilities(),
16 platform_type: detect_platform_type(),
17 os: detect_operating_system(),
18 architecture: detect_architecture(),
19 }
20}
21
22fn detect_cpu_capabilities() -> CpuCapabilities {
24 let logical_cores = num_cpus::get();
25 let physical_cores = num_cpus::get_physical();
26
27 CpuCapabilities {
28 physical_cores,
29 logical_cores,
30 simd: detect_simd_capabilities(),
31 cache: detect_cache_info(),
32 base_clock_mhz: detect_cpu_frequency(),
33 vendor: detect_cpu_vendor(),
34 model_name: detect_cpu_model(),
35 }
36}
37
38fn detect_cpu_frequency() -> Option<f32> {
40 use sysinfo::System;
41
42 let mut sys = System::new();
43 sys.refresh_cpu_all();
44
45 sys.cpus().first().map(|cpu| cpu.frequency() as f32)
47}
48
49fn detect_simd_capabilities() -> SimdCapabilities {
51 #[cfg(target_arch = "x86_64")]
55 {
56 SimdCapabilities {
57 sse: is_x86_feature_detected!("sse"),
58 sse2: is_x86_feature_detected!("sse2"),
59 sse3: is_x86_feature_detected!("sse3"),
60 ssse3: is_x86_feature_detected!("ssse3"),
61 sse4_1: is_x86_feature_detected!("sse4.1"),
62 sse4_2: is_x86_feature_detected!("sse4.2"),
63 avx: is_x86_feature_detected!("avx"),
64 avx2: is_x86_feature_detected!("avx2"),
65 avx512: cfg!(target_feature = "avx512f"),
66 fma: is_x86_feature_detected!("fma"),
67 neon: false,
68 sve: false,
69 }
70 }
71
72 #[cfg(target_arch = "aarch64")]
73 {
74 SimdCapabilities {
75 sse: false,
76 sse2: false,
77 sse3: false,
78 ssse3: false,
79 sse4_1: false,
80 sse4_2: false,
81 avx: false,
82 avx2: false,
83 avx512: false,
84 fma: false,
85 neon: cfg!(target_feature = "neon"),
86 sve: cfg!(target_feature = "sve"),
87 }
88 }
89
90 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
91 {
92 SimdCapabilities {
93 sse: false,
94 sse2: false,
95 sse3: false,
96 ssse3: false,
97 sse4_1: false,
98 sse4_2: false,
99 avx: false,
100 avx2: false,
101 avx512: false,
102 fma: false,
103 neon: false,
104 sve: false,
105 }
106 }
107}
108
109const fn detect_cache_info() -> CacheInfo {
111 CacheInfo {
113 l1_data: Some(32 * 1024), l1_instruction: Some(32 * 1024), l2: Some(256 * 1024), l3: Some(8 * 1024 * 1024), line_size: Some(64), }
119}
120
121fn detect_cpu_vendor() -> String {
123 use sysinfo::System;
124
125 let mut sys = System::new();
126 sys.refresh_cpu_all();
127
128 if let Some(cpu) = sys.cpus().first() {
130 let brand = cpu.brand();
131 if brand.contains("Intel") {
132 return "Intel".to_string();
133 } else if brand.contains("AMD") {
134 return "AMD".to_string();
135 } else if brand.contains("Apple") {
136 return "Apple".to_string();
137 } else if brand.contains("ARM") {
138 return "ARM".to_string();
139 } else if brand.contains("Qualcomm") {
140 return "Qualcomm".to_string();
141 }
142 brand.to_string()
144 } else {
145 "Unknown".to_string()
146 }
147}
148
149fn detect_cpu_model() -> String {
151 use sysinfo::System;
152
153 let mut sys = System::new();
154 sys.refresh_cpu_all();
155
156 sys.cpus()
158 .first()
159 .map(|cpu| cpu.brand().to_string())
160 .unwrap_or_else(|| "Unknown".to_string())
161}
162
163const fn detect_gpu_capabilities() -> GpuCapabilities {
165 let devices = Vec::new();
167
168 GpuCapabilities {
172 available: false,
173 devices,
174 primary_device: None,
175 }
176}
177
178fn detect_memory_capabilities() -> MemoryCapabilities {
180 use sysinfo::System;
181
182 let mut sys = System::new_all();
183 sys.refresh_memory();
184
185 MemoryCapabilities {
186 total_memory: sys.total_memory() as usize,
187 available_memory: sys.available_memory() as usize,
188 bandwidth_gbps: detect_memory_bandwidth(),
189 numa_nodes: detect_numa_nodes(),
190 hugepage_support: detect_hugepage_support(),
191 }
192}
193
194fn detect_memory_bandwidth() -> Option<f32> {
196 #[cfg(target_os = "linux")]
197 {
198 if let Ok(output) = std::process::Command::new("dmidecode")
200 .args(["-t", "memory"])
201 .output()
202 {
203 if output.status.success() {
204 if let Ok(text) = String::from_utf8(output.stdout) {
205 for line in text.lines() {
207 if line.contains("Speed:") && line.contains("MT/s") {
208 if let Some(speed_str) = line.split_whitespace().nth(1) {
210 if let Ok(speed_mts) = speed_str.parse::<f32>() {
211 let bandwidth_gbps = (speed_mts * 8.0) / 1000.0;
214 return Some(bandwidth_gbps);
215 }
216 }
217 }
218 }
219 }
220 }
221 }
222
223 Some(25.0) }
227
228 #[cfg(target_os = "macos")]
229 {
230 if let Ok(output) = std::process::Command::new("sysctl")
232 .arg("hw.memsize")
233 .output()
234 {
235 if output.status.success() {
236 if std::process::Command::new("sysctl")
240 .arg("machdep.cpu.brand_string")
241 .output()
242 .ok()
243 .and_then(|o| String::from_utf8(o.stdout).ok())
244 .map(|s| s.contains("Apple"))
245 .unwrap_or(false)
246 {
247 return Some(200.0); }
249 return Some(30.0); }
251 }
252 Some(30.0)
253 }
254
255 #[cfg(target_os = "windows")]
256 {
257 Some(25.0)
260 }
261
262 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
263 {
264 None
265 }
266}
267
268fn detect_numa_nodes() -> usize {
270 #[cfg(target_os = "linux")]
271 {
272 if let Ok(entries) = std::fs::read_dir("/sys/devices/system/node") {
274 let node_count = entries
275 .filter_map(|e| e.ok())
276 .filter(|e| {
277 e.file_name().to_string_lossy().starts_with("node") && e.file_name() != "node"
278 })
279 .count();
280
281 if node_count > 0 {
282 return node_count;
283 }
284 }
285
286 if let Ok(output) = std::process::Command::new("numactl")
288 .arg("--hardware")
289 .output()
290 {
291 if output.status.success() {
292 if let Ok(text) = String::from_utf8(output.stdout) {
293 for line in text.lines() {
295 if line.contains("available:") && line.contains("nodes") {
296 if let Some(word) = line.split_whitespace().nth(1) {
297 if let Ok(n) = word.parse::<usize>() {
298 return n;
299 }
300 }
301 }
302 }
303 }
304 }
305 }
306
307 1 }
309
310 #[cfg(target_os = "macos")]
311 {
312 1
315 }
316
317 #[cfg(target_os = "windows")]
318 {
319 1
323 }
324
325 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
326 {
327 1
328 }
329}
330
331fn detect_hugepage_support() -> bool {
333 #[cfg(target_os = "linux")]
334 {
335 std::path::Path::new("/sys/kernel/mm/hugepages").exists()
336 }
337 #[cfg(not(target_os = "linux"))]
338 {
339 false
340 }
341}
342
343fn detect_platform_type() -> PlatformType {
345 if env::var("KUBERNETES_SERVICE_HOST").is_ok()
347 || env::var("ECS_CONTAINER_METADATA_URI").is_ok()
348 || env::var("AWS_EXECUTION_ENV").is_ok()
349 || env::var("GOOGLE_CLOUD_PROJECT").is_ok()
350 || env::var("AZURE_FUNCTIONS_ENVIRONMENT").is_ok()
351 {
352 return PlatformType::Cloud;
353 }
354
355 if cfg!(target_os = "android") || cfg!(target_os = "ios") {
357 return PlatformType::Mobile;
358 }
359
360 let logical_cores = num_cpus::get();
362 let physical_cores = num_cpus::get_physical();
363
364 use sysinfo::System;
365 let mut sys = System::new_all();
366 sys.refresh_memory();
367 let total_memory_gb = sys.total_memory() / (1024 * 1024 * 1024);
368
369 let is_server = logical_cores > 16
375 || total_memory_gb > 64
376 || detect_numa_nodes() > 1
377 || detect_cpu_model().contains("Xeon")
378 || detect_cpu_model().contains("EPYC")
379 || detect_cpu_model().contains("Threadripper");
380
381 if is_server {
382 PlatformType::Server
383 } else if cfg!(any(target_arch = "arm", target_arch = "aarch64")) && !cfg!(target_os = "macos")
384 {
385 PlatformType::Embedded
387 } else {
388 PlatformType::Desktop
389 }
390}
391
392const fn detect_operating_system() -> OperatingSystem {
394 #[cfg(target_os = "linux")]
395 {
396 OperatingSystem::Linux
397 }
398 #[cfg(target_os = "windows")]
399 {
400 OperatingSystem::Windows
401 }
402 #[cfg(target_os = "macos")]
403 {
404 OperatingSystem::MacOS
405 }
406 #[cfg(target_os = "freebsd")]
407 {
408 OperatingSystem::FreeBSD
409 }
410 #[cfg(target_os = "android")]
411 {
412 OperatingSystem::Android
413 }
414 #[cfg(not(any(
415 target_os = "linux",
416 target_os = "windows",
417 target_os = "macos",
418 target_os = "freebsd",
419 target_os = "android"
420 )))]
421 {
422 OperatingSystem::Unknown
423 }
424}
425
426const fn detect_architecture() -> Architecture {
428 #[cfg(target_arch = "x86_64")]
429 {
430 Architecture::X86_64
431 }
432 #[cfg(target_arch = "aarch64")]
433 {
434 Architecture::Aarch64
435 }
436 #[cfg(target_arch = "riscv64")]
437 {
438 Architecture::Riscv64
439 }
440 #[cfg(target_arch = "wasm32")]
441 {
442 Architecture::Wasm32
443 }
444 #[cfg(not(any(
445 target_arch = "x86_64",
446 target_arch = "aarch64",
447 target_arch = "riscv64",
448 target_arch = "wasm32"
449 )))]
450 {
451 Architecture::Unknown
452 }
453}