memscope_rs/platform/
memory_info.rs

1use std::time::{Duration, Instant};
2
3/// Platform-specific memory information collector
4pub struct PlatformMemoryInfo {
5    /// Last collected statistics
6    last_stats: Option<MemoryStats>,
7    /// Collection interval
8    collection_interval: Duration,
9    /// Last collection time
10    last_collection: Option<Instant>,
11    /// Platform-specific context
12    platform_context: MemoryContext,
13}
14
15/// Comprehensive memory statistics
16#[derive(Debug, Clone)]
17pub struct MemoryStats {
18    /// Virtual memory statistics
19    pub virtual_memory: VirtualMemoryStats,
20    /// Physical memory statistics
21    pub physical_memory: PhysicalMemoryStats,
22    /// Process-specific memory statistics
23    pub process_memory: ProcessMemoryStats,
24    /// System-wide memory statistics
25    pub system_memory: SystemMemoryStats,
26    /// Memory pressure indicators
27    pub pressure_indicators: PressureIndicators,
28    /// Collection timestamp
29    pub timestamp: Instant,
30}
31
32/// Virtual memory statistics
33#[derive(Debug, Clone)]
34pub struct VirtualMemoryStats {
35    /// Total virtual address space
36    pub total_virtual: u64,
37    /// Available virtual address space
38    pub available_virtual: u64,
39    /// Used virtual address space
40    pub used_virtual: u64,
41    /// Reserved but uncommitted memory
42    pub reserved: u64,
43    /// Committed memory
44    pub committed: u64,
45}
46
47/// Physical memory statistics
48#[derive(Debug, Clone)]
49pub struct PhysicalMemoryStats {
50    /// Total physical memory (RAM)
51    pub total_physical: u64,
52    /// Available physical memory
53    pub available_physical: u64,
54    /// Used physical memory
55    pub used_physical: u64,
56    /// Memory used by OS cache
57    pub cached: u64,
58    /// Memory used by OS buffers
59    pub buffers: u64,
60    /// Swap/page file statistics
61    pub swap: SwapStats,
62}
63
64/// Swap/page file statistics
65#[derive(Debug, Clone)]
66pub struct SwapStats {
67    /// Total swap/page file size
68    pub total_swap: u64,
69    /// Used swap/page file
70    pub used_swap: u64,
71    /// Available swap/page file
72    pub available_swap: u64,
73    /// Swap-in rate (pages per second)
74    pub swap_in_rate: f64,
75    /// Swap-out rate (pages per second)
76    pub swap_out_rate: f64,
77}
78
79/// Process-specific memory statistics
80#[derive(Debug, Clone)]
81pub struct ProcessMemoryStats {
82    /// Process virtual memory size
83    pub virtual_size: u64,
84    /// Process resident set size (RSS)
85    pub resident_size: u64,
86    /// Process shared memory
87    pub shared_size: u64,
88    /// Process private memory
89    pub private_size: u64,
90    /// Heap memory usage
91    pub heap_size: u64,
92    /// Stack memory usage
93    pub stack_size: u64,
94    /// Memory-mapped files
95    pub mapped_files: u64,
96    /// Process memory peak usage
97    pub peak_usage: u64,
98}
99
100/// System-wide memory statistics
101#[derive(Debug, Clone)]
102pub struct SystemMemoryStats {
103    /// Number of memory allocations
104    pub allocation_count: u64,
105    /// Number of memory deallocations
106    pub deallocation_count: u64,
107    /// Current active allocations
108    pub active_allocations: u64,
109    /// Total bytes allocated
110    pub total_allocated: u64,
111    /// Total bytes deallocated
112    pub total_deallocated: u64,
113    /// Memory fragmentation level
114    pub fragmentation_level: f64,
115    /// Large page usage
116    pub large_pages: LargePageStats,
117}
118
119/// Large page usage statistics
120#[derive(Debug, Clone)]
121pub struct LargePageStats {
122    /// Whether large pages are supported
123    pub supported: bool,
124    /// Total large page memory
125    pub total_large_pages: u64,
126    /// Used large page memory
127    pub used_large_pages: u64,
128    /// Large page size
129    pub page_size: u64,
130}
131
132/// Memory pressure indicators
133#[derive(Debug, Clone)]
134pub struct PressureIndicators {
135    /// Overall memory pressure level
136    pub pressure_level: PressureLevel,
137    /// Whether system is in low memory condition
138    pub low_memory: bool,
139    /// Whether swapping is occurring
140    pub swapping_active: bool,
141    /// Memory allocation failure rate
142    pub allocation_failure_rate: f64,
143    /// GC pressure (if applicable)
144    pub gc_pressure: Option<f64>,
145}
146
147/// Memory pressure levels
148#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
149pub enum PressureLevel {
150    /// Normal memory pressure
151    Normal,
152    /// Moderate memory pressure
153    Moderate,
154    /// High memory pressure
155    High,
156    /// Critical memory pressure
157    Critical,
158}
159
160/// System information
161#[derive(Debug, Clone)]
162pub struct SystemInfo {
163    /// Operating system name
164    pub os_name: String,
165    /// OS version
166    pub os_version: String,
167    /// System architecture
168    pub architecture: String,
169    /// Number of CPU cores
170    pub cpu_cores: u32,
171    /// CPU cache sizes
172    pub cpu_cache: CpuCacheInfo,
173    /// Page size
174    pub page_size: u64,
175    /// Large page size if supported
176    pub large_page_size: Option<u64>,
177    /// Memory management unit info
178    pub mmu_info: MmuInfo,
179}
180
181/// CPU cache information
182#[derive(Debug, Clone)]
183pub struct CpuCacheInfo {
184    /// L1 cache size per core
185    pub l1_cache_size: u64,
186    /// L2 cache size per core
187    pub l2_cache_size: u64,
188    /// L3 cache size (shared)
189    pub l3_cache_size: Option<u64>,
190    /// Cache line size
191    pub cache_line_size: u64,
192}
193
194/// Memory Management Unit information
195#[derive(Debug, Clone)]
196pub struct MmuInfo {
197    /// Virtual address space size (bits)
198    pub virtual_address_bits: u32,
199    /// Physical address space size (bits)
200    pub physical_address_bits: u32,
201    /// Whether ASLR is enabled
202    pub aslr_enabled: bool,
203    /// Whether NX/XD bit is supported
204    pub nx_bit_supported: bool,
205}
206
207/// Platform-specific context
208#[derive(Debug)]
209struct MemoryContext {
210    /// Whether collector is initialized
211    initialized: bool,
212
213    #[cfg(target_os = "linux")]
214    linux_context: LinuxMemoryContext,
215
216    #[cfg(target_os = "windows")]
217    windows_context: WindowsMemoryContext,
218
219    #[cfg(target_os = "macos")]
220    macos_context: MacOSMemoryContext,
221}
222
223#[cfg(target_os = "linux")]
224#[derive(Debug)]
225struct LinuxMemoryContext {
226    /// Whether /proc/meminfo is accessible
227    proc_meminfo_available: bool,
228    /// Whether /proc/self/status is accessible
229    proc_status_available: bool,
230    /// Whether /proc/self/maps is accessible
231    proc_maps_available: bool,
232}
233
234#[cfg(target_os = "windows")]
235#[derive(Debug)]
236struct WindowsMemoryContext {
237    /// Whether GlobalMemoryStatusEx is available
238    global_memory_api_available: bool,
239    /// Whether GetProcessMemoryInfo is available
240    process_memory_api_available: bool,
241    /// Whether VirtualQueryEx is available
242    virtual_query_available: bool,
243}
244
245#[cfg(target_os = "macos")]
246#[derive(Debug)]
247struct MacOSMemoryContext {
248    /// Whether vm_stat is available
249    vm_stat_available: bool,
250    /// Whether task_info is available
251    task_info_available: bool,
252    /// Whether mach APIs are available
253    mach_api_available: bool,
254}
255
256impl PlatformMemoryInfo {
257    /// Create new memory info collector
258    pub fn new() -> Self {
259        Self {
260            last_stats: None,
261            collection_interval: Duration::from_secs(1),
262            last_collection: None,
263            platform_context: MemoryContext::new(),
264        }
265    }
266
267    /// Initialize memory info collector
268    pub fn initialize(&mut self) -> Result<(), MemoryError> {
269        #[cfg(target_os = "linux")]
270        {
271            self.initialize_linux()
272        }
273
274        #[cfg(target_os = "windows")]
275        {
276            self.initialize_windows()
277        }
278
279        #[cfg(target_os = "macos")]
280        {
281            self.initialize_macos()
282        }
283
284        #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
285        {
286            Err(MemoryError::UnsupportedPlatform)
287        }
288    }
289
290    /// Collect current memory statistics
291    pub fn collect_stats(&mut self) -> Result<MemoryStats, MemoryError> {
292        if !self.platform_context.initialized {
293            return Err(MemoryError::NotInitialized);
294        }
295
296        let now = Instant::now();
297
298        // Check if we should collect (rate limiting)
299        if let Some(last) = self.last_collection {
300            if now.duration_since(last) < self.collection_interval {
301                if let Some(ref stats) = self.last_stats {
302                    return Ok(stats.clone());
303                }
304            }
305        }
306
307        let stats = self.perform_collection()?;
308        self.last_stats = Some(stats.clone());
309        self.last_collection = Some(now);
310
311        Ok(stats)
312    }
313
314    /// Get system information
315    pub fn get_system_info(&self) -> Result<SystemInfo, MemoryError> {
316        if !self.platform_context.initialized {
317            return Err(MemoryError::NotInitialized);
318        }
319
320        #[cfg(target_os = "linux")]
321        return self.get_linux_system_info();
322
323        #[cfg(target_os = "windows")]
324        return self.get_windows_system_info();
325
326        #[cfg(target_os = "macos")]
327        return self.get_macos_system_info();
328
329        #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
330        Err(MemoryError::UnsupportedPlatform)
331    }
332
333    /// Set collection interval
334    pub fn set_collection_interval(&mut self, interval: Duration) {
335        self.collection_interval = interval;
336    }
337
338    /// Get last collected statistics
339    pub fn get_last_stats(&self) -> Option<&MemoryStats> {
340        self.last_stats.as_ref()
341    }
342
343    fn perform_collection(&self) -> Result<MemoryStats, MemoryError> {
344        #[cfg(target_os = "linux")]
345        return self.collect_linux_stats();
346
347        #[cfg(target_os = "windows")]
348        return self.collect_windows_stats();
349
350        #[cfg(target_os = "macos")]
351        return self.collect_macos_stats();
352
353        #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
354        Err(MemoryError::UnsupportedPlatform)
355    }
356
357    #[cfg(target_os = "linux")]
358    fn initialize_linux(&mut self) -> Result<(), MemoryError> {
359        // Check availability of Linux memory information sources
360        self.platform_context.linux_context.proc_meminfo_available =
361            std::path::Path::new("/proc/meminfo").exists();
362        self.platform_context.linux_context.proc_status_available =
363            std::path::Path::new("/proc/self/status").exists();
364        self.platform_context.linux_context.proc_maps_available =
365            std::path::Path::new("/proc/self/maps").exists();
366
367        self.platform_context.initialized = true;
368        Ok(())
369    }
370
371    #[cfg(target_os = "windows")]
372    fn initialize_windows(&mut self) -> Result<(), MemoryError> {
373        // Check availability of Windows memory APIs
374        self.platform_context
375            .windows_context
376            .global_memory_api_available = true; // Simplified
377        self.platform_context
378            .windows_context
379            .process_memory_api_available = true; // Simplified
380        self.platform_context
381            .windows_context
382            .virtual_query_available = true; // Simplified
383
384        self.platform_context.initialized = true;
385        Ok(())
386    }
387
388    #[cfg(target_os = "macos")]
389    fn initialize_macos(&mut self) -> Result<(), MemoryError> {
390        // Check availability of macOS memory APIs
391        self.platform_context.macos_context.vm_stat_available = true; // Simplified
392        self.platform_context.macos_context.task_info_available = true; // Simplified
393        self.platform_context.macos_context.mach_api_available = true; // Simplified
394
395        self.platform_context.initialized = true;
396        Ok(())
397    }
398
399    #[cfg(target_os = "linux")]
400    fn collect_linux_stats(&self) -> Result<MemoryStats, MemoryError> {
401        // Collect Linux memory statistics from /proc filesystem
402        // This is a simplified mock implementation
403        Ok(MemoryStats {
404            virtual_memory: VirtualMemoryStats {
405                total_virtual: 1_099_511_627_776,   // 1TB on 64-bit
406                available_virtual: 549_755_813_888, // 512GB
407                used_virtual: 549_755_813_888,
408                reserved: 274_877_906_944, // 256GB
409                committed: 274_877_906_944,
410            },
411            physical_memory: PhysicalMemoryStats {
412                total_physical: 17_179_869_184,    // 16GB
413                available_physical: 8_589_934_592, // 8GB
414                used_physical: 8_589_934_592,
415                cached: 4_294_967_296,  // 4GB
416                buffers: 1_073_741_824, // 1GB
417                swap: SwapStats {
418                    total_swap: 8_589_934_592, // 8GB
419                    used_swap: 1_073_741_824,  // 1GB
420                    available_swap: 7_516_192_768,
421                    swap_in_rate: 0.0,
422                    swap_out_rate: 0.0,
423                },
424            },
425            process_memory: ProcessMemoryStats {
426                virtual_size: 1_073_741_824, // 1GB
427                resident_size: 536_870_912,  // 512MB
428                shared_size: 134_217_728,    // 128MB
429                private_size: 402_653_184,   // 384MB
430                heap_size: 268_435_456,      // 256MB
431                stack_size: 8_388_608,       // 8MB
432                mapped_files: 134_217_728,   // 128MB
433                peak_usage: 1_073_741_824,
434            },
435            system_memory: SystemMemoryStats {
436                allocation_count: 1_000_000,
437                deallocation_count: 950_000,
438                active_allocations: 50_000,
439                total_allocated: 10_737_418_240,  // 10GB
440                total_deallocated: 9_663_676_416, // 9GB
441                fragmentation_level: 0.15,
442                large_pages: LargePageStats {
443                    supported: true,
444                    total_large_pages: 2_097_152, // 2MB
445                    used_large_pages: 0,
446                    page_size: 2_097_152,
447                },
448            },
449            pressure_indicators: PressureIndicators {
450                pressure_level: PressureLevel::Normal,
451                low_memory: false,
452                swapping_active: false,
453                allocation_failure_rate: 0.001,
454                gc_pressure: None,
455            },
456            timestamp: Instant::now(),
457        })
458    }
459
460    #[cfg(target_os = "windows")]
461    fn collect_windows_stats(&self) -> Result<MemoryStats, MemoryError> {
462        // Collect Windows memory statistics using Windows APIs
463        // This is a simplified mock implementation
464        Ok(MemoryStats {
465            virtual_memory: VirtualMemoryStats {
466                total_virtual: 140_737_488_355_328,    // 128TB on x64
467                available_virtual: 70_368_744_177_664, // 64TB
468                used_virtual: 70_368_744_177_664,
469                reserved: 35_184_372_088_832, // 32TB
470                committed: 35_184_372_088_832,
471            },
472            physical_memory: PhysicalMemoryStats {
473                total_physical: 34_359_738_368,     // 32GB
474                available_physical: 17_179_869_184, // 16GB
475                used_physical: 17_179_869_184,
476                cached: 8_589_934_592,  // 8GB
477                buffers: 2_147_483_648, // 2GB
478                swap: SwapStats {
479                    total_swap: 17_179_869_184, // 16GB page file
480                    used_swap: 2_147_483_648,   // 2GB
481                    available_swap: 15_032_385_536,
482                    swap_in_rate: 0.0,
483                    swap_out_rate: 0.0,
484                },
485            },
486            process_memory: ProcessMemoryStats {
487                virtual_size: 2_147_483_648,  // 2GB
488                resident_size: 1_073_741_824, // 1GB
489                shared_size: 268_435_456,     // 256MB
490                private_size: 805_306_368,    // 768MB
491                heap_size: 536_870_912,       // 512MB
492                stack_size: 16_777_216,       // 16MB
493                mapped_files: 268_435_456,    // 256MB
494                peak_usage: 2_147_483_648,
495            },
496            system_memory: SystemMemoryStats {
497                allocation_count: 2_000_000,
498                deallocation_count: 1_900_000,
499                active_allocations: 100_000,
500                total_allocated: 21_474_836_480,   // 20GB
501                total_deallocated: 19_327_352_832, // 18GB
502                fragmentation_level: 0.12,
503                large_pages: LargePageStats {
504                    supported: true,
505                    total_large_pages: 2_097_152, // 2MB
506                    used_large_pages: 0,
507                    page_size: 2_097_152,
508                },
509            },
510            pressure_indicators: PressureIndicators {
511                pressure_level: PressureLevel::Normal,
512                low_memory: false,
513                swapping_active: false,
514                allocation_failure_rate: 0.0005,
515                gc_pressure: None,
516            },
517            timestamp: Instant::now(),
518        })
519    }
520
521    #[cfg(target_os = "macos")]
522    fn collect_macos_stats(&self) -> Result<MemoryStats, MemoryError> {
523        // Collect macOS memory statistics using mach APIs
524        // This is a simplified mock implementation
525        Ok(MemoryStats {
526            virtual_memory: VirtualMemoryStats {
527                total_virtual: 1_099_511_627_776,   // 1TB
528                available_virtual: 549_755_813_888, // 512GB
529                used_virtual: 549_755_813_888,
530                reserved: 274_877_906_944, // 256GB
531                committed: 274_877_906_944,
532            },
533            physical_memory: PhysicalMemoryStats {
534                total_physical: 68_719_476_736,     // 64GB
535                available_physical: 34_359_738_368, // 32GB
536                used_physical: 34_359_738_368,
537                cached: 17_179_869_184, // 16GB
538                buffers: 4_294_967_296, // 4GB
539                swap: SwapStats {
540                    total_swap: 34_359_738_368, // 32GB
541                    used_swap: 4_294_967_296,   // 4GB
542                    available_swap: 30_064_771_072,
543                    swap_in_rate: 0.0,
544                    swap_out_rate: 0.0,
545                },
546            },
547            process_memory: ProcessMemoryStats {
548                virtual_size: 4_294_967_296,  // 4GB
549                resident_size: 2_147_483_648, // 2GB
550                shared_size: 536_870_912,     // 512MB
551                private_size: 1_610_612_736,  // 1.5GB
552                heap_size: 1_073_741_824,     // 1GB
553                stack_size: 33_554_432,       // 32MB
554                mapped_files: 536_870_912,    // 512MB
555                peak_usage: 4_294_967_296,
556            },
557            system_memory: SystemMemoryStats {
558                allocation_count: 1_500_000,
559                deallocation_count: 1_425_000,
560                active_allocations: 75_000,
561                total_allocated: 16_106_127_360,   // 15GB
562                total_deallocated: 14_495_514_624, // 13.5GB
563                fragmentation_level: 0.10,
564                large_pages: LargePageStats {
565                    supported: false,
566                    total_large_pages: 0,
567                    used_large_pages: 0,
568                    page_size: 0,
569                },
570            },
571            pressure_indicators: PressureIndicators {
572                pressure_level: PressureLevel::Normal,
573                low_memory: false,
574                swapping_active: false,
575                allocation_failure_rate: 0.0002,
576                gc_pressure: None,
577            },
578            timestamp: Instant::now(),
579        })
580    }
581
582    #[cfg(target_os = "linux")]
583    fn get_linux_system_info(&self) -> Result<SystemInfo, MemoryError> {
584        Ok(SystemInfo {
585            os_name: "Linux".to_string(),
586            os_version: "5.15.0".to_string(),
587            architecture: "x86_64".to_string(),
588            cpu_cores: 8,
589            cpu_cache: CpuCacheInfo {
590                l1_cache_size: 32768,         // 32KB
591                l2_cache_size: 262144,        // 256KB
592                l3_cache_size: Some(8388608), // 8MB
593                cache_line_size: 64,
594            },
595            page_size: 4096,
596            large_page_size: Some(2097152), // 2MB
597            mmu_info: MmuInfo {
598                virtual_address_bits: 48,
599                physical_address_bits: 40,
600                aslr_enabled: true,
601                nx_bit_supported: true,
602            },
603        })
604    }
605
606    #[cfg(target_os = "windows")]
607    fn get_windows_system_info(&self) -> Result<SystemInfo, MemoryError> {
608        Ok(SystemInfo {
609            os_name: "Windows".to_string(),
610            os_version: "10.0.19045".to_string(),
611            architecture: "x86_64".to_string(),
612            cpu_cores: 16,
613            cpu_cache: CpuCacheInfo {
614                l1_cache_size: 32768,          // 32KB
615                l2_cache_size: 524288,         // 512KB
616                l3_cache_size: Some(16777216), // 16MB
617                cache_line_size: 64,
618            },
619            page_size: 4096,
620            large_page_size: Some(2097152), // 2MB
621            mmu_info: MmuInfo {
622                virtual_address_bits: 48,
623                physical_address_bits: 40,
624                aslr_enabled: true,
625                nx_bit_supported: true,
626            },
627        })
628    }
629
630    #[cfg(target_os = "macos")]
631    fn get_macos_system_info(&self) -> Result<SystemInfo, MemoryError> {
632        Ok(SystemInfo {
633            os_name: "macOS".to_string(),
634            os_version: "14.1.0".to_string(),
635            architecture: "arm64".to_string(),
636            cpu_cores: 12,
637            cpu_cache: CpuCacheInfo {
638                l1_cache_size: 65536,   // 64KB
639                l2_cache_size: 4194304, // 4MB
640                l3_cache_size: None,    // Unified memory architecture
641                cache_line_size: 128,
642            },
643            page_size: 16384,      // 16KB on Apple Silicon
644            large_page_size: None, // Not supported on Apple Silicon
645            mmu_info: MmuInfo {
646                virtual_address_bits: 48,
647                physical_address_bits: 40,
648                aslr_enabled: true,
649                nx_bit_supported: true,
650            },
651        })
652    }
653}
654
655impl MemoryContext {
656    fn new() -> Self {
657        Self {
658            initialized: false,
659            #[cfg(target_os = "linux")]
660            linux_context: LinuxMemoryContext {
661                proc_meminfo_available: false,
662                proc_status_available: false,
663                proc_maps_available: false,
664            },
665            #[cfg(target_os = "windows")]
666            windows_context: WindowsMemoryContext {
667                global_memory_api_available: false,
668                process_memory_api_available: false,
669                virtual_query_available: false,
670            },
671            #[cfg(target_os = "macos")]
672            macos_context: MacOSMemoryContext {
673                vm_stat_available: false,
674                task_info_available: false,
675                mach_api_available: false,
676            },
677        }
678    }
679}
680
681/// Errors that can occur during memory information collection
682#[derive(Debug, Clone, PartialEq)]
683pub enum MemoryError {
684    /// Platform not supported
685    UnsupportedPlatform,
686    /// Collector not initialized
687    NotInitialized,
688    /// Permission denied
689    PermissionDenied,
690    /// System API error
691    SystemError(String),
692    /// Parse error
693    ParseError(String),
694    /// I/O error
695    IoError(String),
696}
697
698impl Default for PlatformMemoryInfo {
699    fn default() -> Self {
700        Self::new()
701    }
702}
703
704impl std::fmt::Display for MemoryError {
705    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
706        match self {
707            MemoryError::UnsupportedPlatform => {
708                write!(f, "Platform not supported for memory info collection")
709            }
710            MemoryError::NotInitialized => write!(f, "Memory info collector not initialized"),
711            MemoryError::PermissionDenied => write!(f, "Permission denied for memory info access"),
712            MemoryError::SystemError(msg) => write!(f, "System error: {}", msg),
713            MemoryError::ParseError(msg) => write!(f, "Parse error: {}", msg),
714            MemoryError::IoError(msg) => write!(f, "I/O error: {}", msg),
715        }
716    }
717}
718
719impl std::error::Error for MemoryError {}
720
721#[cfg(test)]
722mod tests {
723    use super::*;
724
725    #[test]
726    fn test_memory_info_creation() {
727        let info = PlatformMemoryInfo::new();
728        assert!(!info.platform_context.initialized);
729        assert!(info.last_stats.is_none());
730    }
731
732    #[test]
733    fn test_initialization() {
734        let mut info = PlatformMemoryInfo::new();
735        let result = info.initialize();
736
737        #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
738        assert!(result.is_ok());
739
740        #[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
741        assert_eq!(result, Err(MemoryError::UnsupportedPlatform));
742    }
743
744    #[test]
745    fn test_stats_collection() {
746        let mut info = PlatformMemoryInfo::new();
747        let _ = info.initialize();
748
749        let result = info.collect_stats();
750
751        #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
752        {
753            if info.platform_context.initialized {
754                assert!(result.is_ok());
755                let stats = result.expect("Stats should be collected");
756                assert!(stats.physical_memory.total_physical > 0);
757                assert!(stats.virtual_memory.total_virtual > 0);
758            }
759        }
760    }
761
762    #[test]
763    fn test_system_info() {
764        let mut info = PlatformMemoryInfo::new();
765        let _ = info.initialize();
766
767        let result = info.get_system_info();
768
769        #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
770        {
771            if info.platform_context.initialized {
772                assert!(result.is_ok());
773                let sys_info = result.expect("System info should be available");
774                assert!(!sys_info.os_name.is_empty());
775                assert!(sys_info.cpu_cores > 0);
776                assert!(sys_info.page_size > 0);
777            }
778        }
779    }
780
781    #[test]
782    fn test_pressure_level_ordering() {
783        assert!(PressureLevel::Critical > PressureLevel::High);
784        assert!(PressureLevel::High > PressureLevel::Moderate);
785        assert!(PressureLevel::Moderate > PressureLevel::Normal);
786    }
787
788    #[test]
789    fn test_collection_interval() {
790        let mut info = PlatformMemoryInfo::new();
791        info.set_collection_interval(Duration::from_millis(500));
792        assert_eq!(info.collection_interval, Duration::from_millis(500));
793    }
794}