diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index b1ba6a51..bfc7ae8d 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -16,8 +16,9 @@ use once_cell::sync::Lazy; use std::{time::Instant, vec::Vec}; +use crate::app::data_harvester::load_avg::LoadAvgHarvest; use crate::{ - data_harvester::{batteries, cpu, disks, mem, network, processes, temperature, Data}, + data_harvester::{batteries, cpu, disks, load_avg, mem, network, processes, temperature, Data}, utils::gen_util::get_simple_byte_values, }; use regex::Regex; @@ -30,6 +31,7 @@ pub struct TimedData { pub rx_data: Value, pub tx_data: Value, pub cpu_data: Vec, + pub load_avg_data: [f32; 3], pub mem_data: Option, pub swap_data: Option, } @@ -52,6 +54,7 @@ pub struct DataCollection { pub memory_harvest: mem::MemHarvest, pub swap_harvest: mem::MemHarvest, pub cpu_harvest: cpu::CpuHarvest, + pub load_avg_harvest: load_avg::LoadAvgHarvest, pub process_harvest: Vec, pub disk_harvest: Vec, pub io_harvest: disks::IOHarvest, @@ -71,6 +74,7 @@ impl Default for DataCollection { memory_harvest: mem::MemHarvest::default(), swap_harvest: mem::MemHarvest::default(), cpu_harvest: cpu::CpuHarvest::default(), + load_avg_harvest: load_avg::LoadAvgHarvest::default(), process_harvest: Vec::default(), disk_harvest: Vec::default(), io_harvest: disks::IOHarvest::default(), @@ -143,6 +147,11 @@ impl DataCollection { self.eat_cpu(cpu, &mut new_entry); } + // Load Average + if let Some(load_avg) = harvested_data.load_avg { + self.eat_load_avg(load_avg, &mut new_entry); + } + // Temp if let Some(temperature_sensors) = harvested_data.temperature_sensors { self.eat_temp(temperature_sensors); @@ -228,6 +237,12 @@ impl DataCollection { self.cpu_harvest = cpu.to_vec(); } + fn eat_load_avg(&mut self, load_avg: LoadAvgHarvest, new_entry: &mut TimedData) { + new_entry.load_avg_data = load_avg; + + self.load_avg_harvest = load_avg; + } + fn eat_temp(&mut self, temperature_sensors: Vec) { // trace!("Eating temps."); // TODO: [PO] To implement diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index 0fc8c6a5..3b7a0f63 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -19,6 +19,7 @@ use super::DataFilters; pub mod batteries; pub mod cpu; pub mod disks; +pub mod load_avg; pub mod mem; pub mod network; pub mod processes; @@ -28,6 +29,7 @@ pub mod temperature; pub struct Data { pub last_collection_time: Instant, pub cpu: Option, + pub load_avg: Option, pub memory: Option, pub swap: Option, pub temperature_sensors: Option>, @@ -43,6 +45,7 @@ impl Default for Data { Data { last_collection_time: Instant::now(), cpu: None, + load_avg: None, memory: None, swap: None, temperature_sensors: None, @@ -64,6 +67,7 @@ impl Data { self.memory = None; self.swap = None; self.cpu = None; + self.load_avg = None; if let Some(network) = &mut self.network { network.first_run_cleanup(); @@ -248,6 +252,14 @@ impl DataCollector { self.data.cpu = Some(cpu_data); } } + + #[cfg(target_family = "unix")] + { + // Load Average + if let Ok(load_avg_data) = load_avg::get_load_avg().await { + self.data.load_avg = Some(load_avg_data); + } + } } // Batteries diff --git a/src/app/data_harvester/load_avg.rs b/src/app/data_harvester/load_avg.rs new file mode 100644 index 00000000..0f58ea8b --- /dev/null +++ b/src/app/data_harvester/load_avg.rs @@ -0,0 +1,12 @@ +pub type LoadAvgHarvest = [f32; 3]; + +#[cfg(target_family = "unix")] +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/bin/main.rs b/src/bin/main.rs index 24aacd2f..70d02efe 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -222,6 +222,7 @@ fn main() -> Result<()> { &mut app.canvas_data.cpu_data, false, ); + app.canvas_data.load_avg_data = app.data_collection.load_avg_harvest; } // Processes diff --git a/src/canvas.rs b/src/canvas.rs index cf7d6af4..b904e217 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -56,6 +56,7 @@ pub struct DisplayableData { pub mem_data: Vec, pub swap_data: Vec, + pub load_avg_data: [f32; 3], pub cpu_data: Vec, pub battery_data: Vec, } diff --git a/src/canvas/widgets/cpu_graph.rs b/src/canvas/widgets/cpu_graph.rs index e19da20a..1b79482f 100644 --- a/src/canvas/widgets/cpu_graph.rs +++ b/src/canvas/widgets/cpu_graph.rs @@ -247,8 +247,42 @@ impl CpuGraphWidget for Painter { self.colours.border_style }; - let title = if app_state.is_expanded { + let title = if cfg!(target_family = "unix") { + let load_avg = app_state.canvas_data.load_avg_data; + let load_avg_str = format!( + "─ {:.2} {:.2} {:.2} ", + load_avg[0], load_avg[1], load_avg[2] + ); + let load_avg_str_size = + UnicodeSegmentation::graphemes(load_avg_str.as_str(), true).count(); + + if app_state.is_expanded { + const TITLE_BASE: &str = " CPU ── Esc to go back "; + + Spans::from(vec![ + Span::styled(" CPU ", self.colours.widget_title_style), + Span::styled(load_avg_str, self.colours.widget_title_style), + Span::styled( + format!( + "─{}─ Esc to go back ", + "─".repeat(usize::from(draw_loc.width).saturating_sub( + load_avg_str_size + + UnicodeSegmentation::graphemes(TITLE_BASE, true).count() + + 2 + )) + ), + border_style, + ), + ]) + } else { + Spans::from(vec![ + Span::styled(" CPU ", self.colours.widget_title_style), + Span::styled(load_avg_str, self.colours.widget_title_style), + ]) + } + } else if app_state.is_expanded { const TITLE_BASE: &str = " CPU ── Esc to go back "; + Spans::from(vec![ Span::styled(" CPU ", self.colours.widget_title_style), Span::styled( @@ -262,7 +296,7 @@ impl CpuGraphWidget for Painter { ), ]) } else { - Spans::from(Span::styled(" CPU ", self.colours.widget_title_style)) + Spans::from(vec![Span::styled(" CPU ", self.colours.widget_title_style)]) }; f.render_widget( diff --git a/src/lib.rs b/src/lib.rs index e3be6823..a3b951f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -315,6 +315,7 @@ pub fn handle_force_redraws(app: &mut App) { &mut app.canvas_data.cpu_data, app.is_frozen, ); + app.canvas_data.load_avg_data = app.data_collection.load_avg_harvest; app.cpu_state.force_update = None; }