use crate::error::{IoError, Result};
use std::time::{Duration, Instant};
#[derive(Debug)]
pub struct ResourceMonitor {
system_metrics: SystemMetrics,
monitoring_interval: Duration,
last_update: Instant,
}
impl Default for ResourceMonitor {
fn default() -> Self {
Self::new()
}
}
impl ResourceMonitor {
pub fn new() -> Self {
Self {
system_metrics: SystemMetrics::default(),
monitoring_interval: Duration::from_millis(100),
last_update: Instant::now(),
}
}
pub fn get_current_metrics(&mut self) -> Result<SystemMetrics> {
if self.last_update.elapsed() >= self.monitoring_interval {
self.update_metrics()?;
self.last_update = Instant::now();
}
Ok(self.system_metrics.clone())
}
fn update_metrics(&mut self) -> Result<()> {
self.system_metrics.cpu_usage = self.get_cpu_usage()?;
self.system_metrics.memory_usage = self.get_memory_usage()?;
self.system_metrics.io_utilization = self.get_io_utilization()?;
self.system_metrics.network_bandwidth_usage = self.get_network_usage()?;
self.system_metrics.cache_performance = self.get_cache_performance()?;
Ok(())
}
fn get_cpu_usage(&self) -> Result<f64> {
#[cfg(target_os = "linux")]
{
self.get_linux_cpu_usage()
}
#[cfg(target_os = "windows")]
{
self.get_windows_cpu_usage()
}
#[cfg(target_os = "macos")]
{
self.get_macos_cpu_usage()
}
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
{
Ok(0.5) }
}
#[cfg(target_os = "linux")]
fn get_linux_cpu_usage(&self) -> Result<f64> {
let stat_content = std::fs::read_to_string("/proc/stat")
.map_err(|e| IoError::Other(format!("Failed to read /proc/stat: {}", e)))?;
if let Some(cpu_line) = stat_content.lines().next() {
let values: Vec<u64> = cpu_line
.split_whitespace()
.skip(1)
.take(4)
.filter_map(|s| s.parse().ok())
.collect();
if values.len() >= 4 {
let idle = values[3];
let total: u64 = values.iter().sum();
return Ok(1.0 - (idle as f64) / (total as f64));
}
}
Ok(0.5) }
#[cfg(target_os = "windows")]
fn get_windows_cpu_usage(&self) -> Result<f64> {
Ok(0.5) }
#[cfg(target_os = "macos")]
fn get_macos_cpu_usage(&self) -> Result<f64> {
Ok(0.5) }
fn get_memory_usage(&self) -> Result<MemoryUsage> {
#[cfg(target_os = "linux")]
{
self.get_linux_memory_usage()
}
#[cfg(not(target_os = "linux"))]
{
Ok(MemoryUsage {
total: 8 * 1024 * 1024 * 1024, available: 4 * 1024 * 1024 * 1024, used: 4 * 1024 * 1024 * 1024,
utilization: 0.5,
})
}
}
#[cfg(target_os = "linux")]
fn get_linux_memory_usage(&self) -> Result<MemoryUsage> {
let meminfo_content = std::fs::read_to_string("/proc/meminfo")
.map_err(|e| IoError::Other(format!("Failed to read /proc/meminfo: {}", e)))?;
let mut total = 0u64;
let mut available = 0u64;
for line in meminfo_content.lines() {
if line.starts_with("MemTotal:") {
total = line
.split_whitespace()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(0)
* 1024; } else if line.starts_with("MemAvailable:") {
available = line
.split_whitespace()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(0)
* 1024; }
}
let used = total - available;
let utilization = if total > 0 {
used as f64 / total as f64
} else {
0.0
};
Ok(MemoryUsage {
total,
available,
used,
utilization,
})
}
fn get_io_utilization(&self) -> Result<f64> {
Ok(0.3) }
fn get_network_usage(&self) -> Result<f64> {
Ok(0.2) }
fn get_cache_performance(&self) -> Result<CachePerformance> {
Ok(CachePerformance {
l1_hit_rate: 0.95,
l2_hit_rate: 0.85,
l3_hit_rate: 0.75,
tlb_hit_rate: 0.99,
})
}
}
#[derive(Debug, Clone)]
pub struct SystemMetrics {
pub cpu_usage: f64,
pub memory_usage: MemoryUsage,
pub io_utilization: f64,
pub network_bandwidth_usage: f64,
pub cache_performance: CachePerformance,
pub numa_topology: NumaTopology,
}
impl Default for SystemMetrics {
fn default() -> Self {
Self {
cpu_usage: 0.5,
memory_usage: MemoryUsage {
total: 8 * 1024 * 1024 * 1024,
available: 4 * 1024 * 1024 * 1024,
used: 4 * 1024 * 1024 * 1024,
utilization: 0.5,
},
io_utilization: 0.3,
network_bandwidth_usage: 0.2,
cache_performance: CachePerformance {
l1_hit_rate: 0.95,
l2_hit_rate: 0.85,
l3_hit_rate: 0.75,
tlb_hit_rate: 0.99,
},
numa_topology: NumaTopology::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct MemoryUsage {
pub total: u64,
pub available: u64,
pub used: u64,
pub utilization: f64,
}
#[derive(Debug, Clone)]
pub struct CachePerformance {
pub l1_hit_rate: f64,
pub l2_hit_rate: f64,
pub l3_hit_rate: f64,
pub tlb_hit_rate: f64,
}
#[derive(Debug, Clone)]
pub struct NumaTopology {
pub nodes: Vec<NumaNode>,
pub preferred_node: usize,
}
impl Default for NumaTopology {
fn default() -> Self {
Self {
nodes: vec![NumaNode {
id: 0,
memory_size: 8 * 1024 * 1024 * 1024,
cpu_cores: vec![0, 1, 2, 3],
}],
preferred_node: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct NumaNode {
pub id: usize,
pub memory_size: u64,
pub cpu_cores: Vec<usize>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resource_monitor_creation() {
let monitor = ResourceMonitor::new();
assert!(monitor.monitoring_interval > Duration::from_millis(0));
}
#[test]
fn test_system_metrics_default() {
let metrics = SystemMetrics::default();
assert!(metrics.cpu_usage >= 0.0 && metrics.cpu_usage <= 1.0);
assert!(metrics.memory_usage.total > 0);
assert!(metrics.cache_performance.l1_hit_rate > 0.0);
}
#[test]
fn test_numa_topology_default() {
let topology = NumaTopology::default();
assert!(!topology.nodes.is_empty());
assert_eq!(topology.preferred_node, 0);
}
}