scirs2_core/resource/
mod.rs

1//! # Resource Discovery and Hardware Detection
2//!
3//! This module provides automatic hardware detection and resource discovery
4//! capabilities for optimizing `SciRS2` Core performance based on available
5//! system resources. It includes:
6//! - CPU detection and optimization parameter tuning
7//! - Memory hierarchy analysis
8//! - GPU discovery and capability assessment
9//! - Network and storage resource detection
10//! - Dynamic optimization parameter adjustment
11
12pub mod auto_tuning;
13pub mod cpu;
14pub mod gpu;
15pub mod memory;
16pub mod network;
17pub mod optimization;
18pub mod storage;
19
20use crate::error::{CoreError, CoreResult};
21// Collections are used in the SystemResources struct
22use std::time::Duration;
23
24/// System resource information
25#[derive(Debug, Clone)]
26pub struct SystemResources {
27    /// CPU information
28    pub cpu: cpu::CpuInfo,
29    /// Memory information
30    pub memory: memory::MemoryInfo,
31    /// GPU information (if available)
32    pub gpu: Option<gpu::GpuInfo>,
33    /// Network information
34    pub network: network::NetworkInfo,
35    /// Storage information
36    pub storage: storage::StorageInfo,
37    /// Optimization recommendations
38    pub optimization_params: optimization::OptimizationParams,
39}
40
41impl SystemResources {
42    /// Discover all system resources
43    pub fn discover() -> CoreResult<Self> {
44        let cpu = cpu::CpuInfo::detect()?;
45        let memory = memory::MemoryInfo::detect()?;
46        let gpu = gpu::GpuInfo::detect().ok();
47        let network = network::NetworkInfo::detect()?;
48        let storage = storage::StorageInfo::detect()?;
49
50        let optimization_params = optimization::OptimizationParams::generate(
51            &cpu,
52            &memory,
53            gpu.as_ref(),
54            &network,
55            &storage,
56        )?;
57
58        Ok(Self {
59            cpu,
60            memory,
61            gpu,
62            network,
63            storage,
64            optimization_params,
65        })
66    }
67
68    /// Get recommended thread count for parallel operations
69    pub fn recommended_thread_count(&self) -> usize {
70        self.optimization_params.thread_count
71    }
72
73    /// Get recommended chunk size for memory operations
74    pub fn recommended_chunk_size(&self) -> usize {
75        self.optimization_params.chunk_size
76    }
77
78    /// Check if SIMD operations are supported
79    pub fn supports_simd(&self) -> bool {
80        self.cpu.simd_capabilities.avx2 || self.cpu.simd_capabilities.sse4_2
81    }
82
83    /// Check if GPU acceleration is available
84    pub fn supports_gpu(&self) -> bool {
85        self.gpu.is_some()
86    }
87
88    /// Get total available memory in bytes
89    pub fn total_memory(&self) -> usize {
90        self.memory.total_memory
91    }
92
93    /// Get available memory in bytes
94    pub fn available_memory(&self) -> usize {
95        self.memory.available_memory
96    }
97
98    /// Get performance tier classification
99    pub fn performance_tier(&self) -> PerformanceTier {
100        let cpu_score = self.cpu.performance_score();
101        let memory_score = self.memory.performance_score();
102        let gpu_score = self
103            .gpu
104            .as_ref()
105            .map(|g| g.performance_score())
106            .unwrap_or(0.0);
107
108        let combined_score = (cpu_score + memory_score + gpu_score) / 3.0;
109
110        if combined_score >= 0.8 {
111            PerformanceTier::High
112        } else if combined_score >= 0.5 {
113            PerformanceTier::Medium
114        } else {
115            PerformanceTier::Low
116        }
117    }
118
119    /// Generate a system summary report
120    pub fn summary_report(&self) -> String {
121        let mut report = String::new();
122
123        report.push_str("# System Resource Summary\n\n");
124
125        // CPU information
126        report.push_str("## CPU\n");
127        report.push_str(&format!("- Model: {}\n", self.cpu.model));
128        report.push_str(&format!(
129            "- Cores: {} physical, {} logical\n",
130            self.cpu.physical_cores, self.cpu.logical_cores
131        ));
132        report.push_str(&format!(
133            "- Base frequency: {:.2} GHz\n",
134            self.cpu.base_frequency_ghz
135        ));
136        report.push_str(&format!(
137            "- Cache L1: {} KB, L2: {} KB, L3: {} KB\n",
138            self.cpu.cache_l1_kb, self.cpu.cache_l2_kb, self.cpu.cache_l3_kb
139        ));
140
141        // SIMD capabilities
142        report.push_str("- SIMD support:");
143        if self.cpu.simd_capabilities.sse4_2 {
144            report.push_str(" SSE4.2");
145        }
146        if self.cpu.simd_capabilities.avx2 {
147            report.push_str(" AVX2");
148        }
149        if self.cpu.simd_capabilities.avx512 {
150            report.push_str(" AVX512");
151        }
152        if self.cpu.simd_capabilities.neon {
153            report.push_str(" NEON");
154        }
155        report.push('\n');
156
157        // Memory information
158        report.push_str("\n## Memory\n");
159        report.push_str(&format!(
160            "- Total: {:.2} GB\n",
161            self.memory.total_memory as f64 / (1024.0 * 1024.0 * 1024.0)
162        ));
163        report.push_str(&format!(
164            "- Available: {:.2} GB\n",
165            self.memory.available_memory as f64 / (1024.0 * 1024.0 * 1024.0)
166        ));
167        report.push_str(&format!(
168            "- Page size: {} KB\n",
169            self.memory.page_size / 1024
170        ));
171
172        // GPU information
173        if let Some(ref gpu) = self.gpu {
174            report.push_str("\n## GPU\n");
175            report.push_str(&format!("- Model: {}\n", gpu.name));
176            report.push_str(&format!(
177                "- Memory: {:.2} GB\n",
178                gpu.memory_total as f64 / (1024.0 * 1024.0 * 1024.0)
179            ));
180            report.push_str(&format!("- Compute units: {}\n", gpu.compute_units));
181        }
182
183        // Optimization recommendations
184        report.push_str("\n## Optimization Recommendations\n");
185        report.push_str(&format!(
186            "- Thread count: {}\n",
187            self.optimization_params.thread_count
188        ));
189        report.push_str(&format!(
190            "- Chunk size: {} KB\n",
191            self.optimization_params.chunk_size / 1024
192        ));
193        report.push_str(&format!(
194            "- SIMD enabled: {}\n",
195            self.optimization_params.enable_simd
196        ));
197        report.push_str(&format!(
198            "- GPU enabled: {}\n",
199            self.optimization_params.enable_gpu
200        ));
201
202        // Performance tier
203        report.push_str(&format!(
204            "\n## Performance Tier: {:?}\n",
205            self.performance_tier()
206        ));
207
208        report
209    }
210}
211
212/// Performance tier classification
213#[derive(Debug, Clone, Copy, PartialEq, Eq)]
214pub enum PerformanceTier {
215    /// High-performance system (server, workstation)
216    High,
217    /// Medium-performance system (desktop, laptop)
218    Medium,
219    /// Low-performance system (embedded, older hardware)
220    Low,
221}
222
223/// Resource discovery configuration
224#[derive(Debug, Clone)]
225pub struct DiscoveryConfig {
226    /// Enable CPU detection
227    pub detect_cpu: bool,
228    /// Enable memory detection
229    pub detect_memory: bool,
230    /// Enable GPU detection
231    pub detect_gpu: bool,
232    /// Enable network detection
233    pub detect_network: bool,
234    /// Enable storage detection
235    pub detectstorage: bool,
236    /// Cache discovery results
237    pub cache_results: bool,
238    /// Cache duration
239    pub cache_duration: Duration,
240    /// Enable detailed detection (may be slower)
241    pub detailed_detection: bool,
242}
243
244impl Default for DiscoveryConfig {
245    fn default() -> Self {
246        Self {
247            detect_cpu: true,
248            detect_memory: true,
249            detect_gpu: true,
250            detect_network: true,
251            detectstorage: true,
252            cache_results: true,
253            cache_duration: Duration::from_secs(300), // 5 minutes
254            detailed_detection: false,
255        }
256    }
257}
258
259impl DiscoveryConfig {
260    /// Create a new discovery configuration
261    pub fn new() -> Self {
262        Self::default()
263    }
264
265    /// Enable all detection
266    pub fn detect_all(mut self) -> Self {
267        self.detect_cpu = true;
268        self.detect_memory = true;
269        self.detect_gpu = true;
270        self.detect_network = true;
271        self.detectstorage = true;
272        self
273    }
274
275    /// Disable all detection
276    pub fn detect_none(mut self) -> Self {
277        self.detect_cpu = false;
278        self.detect_memory = false;
279        self.detect_gpu = false;
280        self.detect_network = false;
281        self.detectstorage = false;
282        self
283    }
284
285    /// Enable only essential detection (CPU and memory)
286    pub fn detect_essential(mut self) -> Self {
287        self.detect_cpu = true;
288        self.detect_memory = true;
289        self.detect_gpu = false;
290        self.detect_network = false;
291        self.detectstorage = false;
292        self
293    }
294
295    /// Enable caching with custom duration
296    pub fn with_cache_duration(mut self, duration: Duration) -> Self {
297        self.cache_results = true;
298        self.cache_duration = duration;
299        self
300    }
301
302    /// Enable detailed detection
303    pub fn with_detailed_detection(mut self, enabled: bool) -> Self {
304        self.detailed_detection = enabled;
305        self
306    }
307}
308
309/// Resource discovery manager with caching
310pub struct ResourceDiscovery {
311    config: DiscoveryConfig,
312    cached_resources: std::sync::Mutex<Option<(SystemResources, std::time::Instant)>>,
313}
314
315impl ResourceDiscovery {
316    /// Create a new resource discovery manager
317    pub fn new(config: DiscoveryConfig) -> Self {
318        Self {
319            config,
320            cached_resources: std::sync::Mutex::new(None),
321        }
322    }
323}
324
325impl Default for ResourceDiscovery {
326    fn default() -> Self {
327        Self::new(DiscoveryConfig::default())
328    }
329}
330
331impl ResourceDiscovery {
332    /// Discover system resources with caching
333    pub fn discover(&self) -> CoreResult<SystemResources> {
334        if self.config.cache_results {
335            if let Ok(cache) = self.cached_resources.lock() {
336                if let Some((ref resources, timestamp)) = *cache {
337                    if timestamp.elapsed() < self.config.cache_duration {
338                        return Ok(resources.clone());
339                    }
340                }
341            }
342        }
343
344        // Perform discovery
345        let resources = self.discover_fresh()?;
346
347        // Update cache
348        if self.config.cache_results {
349            if let Ok(mut cache) = self.cached_resources.lock() {
350                *cache = Some((resources.clone(), std::time::Instant::now()));
351            }
352        }
353
354        Ok(resources)
355    }
356
357    /// Force fresh discovery without cache
358    pub fn discover_fresh(&self) -> CoreResult<SystemResources> {
359        let cpu = if self.config.detect_cpu {
360            cpu::CpuInfo::detect()?
361        } else {
362            cpu::CpuInfo::default()
363        };
364
365        let memory = if self.config.detect_memory {
366            memory::MemoryInfo::detect()?
367        } else {
368            memory::MemoryInfo::default()
369        };
370
371        let gpu = if self.config.detect_gpu {
372            gpu::GpuInfo::detect().ok()
373        } else {
374            None
375        };
376
377        let network = if self.config.detect_network {
378            network::NetworkInfo::detect()?
379        } else {
380            network::NetworkInfo::default()
381        };
382
383        let storage = if self.config.detectstorage {
384            storage::StorageInfo::detect()?
385        } else {
386            storage::StorageInfo::default()
387        };
388
389        let optimization_params = optimization::OptimizationParams::generate(
390            &cpu,
391            &memory,
392            gpu.as_ref(),
393            &network,
394            &storage,
395        )?;
396
397        Ok(SystemResources {
398            cpu,
399            memory,
400            gpu,
401            network,
402            storage,
403            optimization_params,
404        })
405    }
406
407    /// Clear cache
408    pub fn clear_cache(&self) -> CoreResult<()> {
409        if let Ok(mut cache) = self.cached_resources.lock() {
410            *cache = None;
411            Ok(())
412        } else {
413            Err(CoreError::ComputationError(
414                crate::error::ErrorContext::new("Failed to clear cache"),
415            ))
416        }
417    }
418
419    /// Get cache status
420    pub fn cache_status(&self) -> CoreResult<Option<Duration>> {
421        if let Ok(cache) = self.cached_resources.lock() {
422            if let Some((_, timestamp)) = cache.as_ref() {
423                Ok(Some(timestamp.elapsed()))
424            } else {
425                Ok(None)
426            }
427        } else {
428            Err(CoreError::ComputationError(
429                crate::error::ErrorContext::new("Failed to read cache status"),
430            ))
431        }
432    }
433}
434
435/// Global resource discovery instance
436static GLOBAL_RESOURCE_DISCOVERY: std::sync::LazyLock<ResourceDiscovery> =
437    std::sync::LazyLock::new(ResourceDiscovery::default);
438
439/// Get the global resource discovery instance
440#[allow(dead_code)]
441pub fn global_resource_discovery() -> &'static ResourceDiscovery {
442    &GLOBAL_RESOURCE_DISCOVERY
443}
444
445/// Quick access functions for common operations
446/// Get system resources using global discovery
447#[allow(dead_code)]
448pub fn get_system_resources() -> CoreResult<SystemResources> {
449    global_resource_discovery().discover()
450}
451
452/// Get recommended thread count
453#[allow(dead_code)]
454pub fn get_recommended_thread_count() -> CoreResult<usize> {
455    Ok(get_system_resources()?.recommended_thread_count())
456}
457
458/// Get recommended chunk size
459#[allow(dead_code)]
460pub fn get_recommended_chunk_size() -> CoreResult<usize> {
461    Ok(get_system_resources()?.recommended_chunk_size())
462}
463
464/// Check if SIMD is supported
465#[allow(dead_code)]
466pub fn is_simd_supported() -> CoreResult<bool> {
467    Ok(get_system_resources()?.supports_simd())
468}
469
470/// Check if GPU is available
471#[allow(dead_code)]
472pub fn is_gpu_available() -> CoreResult<bool> {
473    Ok(get_system_resources()?.supports_gpu())
474}
475
476/// Get total system memory
477#[allow(dead_code)]
478pub fn get_total_memory() -> CoreResult<usize> {
479    Ok(get_system_resources()?.total_memory())
480}
481
482/// Get available system memory
483#[allow(dead_code)]
484pub fn get_available_memory() -> CoreResult<usize> {
485    Ok(get_system_resources()?.available_memory())
486}
487
488/// Get performance tier
489#[allow(dead_code)]
490pub fn get_performance_tier() -> CoreResult<PerformanceTier> {
491    Ok(get_system_resources()?.performance_tier())
492}
493
494/// Resource monitoring for adaptive optimization
495pub struct ResourceMonitor {
496    discovery: ResourceDiscovery,
497    monitoring_interval: Duration,
498    last_update: std::sync::Mutex<std::time::Instant>,
499    adaptive_params: std::sync::Mutex<optimization::OptimizationParams>,
500}
501
502impl ResourceMonitor {
503    /// Create a new resource monitor
504    pub fn new(config: DiscoveryConfig, monitoringinterval: Duration) -> Self {
505        let discovery = ResourceDiscovery::new(config);
506
507        Self {
508            discovery,
509            monitoring_interval: monitoringinterval,
510            last_update: std::sync::Mutex::new(std::time::Instant::now()),
511            adaptive_params: std::sync::Mutex::new(optimization::OptimizationParams::default()),
512        }
513    }
514
515    /// Update optimization parameters based on current resource state
516    pub fn update_optimization_params(&self) -> CoreResult<optimization::OptimizationParams> {
517        let should_update = {
518            if let Ok(last_update) = self.last_update.lock() {
519                last_update.elapsed() >= self.monitoring_interval
520            } else {
521                true
522            }
523        };
524
525        if should_update {
526            let resources = self.discovery.discover_fresh()?;
527
528            // Update cached parameters
529            if let Ok(mut params) = self.adaptive_params.lock() {
530                *params = resources.optimization_params.clone();
531            }
532
533            // Update timestamp
534            if let Ok(mut last_update) = self.last_update.lock() {
535                *last_update = std::time::Instant::now();
536            }
537
538            Ok(resources.optimization_params)
539        } else {
540            // Return cached parameters
541            if let Ok(params) = self.adaptive_params.lock() {
542                Ok(params.clone())
543            } else {
544                Err(CoreError::ComputationError(
545                    crate::error::ErrorContext::new("Failed to read adaptive parameters"),
546                ))
547            }
548        }
549    }
550
551    /// Get current optimization parameters
552    pub fn current_params(&self) -> CoreResult<optimization::OptimizationParams> {
553        if let Ok(params) = self.adaptive_params.lock() {
554            Ok(params.clone())
555        } else {
556            Err(CoreError::ComputationError(
557                crate::error::ErrorContext::new("Failed to read current parameters"),
558            ))
559        }
560    }
561}
562
563#[cfg(test)]
564mod tests {
565    use super::*;
566
567    #[test]
568    fn test_discovery_config() {
569        let config = DiscoveryConfig::new()
570            .detect_essential()
571            .with_cache_duration(Duration::from_secs(60))
572            .with_detailed_detection(true);
573
574        assert!(config.detect_cpu);
575        assert!(config.detect_memory);
576        assert!(!config.detect_gpu);
577        assert_eq!(config.cache_duration, Duration::from_secs(60));
578        assert!(config.detailed_detection);
579    }
580
581    #[test]
582    fn test_performance_tier() {
583        assert_eq!(PerformanceTier::High, PerformanceTier::High);
584        assert_ne!(PerformanceTier::High, PerformanceTier::Low);
585    }
586
587    #[test]
588    fn test_resource_discovery() {
589        let config = DiscoveryConfig::new().detect_essential();
590        let discovery = ResourceDiscovery::new(config);
591
592        // This should work on any system
593        let resources = discovery.discover();
594        assert!(resources.is_ok());
595    }
596
597    #[test]
598    fn test_global_functions() {
599        // These should work on any system
600        let thread_count = get_recommended_thread_count();
601        assert!(thread_count.is_ok());
602        assert!(thread_count.unwrap() > 0);
603
604        let chunk_size = get_recommended_chunk_size();
605        assert!(chunk_size.is_ok());
606        assert!(chunk_size.unwrap() > 0);
607    }
608
609    #[test]
610    fn test_resourcemonitor() {
611        let config = DiscoveryConfig::new().detect_essential();
612        let monitor = ResourceMonitor::new(config, Duration::from_secs(1));
613
614        let params = monitor.update_optimization_params();
615        assert!(params.is_ok());
616
617        let current = monitor.current_params();
618        assert!(current.is_ok());
619    }
620}