From 18f56ad5cce8bc2d129167ab3dd53af4a83662a4 Mon Sep 17 00:00:00 2001 From: csehviktor Date: Thu, 3 Jul 2025 06:12:03 +0200 Subject: [PATCH] create cpu breakdown --- agent/src/collector.rs | 17 ++++---- agent/src/cpu.rs | 97 ++++++++++++++++++++++++++++++++++++++++++ agent/src/main.rs | 3 ++ 3 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 agent/src/cpu.rs diff --git a/agent/src/collector.rs b/agent/src/collector.rs index 15531ca..27c65e3 100644 --- a/agent/src/collector.rs +++ b/agent/src/collector.rs @@ -1,10 +1,13 @@ use common::metrics::{Disk, Memory, Metrics, Network, SystemInfo, CPU}; use sysinfo::{Disks, Networks, System}; +use crate::cpu::CpuStatReader; + pub struct Collector { sys: System, disks: Disks, networks: Networks, + cpu_reader: CpuStatReader, } impl Collector { @@ -13,6 +16,7 @@ impl Collector { sys: System::new_all(), disks: Disks::new_with_refreshed_list(), networks: Networks::new_with_refreshed_list(), + cpu_reader: CpuStatReader::new(), } } @@ -46,16 +50,11 @@ impl Collector { } } - fn collect_cpu(&self) -> CPU { - let cpus = self.sys.cpus(); - - let threads = cpus.len(); - let usage = self.sys.global_cpu_usage(); - + fn collect_cpu(&mut self) -> CPU { CPU { - brand: String::from(cpus[0].brand()), - usage, - threads, + usage: self.sys.global_cpu_usage(), + threads: self.sys.cpus().len(), + breakdown: self.cpu_reader.read_global_cpu_stats().unwrap_or_default() } } diff --git a/agent/src/cpu.rs b/agent/src/cpu.rs new file mode 100644 index 0000000..302c9d0 --- /dev/null +++ b/agent/src/cpu.rs @@ -0,0 +1,97 @@ +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), + } + } +} diff --git a/agent/src/main.rs b/agent/src/main.rs index 380cebf..796249d 100644 --- a/agent/src/main.rs +++ b/agent/src/main.rs @@ -5,6 +5,9 @@ use std::time::Duration; use std::thread; pub mod collector; +pub mod config; +pub mod mqtt; +pub mod cpu; #[tokio::main] async fn main() -> anyhow::Result<()> {