1use std::sync::OnceLock;
21use std::time::Instant;
22
23#[derive(Debug, Clone)]
25pub struct HardwareDetector {
26 cpu_info: CpuInfo,
27 memory_info: MemoryInfo,
28 cache_info: CacheInfo,
29}
30
31#[derive(Debug, Clone)]
32pub struct CpuInfo {
33 pub cores: usize,
34 pub logical_cores: usize,
35 pub architecture: String,
36 pub vendor: String,
37 pub model_name: String,
38 pub base_frequency_mhz: Option<u32>,
39 pub max_frequency_mhz: Option<u32>,
40 pub features: Vec<String>,
41}
42
43#[derive(Debug, Clone)]
44pub struct MemoryInfo {
45 pub total_memory_bytes: u64,
46 pub available_memory_bytes: u64,
47 pub page_size_bytes: usize,
48}
49
50#[derive(Debug, Clone, Default)]
51pub struct CacheInfo {
52 pub l1_data_cache_kb: Option<u32>,
53 pub l1_instruction_cache_kb: Option<u32>,
54 pub l2_cache_kb: Option<u32>,
55 pub l3_cache_kb: Option<u32>,
56 pub cache_line_size_bytes: Option<u32>,
57}
58
59impl Default for CpuInfo {
60 fn default() -> Self {
61 Self {
62 cores: 1,
63 logical_cores: 1,
64 architecture: "unknown".to_string(),
65 vendor: "unknown".to_string(),
66 model_name: "unknown".to_string(),
67 base_frequency_mhz: None,
68 max_frequency_mhz: None,
69 features: Vec::new(),
70 }
71 }
72}
73
74impl Default for MemoryInfo {
75 fn default() -> Self {
76 Self {
77 total_memory_bytes: 0,
78 available_memory_bytes: 0,
79 page_size_bytes: 4096, }
81 }
82}
83
84impl HardwareDetector {
85 pub fn new() -> Self {
87 Self {
88 cpu_info: Self::detect_cpu_info(),
89 memory_info: Self::detect_memory_info(),
90 cache_info: Self::detect_cache_info(),
91 }
92 }
93
94 pub fn cpu_cores(&self) -> usize {
96 self.cpu_info.cores
97 }
98
99 pub fn logical_cores(&self) -> usize {
101 self.cpu_info.logical_cores
102 }
103
104 pub fn cpu_architecture(&self) -> &str {
106 &self.cpu_info.architecture
107 }
108
109 pub fn cpu_vendor(&self) -> &str {
111 &self.cpu_info.vendor
112 }
113
114 pub fn total_memory(&self) -> u64 {
116 self.memory_info.total_memory_bytes
117 }
118
119 pub fn available_memory(&self) -> u64 {
121 self.memory_info.available_memory_bytes
122 }
123
124 pub fn has_avx2(&self) -> bool {
126 self.cpu_info.features.iter().any(|f| f.contains("avx2"))
127 }
128
129 pub fn has_avx512(&self) -> bool {
131 self.cpu_info.features.iter().any(|f| f.contains("avx512"))
132 }
133
134 pub fn has_sse42(&self) -> bool {
136 self.cpu_info.features.iter().any(|f| f.contains("sse4_2"))
137 }
138
139 pub fn has_neon(&self) -> bool {
141 self.cpu_info.features.iter().any(|f| f.contains("neon"))
142 }
143
144 pub fn is_arm(&self) -> bool {
146 self.cpu_info.architecture.contains("arm") || self.cpu_info.architecture.contains("aarch")
147 }
148
149 pub fn is_x86(&self) -> bool {
151 self.cpu_info.architecture.contains("x86") || self.cpu_info.architecture.contains("x64")
152 }
153
154 pub fn l3_cache_size_kb(&self) -> Option<u32> {
156 self.cache_info.l3_cache_kb
157 }
158
159 pub fn cache_line_size(&self) -> Option<u32> {
161 self.cache_info.cache_line_size_bytes
162 }
163
164 pub fn cpu_features(&self) -> &[String] {
166 &self.cpu_info.features
167 }
168
169 fn detect_cpu_info() -> CpuInfo {
171 let mut cpu_info = CpuInfo {
172 logical_cores: num_cpus::get(),
173 cores: num_cpus::get_physical(),
174 architecture: std::env::consts::ARCH.to_string(),
175 ..Default::default()
176 };
177
178 #[cfg(target_arch = "x86_64")]
180 {
181 Self::detect_x86_features(&mut cpu_info);
182 }
183
184 #[cfg(target_arch = "aarch64")]
185 {
186 Self::detect_arm_features(&mut cpu_info);
187 }
188
189 cpu_info
190 }
191
192 #[cfg(target_arch = "x86_64")]
193 fn detect_x86_features(cpu_info: &mut CpuInfo) {
194 if is_x86_feature_detected!("sse") {
195 cpu_info.features.push("sse".to_string());
196 }
197 if is_x86_feature_detected!("sse2") {
198 cpu_info.features.push("sse2".to_string());
199 }
200 if is_x86_feature_detected!("sse3") {
201 cpu_info.features.push("sse3".to_string());
202 }
203 if is_x86_feature_detected!("sse4.1") {
204 cpu_info.features.push("sse4_1".to_string());
205 }
206 if is_x86_feature_detected!("sse4.2") {
207 cpu_info.features.push("sse4_2".to_string());
208 }
209 if is_x86_feature_detected!("avx") {
210 cpu_info.features.push("avx".to_string());
211 }
212 if is_x86_feature_detected!("avx2") {
213 cpu_info.features.push("avx2".to_string());
214 }
215 if is_x86_feature_detected!("fma") {
216 cpu_info.features.push("fma".to_string());
217 }
218
219 cpu_info.vendor = "Intel/AMD".to_string(); }
222
223 #[cfg(target_arch = "aarch64")]
224 fn detect_arm_features(cpu_info: &mut CpuInfo) {
225 cpu_info.vendor = "ARM".to_string();
226 cpu_info.features.push("neon".to_string()); }
228
229 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
230 fn detect_x86_features(_cpu_info: &mut CpuInfo) {}
231
232 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
233 fn detect_arm_features(_cpu_info: &mut CpuInfo) {}
234
235 fn detect_memory_info() -> MemoryInfo {
237 let mut memory_info = MemoryInfo::default();
238
239 #[cfg(feature = "sysinfo")]
241 {
242 use sysinfo::System;
243 let mut system = System::new_all();
244 system.refresh_memory();
245 memory_info.total_memory_bytes = system.total_memory() * 1024; memory_info.available_memory_bytes = system.available_memory() * 1024;
247 }
248
249 #[cfg(not(feature = "sysinfo"))]
251 {
252 #[cfg(target_os = "linux")]
254 {
255 if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
256 for line in meminfo.lines() {
257 if line.starts_with("MemTotal:") {
258 if let Some(kb_str) = line.split_whitespace().nth(1) {
259 if let Ok(kb) = kb_str.parse::<u64>() {
260 memory_info.total_memory_bytes = kb * 1024;
261 }
262 }
263 } else if line.starts_with("MemAvailable:") {
264 if let Some(kb_str) = line.split_whitespace().nth(1) {
265 if let Ok(kb) = kb_str.parse::<u64>() {
266 memory_info.available_memory_bytes = kb * 1024;
267 }
268 }
269 }
270 }
271 }
272 }
273
274 #[cfg(target_os = "macos")]
275 {
276 if let Ok(output) = std::process::Command::new("sysctl")
278 .arg("-n")
279 .arg("hw.memsize")
280 .output()
281 {
282 if let Ok(mem_str) = String::from_utf8(output.stdout) {
283 if let Ok(mem_bytes) = mem_str.trim().parse::<u64>() {
284 memory_info.total_memory_bytes = mem_bytes;
285 memory_info.available_memory_bytes = mem_bytes / 2; }
287 }
288 }
289 }
290
291 if memory_info.total_memory_bytes == 0 {
293 memory_info.total_memory_bytes = 8 * 1024 * 1024 * 1024; memory_info.available_memory_bytes = 4 * 1024 * 1024 * 1024; }
296 }
297
298 #[cfg(unix)]
300 {
301 unsafe {
302 let page_size = libc::sysconf(libc::_SC_PAGESIZE);
303 if page_size > 0 {
304 memory_info.page_size_bytes = page_size as usize;
305 }
306 }
307 }
308
309 memory_info
310 }
311
312 fn detect_cache_info() -> CacheInfo {
314 let mut cache_info = CacheInfo::default();
315
316 #[cfg(target_os = "linux")]
318 {
319 Self::detect_linux_cache_info(&mut cache_info);
320 }
321
322 #[cfg(target_os = "macos")]
323 {
324 Self::detect_macos_cache_info(&mut cache_info);
325 }
326
327 #[cfg(target_os = "windows")]
328 {
329 Self::detect_windows_cache_info(&mut cache_info);
330 }
331
332 cache_info
333 }
334
335 #[cfg(target_os = "linux")]
336 fn detect_linux_cache_info(cache_info: &mut CacheInfo) {
337 if let Ok(l1d) = std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cache/index0/size") {
339 if let Ok(size) = l1d.trim().strip_suffix("K").unwrap_or(&l1d).parse::<u32>() {
340 cache_info.l1_data_cache_kb = Some(size);
341 }
342 }
343
344 if let Ok(l2) = std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cache/index2/size") {
345 if let Ok(size) = l2.trim().strip_suffix("K").unwrap_or(&l2).parse::<u32>() {
346 cache_info.l2_cache_kb = Some(size);
347 }
348 }
349
350 if let Ok(l3) = std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cache/index3/size") {
351 if let Ok(size) = l3.trim().strip_suffix("K").unwrap_or(&l3).parse::<u32>() {
352 cache_info.l3_cache_kb = Some(size);
353 }
354 }
355
356 cache_info.cache_line_size_bytes = Some(64);
358 }
359
360 #[cfg(target_os = "macos")]
361 fn detect_macos_cache_info(cache_info: &mut CacheInfo) {
362 cache_info.cache_line_size_bytes = Some(64); }
365
366 #[cfg(target_os = "windows")]
367 fn detect_windows_cache_info(cache_info: &mut CacheInfo) {
368 cache_info.cache_line_size_bytes = Some(64); }
371
372 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
373 fn detect_linux_cache_info(_cache_info: &mut CacheInfo) {}
374
375 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
376 fn detect_macos_cache_info(_cache_info: &mut CacheInfo) {}
377
378 #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
379 fn detect_windows_cache_info(_cache_info: &mut CacheInfo) {}
380}
381
382impl Default for HardwareDetector {
383 fn default() -> Self {
384 Self::new()
385 }
386}
387
388#[derive(Debug, Clone)]
390pub struct OSInfo {
391 pub name: String,
392 pub version: String,
393 pub arch: String,
394 pub kernel_version: Option<String>,
395 pub is_64bit: bool,
396}
397
398impl OSInfo {
399 pub fn detect() -> Self {
401 Self {
402 name: std::env::consts::OS.to_string(),
403 version: Self::detect_os_version(),
404 arch: std::env::consts::ARCH.to_string(),
405 kernel_version: Self::detect_kernel_version(),
406 is_64bit: cfg!(target_pointer_width = "64"),
407 }
408 }
409
410 pub fn is_linux(&self) -> bool {
412 self.name == "linux"
413 }
414
415 pub fn is_macos(&self) -> bool {
417 self.name == "macos"
418 }
419
420 pub fn is_windows(&self) -> bool {
422 self.name == "windows"
423 }
424
425 pub fn is_unix(&self) -> bool {
427 cfg!(unix)
428 }
429
430 fn detect_os_version() -> String {
431 #[cfg(target_os = "linux")]
432 {
433 if let Ok(version) = std::fs::read_to_string("/proc/version") {
434 return version.lines().next().unwrap_or("unknown").to_string();
435 }
436 }
437
438 #[cfg(target_os = "macos")]
439 {
440 "macOS".to_string()
442 }
443 #[cfg(target_os = "windows")]
444 {
445 "Windows".to_string()
447 }
448 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
449 {
450 "unknown".to_string()
451 }
452 }
453
454 fn detect_kernel_version() -> Option<String> {
455 #[cfg(unix)]
456 {
457 if let Ok(output) = std::process::Command::new("uname").arg("-r").output() {
458 if let Ok(version) = String::from_utf8(output.stdout) {
459 return Some(version.trim().to_string());
460 }
461 }
462 }
463 None
464 }
465}
466
467#[derive(Debug, Clone)]
469pub struct RuntimeInfo {
470 pub rust_version: String,
471 pub compiler: String,
472 pub target_triple: String,
473 pub build_profile: String,
474 pub features: Vec<String>,
475}
476
477impl RuntimeInfo {
478 pub fn detect() -> Self {
480 let target_family = std::env::var("CARGO_CFG_TARGET_FAMILY")
481 .unwrap_or_else(|_| std::env::consts::FAMILY.to_string());
482 let target_triple = std::env::var("CARGO_CFG_TARGET_TRIPLE").unwrap_or_else(|_| {
483 format!(
484 "{}-{}-{}",
485 std::env::consts::ARCH,
486 std::env::consts::FAMILY,
487 std::env::consts::OS
488 )
489 });
490
491 Self {
492 rust_version: option_env!("CARGO_PKG_RUST_VERSION")
493 .unwrap_or("unknown")
494 .to_string(),
495 compiler: format!("{target_family} {}", rustc_version_runtime::version()),
496 target_triple,
497 build_profile: if cfg!(debug_assertions) {
498 "debug"
499 } else {
500 "release"
501 }
502 .to_string(),
503 features: Self::detect_features(),
504 }
505 }
506
507 pub fn is_debug(&self) -> bool {
509 self.build_profile == "debug"
510 }
511
512 pub fn is_release(&self) -> bool {
514 self.build_profile == "release"
515 }
516
517 fn detect_features() -> Vec<String> {
518 Vec::new()
530 }
531}
532
533#[derive(Debug, Clone)]
535pub struct PerformanceCharacteristics {
536 pub memory_bandwidth_gbps: f64,
537 pub l1_cache_latency_ns: f64,
538 pub l2_cache_latency_ns: f64,
539 pub l3_cache_latency_ns: f64,
540 pub memory_latency_ns: f64,
541 pub cpu_frequency_estimation_mhz: f64,
542 pub single_thread_performance_score: f64,
543 pub multi_thread_performance_score: f64,
544}
545
546impl PerformanceCharacteristics {
547 pub fn measure() -> Self {
549 let _start_time = Instant::now();
550
551 let memory_bandwidth = Self::measure_memory_bandwidth();
552 let cache_latencies = Self::measure_cache_latencies();
553 let cpu_freq = Self::estimate_cpu_frequency();
554 let single_perf = Self::measure_single_thread_performance();
555 let multi_perf = Self::measure_multi_thread_performance();
556
557 Self {
558 memory_bandwidth_gbps: memory_bandwidth,
559 l1_cache_latency_ns: cache_latencies.0,
560 l2_cache_latency_ns: cache_latencies.1,
561 l3_cache_latency_ns: cache_latencies.2,
562 memory_latency_ns: cache_latencies.3,
563 cpu_frequency_estimation_mhz: cpu_freq,
564 single_thread_performance_score: single_perf,
565 multi_thread_performance_score: multi_perf,
566 }
567 }
568
569 fn measure_memory_bandwidth() -> f64 {
570 const SIZE: usize = 16 * 1024 * 1024; let mut data = vec![0u64; SIZE / 8];
573
574 let start = Instant::now();
575
576 for (i, item) in data.iter_mut().enumerate() {
578 *item = i as u64;
579 }
580
581 let mut sum = 0u64;
583 for &val in &data {
584 sum = sum.wrapping_add(val);
585 }
586
587 let elapsed = start.elapsed();
588 let bytes_processed = (SIZE * 2) as f64; let bandwidth_bps = bytes_processed / elapsed.as_secs_f64();
590
591 std::hint::black_box(sum);
593
594 bandwidth_bps / 1e9 }
596
597 fn measure_cache_latencies() -> (f64, f64, f64, f64) {
598 (1.0, 3.0, 10.0, 100.0) }
602
603 fn estimate_cpu_frequency() -> f64 {
604 let iterations = 10_000_000;
606 let start = Instant::now();
607
608 let mut counter = 0u64;
609 for _ in 0..iterations {
610 counter = counter.wrapping_add(1);
611 }
612
613 let elapsed = start.elapsed();
614 std::hint::black_box(counter);
615
616 let cycles_per_second = iterations as f64 / elapsed.as_secs_f64();
618 cycles_per_second / 1e6 }
620
621 fn measure_single_thread_performance() -> f64 {
622 let start = Instant::now();
624 let mut sum = 0.0;
625
626 for i in 0..1_000_000 {
627 sum += (i as f64).sqrt().sin().cos();
628 }
629
630 let elapsed = start.elapsed();
631 std::hint::black_box(sum);
632
633 1_000_000.0 / elapsed.as_secs_f64()
635 }
636
637 fn measure_multi_thread_performance() -> f64 {
638 use std::thread;
639
640 let num_threads = num_cpus::get();
641 let start = Instant::now();
642
643 let handles: Vec<_> = (0..num_threads)
644 .map(|_| {
645 thread::spawn(|| {
646 let mut sum = 0.0;
647 for i in 0..100_000 {
648 sum += (i as f64).sqrt().sin().cos();
649 }
650 sum
651 })
652 })
653 .collect();
654
655 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
656 let elapsed = start.elapsed();
657
658 std::hint::black_box(results);
659
660 (num_threads * 100_000) as f64 / elapsed.as_secs_f64()
662 }
663}
664
665#[derive(Debug, Clone)]
667pub struct FeatureChecker {
668 hardware: HardwareDetector,
669 os_info: OSInfo,
670 #[allow(dead_code)]
671 runtime: RuntimeInfo,
672}
673
674impl FeatureChecker {
675 pub fn new() -> Self {
677 Self {
678 hardware: HardwareDetector::new(),
679 os_info: OSInfo::detect(),
680 runtime: RuntimeInfo::detect(),
681 }
682 }
683
684 pub fn simd_available(&self) -> bool {
686 self.hardware.has_sse42() || self.hardware.has_avx2() || self.hardware.has_neon()
687 }
688
689 pub fn parallel_beneficial(&self) -> bool {
691 self.hardware.logical_cores() > 1
692 }
693
694 pub fn memory_mapping_available(&self) -> bool {
696 self.os_info.is_unix() || self.os_info.is_windows()
697 }
698
699 pub fn high_resolution_timer_available(&self) -> bool {
701 true }
703
704 pub fn recommended_thread_count(&self) -> usize {
706 self.hardware.logical_cores().min(32)
708 }
709
710 pub fn recommended_simd_width(&self) -> usize {
712 if self.hardware.has_avx512() {
713 16 } else if self.hardware.has_avx2() {
715 8 } else if self.hardware.has_sse42() || self.hardware.has_neon() {
717 4 } else {
719 1 }
721 }
722
723 pub fn optimization_recommended(&self, optimization: &str) -> bool {
725 match optimization {
726 "simd" => self.simd_available(),
727 "parallel" => self.parallel_beneficial(),
728 "cache_friendly" => self.hardware.l3_cache_size_kb().is_some(),
729 "memory_pool" => self.hardware.total_memory() > 1_000_000_000, _ => false,
731 }
732 }
733
734 pub fn get_recommendations(&self) -> Vec<String> {
736 let mut recommendations = Vec::new();
737
738 if self.simd_available() {
739 recommendations.push("Enable SIMD optimizations".to_string());
740 }
741
742 if self.parallel_beneficial() {
743 recommendations.push(format!(
744 "Use parallel processing with {} threads",
745 self.recommended_thread_count()
746 ));
747 }
748
749 if let Some(cache_size) = self.hardware.l3_cache_size_kb() {
750 recommendations.push(format!("Optimize for {cache_size}KB L3 cache"));
751 }
752
753 if self.hardware.total_memory() < 1_000_000_000 {
754 recommendations.push("Consider memory usage optimizations".to_string());
755 }
756
757 recommendations
758 }
759}
760
761impl Default for FeatureChecker {
762 fn default() -> Self {
763 Self::new()
764 }
765}
766
767static GLOBAL_ENV_INFO: OnceLock<EnvironmentInfo> = OnceLock::new();
769
770#[derive(Debug, Clone)]
772pub struct EnvironmentInfo {
773 pub hardware: HardwareDetector,
774 pub os_info: OSInfo,
775 pub runtime: RuntimeInfo,
776 pub performance: PerformanceCharacteristics,
777 pub features: FeatureChecker,
778}
779
780impl EnvironmentInfo {
781 pub fn global() -> &'static EnvironmentInfo {
783 GLOBAL_ENV_INFO.get_or_init(EnvironmentInfo::detect)
784 }
785
786 pub fn detect() -> Self {
788 let hardware = HardwareDetector::new();
789 let os_info = OSInfo::detect();
790 let runtime = RuntimeInfo::detect();
791 let performance = PerformanceCharacteristics::measure();
792 let features = FeatureChecker::new();
793
794 Self {
795 hardware,
796 os_info,
797 runtime,
798 performance,
799 features,
800 }
801 }
802
803 pub fn summary(&self) -> String {
805 format!(
806 "Environment Summary:\n\
807 OS: {} {} ({})\n\
808 CPU: {} cores ({} logical), {}\n\
809 Memory: {:.1} GB total, {:.1} GB available\n\
810 Runtime: {} {}\n\
811 Features: SIMD={}, Parallel={}, Cache={}KB",
812 self.os_info.name,
813 self.os_info.version,
814 self.os_info.arch,
815 self.hardware.cpu_cores(),
816 self.hardware.logical_cores(),
817 self.hardware.cpu_architecture(),
818 self.hardware.total_memory() as f64 / 1e9,
819 self.hardware.available_memory() as f64 / 1e9,
820 self.runtime.compiler,
821 self.runtime.build_profile,
822 self.features.simd_available(),
823 self.features.parallel_beneficial(),
824 self.hardware.l3_cache_size_kb().unwrap_or(0)
825 )
826 }
827}
828
829#[allow(non_snake_case)]
830#[cfg(test)]
831mod tests {
832 use super::*;
833
834 #[test]
835 fn test_hardware_detector() {
836 let hw = HardwareDetector::new();
837
838 assert!(hw.cpu_cores() >= 1);
839 assert!(hw.logical_cores() >= 1); assert!(!hw.cpu_architecture().is_empty());
841 assert!(hw.total_memory() > 0);
842 }
843
844 #[test]
845 fn test_os_info() {
846 let os = OSInfo::detect();
847
848 assert!(!os.name.is_empty());
849 assert!(!os.arch.is_empty());
850
851 assert!(os.is_linux() || os.is_macos() || os.is_windows() || !os.name.is_empty());
853 }
854
855 #[test]
856 fn test_runtime_info() {
857 let runtime = RuntimeInfo::detect();
858
859 assert!(!runtime.compiler.is_empty());
860 assert!(!runtime.target_triple.is_empty());
861 assert!(runtime.is_debug() || runtime.is_release());
862 }
863
864 #[test]
865 fn test_performance_characteristics() {
866 let perf = PerformanceCharacteristics::measure();
867
868 assert!(perf.memory_bandwidth_gbps > 0.0);
869 assert!(perf.cpu_frequency_estimation_mhz > 0.0);
870 assert!(perf.single_thread_performance_score > 0.0);
871 assert!(perf.multi_thread_performance_score > 0.0);
872 }
873
874 #[test]
875 fn test_feature_checker() {
876 let checker = FeatureChecker::new();
877
878 assert!(checker.recommended_thread_count() >= 1);
879 assert!(checker.recommended_simd_width() >= 1);
880 assert!(checker.high_resolution_timer_available());
881 }
882
883 #[test]
884 fn test_environment_info() {
885 let env = EnvironmentInfo::detect();
886 let summary = env.summary();
887
888 assert!(!summary.is_empty());
889 assert!(summary.contains("Environment Summary"));
890
891 let global_env = EnvironmentInfo::global();
893 assert!(!global_env.summary().is_empty());
894 }
895
896 #[test]
897 fn test_cpu_features() {
898 let hw = HardwareDetector::new();
899
900 let _has_avx2 = hw.has_avx2();
902 let _has_sse42 = hw.has_sse42();
903 let _has_neon = hw.has_neon();
904 let _is_arm = hw.is_arm();
905 let _is_x86 = hw.is_x86();
906 }
907
908 #[test]
909 fn test_optimization_recommendations() {
910 let checker = FeatureChecker::new();
911 let recommendations = checker.get_recommendations();
912
913 assert!(!recommendations.is_empty());
915
916 let _simd_rec = checker.optimization_recommended("simd");
918 let _parallel_rec = checker.optimization_recommended("parallel");
919 let _cache_rec = checker.optimization_recommended("cache_friendly");
920 }
921}