use std::collections::HashMap; use common::metrics::CpuBreakdown; #[derive(Debug, Clone, Copy)] struct CpuValues { pub user: u64, pub nice: u64, pub system: u64, pub idle: u64, pub iowait: u64, pub irq: u64, pub softirq: u64, pub steal: u64, pub guest: u64, pub guest_nice: u64, } impl CpuValues { pub fn total(&self) -> u64 { self.user + self.nice + self.system + self.idle + self.iowait + self.irq + self.softirq + self.steal + self.guest + self.guest_nice } } pub struct CpuStatReader { previous_stats: HashMap, } impl CpuStatReader { pub fn new() -> Self { Self { previous_stats: HashMap::new() } } pub fn read_global_cpu_stats(&mut self) -> anyhow::Result { let content = std::fs::read_to_string("/proc/stat").unwrap(); let cpu_line = content .lines() .find(|line| line.starts_with("cpu ")) .unwrap(); self.parse_cpu_line(cpu_line) } fn parse_cpu_line(&mut self, line: &str) -> anyhow::Result { let parts: Vec<&str> = line.split_whitespace().collect(); let cpu_name = parts[0].to_string(); let parse = |num: usize| -> u64 { parts[num].parse().ok().unwrap() }; let values = CpuValues { user: parse(1), nice: parse(2), system: parse(3), idle: parse(4), iowait: parse(5), irq: parse(6), softirq: parse(7), steal: parse(8), guest: parse(9), guest_nice: parse(10), }; let previous = self.previous_stats.get(&cpu_name).copied(); let percentages = self.calculate_percentages(&values, previous); self.previous_stats.insert(cpu_name, values); Ok(percentages) } fn calculate_percentages(&self, current: &CpuValues, previous: Option) -> CpuBreakdown { let Some(prev) = previous else { return CpuBreakdown::default(); }; let total_delta = current.total().saturating_sub(prev.total()) as f32; if total_delta <= 0.0 { return CpuBreakdown::default(); } let calculate_pct = |current: u64, prev: u64| { (current.saturating_sub(prev) as f32 / total_delta) * 100.0 }; CpuBreakdown { system: calculate_pct(current.system, prev.system), user: calculate_pct(current.user, prev.user), idle: calculate_pct(current.idle, prev.idle), steal: calculate_pct(current.steal, prev.steal), iowait: calculate_pct(current.iowait, prev.iowait), } } }