use std::fs::File; use std::io::{self, BufRead, BufReader}; use std::thread; use std::time::Duration; use crate::common; use crate::bar_modules; #[derive(Debug, Default, Clone)] struct CpuTimes { user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64, } impl CpuTimes { pub fn new() -> Self { CpuTimes { user: 0, nice: 0, system: 0, idle: 0, iowait: 0, irq: 0, softirq: 0, steal: 0, guest: 0, guest_nice: 0 } } 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 } fn idle(&self) -> u64 { self.idle + self.iowait } } #[derive(Clone)] pub struct UnibarModuleCpu { opts: common::AppOptions, cpu_times_sample_1: CpuTimes, cpu_times_sample_2: CpuTimes, } impl UnibarModuleCpu { // -------------------- pub fn new(o :common::AppOptions) -> Self { UnibarModuleCpu { opts: o, cpu_times_sample_1: CpuTimes::new(), cpu_times_sample_2: CpuTimes::new(), } } // -------------------- // cpu 242109 7 60985 6538626 8344 39138 9647 0 0 0 // * user – time spent in user mode // * nice – time spent processing nice processes in user mode // * system – time spent executing kernel code // * idle – time spent idle // * iowait – time spent waiting for I/O // * irq – time spent servicing interrupts // * softirq – time spent servicing software interrupts // * steal – time stolen from a virtual machine // * guest – time spent running a virtual CPU for a guest operating system // * guest_nice – time spent running a virtual CPU for a “niced” guest operating system fn read_cpu_times(&self) -> io::Result { let file = File::open("/proc/stat")?; let reader = BufReader::new(file); for line in reader.lines() { let line = line?; if line.starts_with("cpu ") { let fields: Vec = line.split_whitespace().skip(1).map(|s| s.parse().unwrap_or(0)).collect(); if fields.len() >= 8 { return Ok(CpuTimes { user: fields[0], nice: fields[1], system: fields[2], idle: fields[3], iowait: fields[4], irq: fields[5], softirq: fields[6], steal: fields[7], guest: if fields.len() > 8 { fields[8] } else { 0 }, guest_nice: if fields.len() > 9 { fields[9] } else { 0 }, }); } } } Err(io::Error::new(io::ErrorKind::InvalidData, "Could not find cpu line in /proc/stat")) } } impl bar_modules::BarModuleActions for UnibarModuleCpu { // -------------------- fn clear(&mut self) { self.cpu_times_sample_1 = CpuTimes::new(); self.cpu_times_sample_2 = CpuTimes::new(); } // -------------------- fn generate_data(&mut self) { self.cpu_times_sample_1 = self.read_cpu_times().expect("Trouble getting CPU times sample 1"); thread::sleep(Duration::from_millis(500)); self.cpu_times_sample_2 = self.read_cpu_times().expect("Trouble getting CPU times sample 2"); if self.opts.debug { println!("-----> CPU times sample 1 - {:#?}", self.cpu_times_sample_1); println!("-----> CPU times sample 2 - {:#?}", self.cpu_times_sample_2); } } // -------------------- fn get_content(&self) -> String { let sample_1_total = self.cpu_times_sample_1.total(); let sample_2_total = self.cpu_times_sample_2.total(); let sample_1_idle = self.cpu_times_sample_1.idle(); let sample_2_idle = self.cpu_times_sample_2.idle(); let total_diff = sample_2_total - sample_1_total; let idle_diff = sample_2_idle - sample_1_idle; if total_diff > 0 { let cpu_usage = (1.0 - (idle_diff as f64 / total_diff as f64)) * 100.0; return format!("{}%", cpu_usage.ceil() as i32); } else { return format!("CPU?"); } } // -------------------- fn get_icon(&self) -> String { return "💻".to_string(); } } impl bar_modules::BarModuleDebug for UnibarModuleCpu { // -------------------- fn post_debug(&self) { } }