From f26d598410c63dd5fcf6ed10bdd4b56e75697390 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Thu, 2 Mar 2023 00:03:54 -0500 Subject: refactor: migrate CPU from heim to sysinfo for all platforms (#1035) * refactor: migrate CPU from heim to sysinfo for all platforms * fix windows and macos imports * simplify a bit of code * cleanup --- src/app/data_harvester.rs | 81 ++++-------- src/app/data_harvester/cpu.rs | 11 +- src/app/data_harvester/cpu/heim.rs | 159 ----------------------- src/app/data_harvester/cpu/heim/linux.rs | 19 --- src/app/data_harvester/cpu/heim/unix.rs | 13 -- src/app/data_harvester/cpu/heim/windows_macos.rs | 12 -- src/app/data_harvester/cpu/sysinfo.rs | 8 +- src/app/data_harvester/processes/linux.rs | 45 ++++--- 8 files changed, 55 insertions(+), 293 deletions(-) delete mode 100644 src/app/data_harvester/cpu/heim.rs delete mode 100644 src/app/data_harvester/cpu/heim/linux.rs delete mode 100644 src/app/data_harvester/cpu/heim/unix.rs delete mode 100644 src/app/data_harvester/cpu/heim/windows_macos.rs (limited to 'src') diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index e25f0be4..d3c4d715 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -10,7 +10,6 @@ use fxhash::FxHashMap; #[cfg(feature = "battery")] use starship_battery::{Battery, Manager}; -#[cfg(not(target_os = "linux"))] use sysinfo::{System, SystemExt}; use super::DataFilters; @@ -99,10 +98,7 @@ impl Data { #[derive(Debug)] pub struct DataCollector { pub data: Data, - #[cfg(not(target_os = "linux"))] sys: System, - previous_cpu_times: Vec<(cpu::PastCpuWork, cpu::PastCpuTotal)>, - previous_average_cpu_time: Option<(cpu::PastCpuWork, cpu::PastCpuTotal)>, #[cfg(target_os = "linux")] pid_mapping: FxHashMap, #[cfg(target_os = "linux")] @@ -132,10 +128,7 @@ impl DataCollector { pub fn new(filters: DataFilters) -> Self { DataCollector { data: Data::default(), - #[cfg(not(target_os = "linux"))] sys: System::new_with_specifics(sysinfo::RefreshKind::new()), - previous_cpu_times: vec![], - previous_average_cpu_time: None, #[cfg(target_os = "linux")] pid_mapping: FxHashMap::default(), #[cfg(target_os = "linux")] @@ -186,16 +179,16 @@ impl DataCollector { self.sys.refresh_users_list(); } - if self.widgets_to_harvest.use_proc || self.widgets_to_harvest.use_cpu { - self.sys.refresh_cpu(); - } - // Refresh disk list once... if cfg!(target_os = "freebsd") && self.widgets_to_harvest.use_disk { self.sys.refresh_disks_list(); } } + if self.widgets_to_harvest.use_proc || self.widgets_to_harvest.use_cpu { + self.sys.refresh_cpu(); + } + #[cfg(feature = "battery")] { if self.widgets_to_harvest.use_battery { @@ -216,8 +209,6 @@ impl DataCollector { std::thread::sleep(std::time::Duration::from_millis(250)); self.data.cleanup(); - - // trace!("Enabled widgets to harvest: {:#?}", self.widgets_to_harvest); } #[cfg(target_os = "linux")] @@ -250,11 +241,12 @@ impl DataCollector { } pub async fn update_data(&mut self) { + if self.widgets_to_harvest.use_proc || self.widgets_to_harvest.use_cpu { + self.sys.refresh_cpu(); + } + #[cfg(not(target_os = "linux"))] { - if self.widgets_to_harvest.use_proc || self.widgets_to_harvest.use_cpu { - self.sys.refresh_cpu(); - } if self.widgets_to_harvest.use_proc { self.sys.refresh_processes(); } @@ -284,38 +276,12 @@ impl DataCollector { // CPU if self.widgets_to_harvest.use_cpu { - #[cfg(not(target_os = "freebsd"))] - { - if let Ok(cpu_data) = cpu::get_cpu_data_list( - self.show_average_cpu, - &mut self.previous_cpu_times, - &mut self.previous_average_cpu_time, - ) - .await - { - self.data.cpu = Some(cpu_data); - } - } - #[cfg(target_os = "freebsd")] - { - if let Ok(cpu_data) = cpu::get_cpu_data_list( - &self.sys, - self.show_average_cpu, - &mut self.previous_cpu_times, - &mut self.previous_average_cpu_time, - ) - .await - { - self.data.cpu = Some(cpu_data); - } - } + self.data.cpu = cpu::get_cpu_data_list(&self.sys, self.show_average_cpu).ok(); #[cfg(target_family = "unix")] { // Load Average - if let Ok(load_avg_data) = cpu::get_load_avg().await { - self.data.load_avg = Some(load_avg_data); - } + self.data.load_avg = cpu::get_load_avg().ok(); } } @@ -334,24 +300,23 @@ impl DataCollector { if let Ok(mut process_list) = { #[cfg(target_os = "linux")] { - // Must do this here since we otherwise have to make `get_process_data` async. - use self::processes::CpuUsageStrategy; - - let normalize_cpu = if self.unnormalized_cpu { - heim::cpu::logical_count() - .await - .map(|v| CpuUsageStrategy::NonNormalized(v as f64)) - .unwrap_or(CpuUsageStrategy::Normalized) - } else { - CpuUsageStrategy::Normalized + use self::processes::{PrevProc, ProcHarvestOptions}; + + let prev_proc = PrevProc { + prev_idle: &mut self.prev_idle, + prev_non_idle: &mut self.prev_non_idle, + }; + + let proc_harvest_options = ProcHarvestOptions { + use_current_cpu_total: self.use_current_cpu_total, + unnormalized_cpu: self.unnormalized_cpu, }; processes::get_process_data( - &mut self.prev_idle, - &mut self.prev_non_idle, + &self.sys, + prev_proc, &mut self.pid_mapping, - self.use_current_cpu_total, - normalize_cpu, + proc_harvest_options, current_instant .duration_since(self.last_collection_time) .as_secs(), diff --git a/src/app/data_harvester/cpu.rs b/src/app/data_harvester/cpu.rs index c4131876..a827b26c 100644 --- a/src/app/data_harvester/cpu.rs +++ b/src/app/data_harvester/cpu.rs @@ -4,15 +4,8 @@ //! //! For load average, macOS and Linux are supported through Heim, FreeBSD by sysinfo. -cfg_if::cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))] { - pub mod heim; - pub use self::heim::*; - } else if #[cfg(target_os = "freebsd")] { - pub mod sysinfo; - pub use self::sysinfo::*; - } -} +pub mod sysinfo; +pub use self::sysinfo::*; pub type LoadAvgHarvest = [f32; 3]; diff --git a/src/app/data_harvester/cpu/heim.rs b/src/app/data_harvester/cpu/heim.rs deleted file mode 100644 index f3aa92aa..00000000 --- a/src/app/data_harvester/cpu/heim.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! CPU stats through heim. -//! Supports macOS, Linux, and Windows. - -cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - pub mod linux; - pub use linux::*; - } else if #[cfg(any(target_os = "macos", target_os = "windows"))] { - pub mod windows_macos; - pub use windows_macos::*; - } -} - -cfg_if::cfg_if! { - if #[cfg(target_family = "unix")] { - pub mod unix; - pub use unix::*; - } -} - -use std::collections::VecDeque; - -use futures::StreamExt; - -use crate::{ - components::tui_widget::time_chart::Point, - data_harvester::cpu::{CpuData, CpuDataType, CpuHarvest, PastCpuTotal, PastCpuWork}, -}; - -pub async fn get_cpu_data_list( - show_average_cpu: bool, previous_cpu_times: &mut Vec<(PastCpuWork, PastCpuTotal)>, - previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>, -) -> crate::error::Result { - fn calculate_cpu_usage_percentage( - (previous_working_time, previous_total_time): Point, - (current_working_time, current_total_time): Point, - ) -> f64 { - ((if current_working_time > previous_working_time { - current_working_time - previous_working_time - } else { - 0.0 - }) * 100.0) - / (if current_total_time > previous_total_time { - current_total_time - previous_total_time - } else { - 1.0 - }) - } - - // Get all CPU times... - let cpu_times = heim::cpu::times().await?; - futures::pin_mut!(cpu_times); - - let mut cpu_deque: VecDeque = if previous_cpu_times.is_empty() { - // Must initialize ourselves. Use a very quick timeout to calculate an initial. - futures_timer::Delay::new(std::time::Duration::from_millis(100)).await; - - let second_cpu_times = heim::cpu::times().await?; - futures::pin_mut!(second_cpu_times); - - let mut new_cpu_times: Vec<(PastCpuWork, PastCpuTotal)> = Vec::new(); - let mut cpu_deque: VecDeque = VecDeque::new(); - let mut collected_zip = cpu_times.zip(second_cpu_times).enumerate(); // Gotta move it here, can't on while line. - - while let Some((itx, (past, present))) = collected_zip.next().await { - if let (Ok(past), Ok(present)) = (past, present) { - let present_times = convert_cpu_times(&present); - new_cpu_times.push(present_times); - cpu_deque.push_back(CpuData { - data_type: CpuDataType::Cpu(itx), - cpu_usage: calculate_cpu_usage_percentage( - convert_cpu_times(&past), - present_times, - ), - }); - } else { - new_cpu_times.push((0.0, 0.0)); - cpu_deque.push_back(CpuData { - data_type: CpuDataType::Cpu(itx), - cpu_usage: 0.0, - }); - } - } - - *previous_cpu_times = new_cpu_times; - cpu_deque - } else { - let (new_cpu_times, cpu_deque): (Vec<(PastCpuWork, PastCpuTotal)>, VecDeque) = - cpu_times - .collect::>() - .await - .iter() - .zip(&*previous_cpu_times) - .enumerate() - .map(|(itx, (current_cpu, (past_cpu_work, past_cpu_total)))| { - if let Ok(cpu_time) = current_cpu { - let present_times = convert_cpu_times(cpu_time); - - ( - present_times, - CpuData { - data_type: CpuDataType::Cpu(itx), - cpu_usage: calculate_cpu_usage_percentage( - (*past_cpu_work, *past_cpu_total), - present_times, - ), - }, - ) - } else { - ( - (*past_cpu_work, *past_cpu_total), - CpuData { - data_type: CpuDataType::Cpu(itx), - cpu_usage: 0.0, - }, - ) - } - }) - .unzip(); - - *previous_cpu_times = new_cpu_times; - cpu_deque - }; - - // Get average CPU if needed... and slap it at the top - if show_average_cpu { - let cpu_time = heim::cpu::time().await?; - - let (cpu_usage, new_average_cpu_time) = if let Some((past_cpu_work, past_cpu_total)) = - previous_average_cpu_time - { - let present_times = convert_cpu_times(&cpu_time); - ( - calculate_cpu_usage_percentage((*past_cpu_work, *past_cpu_total), present_times), - present_times, - ) - } else { - // Again, we need to do a quick timeout... - futures_timer::Delay::new(std::time::Duration::from_millis(100)).await; - let second_cpu_time = heim::cpu::time().await?; - - let present_times = convert_cpu_times(&second_cpu_time); - ( - calculate_cpu_usage_percentage(convert_cpu_times(&cpu_time), present_times), - present_times, - ) - }; - - *previous_average_cpu_time = Some(new_average_cpu_time); - cpu_deque.push_front(CpuData { - data_type: CpuDataType::Avg, - cpu_usage, - }) - } - - // Ok(Vec::from(cpu_deque.drain(0..3).collect::>())) // For artificially limiting the CPU results - - Ok(Vec::from(cpu_deque)) -} diff --git a/src/app/data_harvester/cpu/heim/linux.rs b/src/app/data_harvester/cpu/heim/linux.rs deleted file mode 100644 index f1b040c4..00000000 --- a/src/app/data_harvester/cpu/heim/linux.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Linux-specific functions regarding CPU usage. - -use heim::cpu::os::linux::CpuTimeExt; - -use crate::components::tui_widget::time_chart::Point; - -pub fn convert_cpu_times(cpu_time: &heim::cpu::CpuTime) -> Point { - let working_time: f64 = (cpu_time.user() - + cpu_time.nice() - + cpu_time.system() - + cpu_time.irq() - + cpu_time.soft_irq() - + cpu_time.steal()) - .get::(); - ( - working_time, - working_time + (cpu_time.idle() + cpu_time.io_wait()).get::(), - ) -} diff --git a/src/app/data_harvester/cpu/heim/unix.rs b/src/app/data_harvester/cpu/heim/unix.rs deleted file mode 100644 index 74340951..00000000 --- a/src/app/data_harvester/cpu/heim/unix.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Unix-specific functions regarding CPU usage. - -use crate::app::data_harvester::cpu::LoadAvgHarvest; - -pub async fn get_load_avg() -> crate::error::Result { - let (one, five, fifteen) = heim::cpu::os::unix::loadavg().await?; - - Ok([ - one.get::(), - five.get::(), - fifteen.get::(), - ]) -} diff --git a/src/app/data_harvester/cpu/heim/windows_macos.rs b/src/app/data_harvester/cpu/heim/windows_macos.rs deleted file mode 100644 index 6c110aab..00000000 --- a/src/app/data_harvester/cpu/heim/windows_macos.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! Windows and macOS-specific functions regarding CPU usage. - -use crate::components::tui_widget::time_chart::Point; - -pub fn convert_cpu_times(cpu_time: &heim::cpu::CpuTime) -> Point { - let working_time: f64 = - (cpu_time.user() + cpu_time.system()).get::(); - ( - working_time, - working_time + cpu_time.idle().get::(), - ) -} diff --git a/src/app/data_harvester/cpu/sysinfo.rs b/src/app/data_harvester/cpu/sysinfo.rs index 54318e1b..d3f000a0 100644 --- a/src/app/data_harvester/cpu/sysinfo.rs +++ b/src/app/data_harvester/cpu/sysinfo.rs @@ -5,13 +5,11 @@ use std::collections::VecDeque; use sysinfo::{CpuExt, LoadAvg, System, SystemExt}; -use super::{CpuData, CpuDataType, CpuHarvest, PastCpuTotal, PastCpuWork}; +use super::{CpuData, CpuDataType, CpuHarvest}; use crate::app::data_harvester::cpu::LoadAvgHarvest; -pub async fn get_cpu_data_list( +pub fn get_cpu_data_list( sys: &sysinfo::System, show_average_cpu: bool, - _previous_cpu_times: &mut [(PastCpuWork, PastCpuTotal)], - _previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>, ) -> crate::error::Result { let mut cpu_deque: VecDeque<_> = sys .cpus() @@ -35,7 +33,7 @@ pub async fn get_cpu_data_list( Ok(Vec::from(cpu_deque)) } -pub async fn get_load_avg() -> crate::error::Result { +pub fn get_load_avg() -> crate::error::Result { let sys = System::new(); let LoadAvg { one, five, fifteen } = sys.load_average(); diff --git a/src/app/data_harvester/processes/linux.rs b/src/app/data_harvester/processes/linux.rs index 282e56a3..a099adb0 100644 --- a/src/app/data_harvester/processes/linux.rs +++ b/src/app/data_harvester/processes/linux.rs @@ -5,7 +5,7 @@ use std::io::{BufRead, BufReader}; use fxhash::{FxHashMap, FxHashSet}; use procfs::process::{Process, Stat}; -use sysinfo::ProcessStatus; +use sysinfo::{ProcessStatus, System}; use super::{ProcessHarvest, UserTable}; use crate::components::tui_widget::time_chart::Point; @@ -221,25 +221,31 @@ fn read_proc( )) } -/// How to calculate CPU usage. -pub enum CpuUsageStrategy { - /// Normalized means the displayed usage percentage is divided over the number of CPU cores. - /// - /// For example, if the "overall" usage over the entire system is 105%, and there are 5 cores, then - /// the displayed percentage is 21%. - Normalized, - - /// Non-normalized means that the overall usage over the entire system is shown, without dividing - /// over the number of cores. - NonNormalized(f64), +pub(crate) struct PrevProc<'a> { + pub prev_idle: &'a mut f64, + pub prev_non_idle: &'a mut f64, } -pub fn get_process_data( - prev_idle: &mut f64, prev_non_idle: &mut f64, - pid_mapping: &mut FxHashMap, use_current_cpu_total: bool, - normalization: CpuUsageStrategy, time_difference_in_secs: u64, mem_total_kb: u64, +pub(crate) struct ProcHarvestOptions { + pub use_current_cpu_total: bool, + pub unnormalized_cpu: bool, +} + +pub(crate) fn get_process_data( + sys: &System, prev_proc: PrevProc<'_>, pid_mapping: &mut FxHashMap, + proc_harvest_options: ProcHarvestOptions, time_difference_in_secs: u64, mem_total_kb: u64, user_table: &mut UserTable, ) -> crate::utils::error::Result> { + let ProcHarvestOptions { + use_current_cpu_total, + unnormalized_cpu, + } = proc_harvest_options; + + let PrevProc { + prev_idle, + prev_non_idle, + } = prev_proc; + // TODO: [PROC THREADS] Add threads if let Ok(CpuUsage { @@ -247,10 +253,13 @@ pub fn get_process_data( cpu_fraction, }) = cpu_usage_calculation(prev_idle, prev_non_idle) { - if let CpuUsageStrategy::NonNormalized(num_cores) = normalization { + if unnormalized_cpu { + use sysinfo::SystemExt; + let num_processors = sys.cpus().len() as f64; + // Note we *divide* here because the later calculation divides `cpu_usage` - in effect, // multiplying over the number of cores. - cpu_usage /= num_cores; + cpu_usage /= num_processors; } let mut pids_to_clear: FxHashSet = pid_mapping.keys().cloned().collect(); -- cgit v1.2.3