From ba0fbf808e4d04405d704bf2a1b071b792d135d5 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Sat, 4 Apr 2020 18:29:32 -0400 Subject: (perf) Avoid harvesting if widget is not being displayed --- README.md | 2 +- src/app.rs | 1 + src/app/data_harvester.rs | 120 ++++++++++++++++++++++------------ src/app/data_harvester/disks.rs | 20 ++++-- src/app/data_harvester/mem.rs | 24 +++++-- src/app/data_harvester/network.rs | 12 ++-- src/app/data_harvester/temperature.rs | 10 ++- src/app/layout_manager.rs | 12 +++- src/main.rs | 86 ++++++++++++++---------- src/options.rs | 21 +++++- 10 files changed, 210 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index e6b8cb78..560ed2b6 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ searching by PID and by process name. ### Zoom -Using the +/- keys or the scroll wheel will move adjust the current time intervals of the currently selected widget. Widgets +Using the `+`/`-` keys or the scroll wheel will move adjust the current time intervals of the currently selected widget. Widgets can hold different time intervals independently. ### Maximizing diff --git a/src/app.rs b/src/app.rs index ba2186a4..8f495afd 100644 --- a/src/app.rs +++ b/src/app.rs @@ -512,6 +512,7 @@ pub struct App { pub app_config_fields: AppConfigFields, pub widget_map: HashMap, pub current_widget: BottomWidget, + pub used_widgets: UsedWidgets, } impl App { diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index e4b59970..a0c7c955 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -4,6 +4,8 @@ use std::{collections::HashMap, time::Instant}; use sysinfo::{System, SystemExt}; +use crate::app::layout_manager::UsedWidgets; + use futures::join; pub mod cpu; @@ -56,7 +58,7 @@ impl Data { } } -pub struct DataState { +pub struct DataCollector { pub data: Data, sys: System, prev_pid_stats: HashMap, @@ -69,11 +71,12 @@ pub struct DataState { total_rx: u64, total_tx: u64, show_average_cpu: bool, + widgets_to_harvest: UsedWidgets, } -impl Default for DataState { +impl Default for DataCollector { fn default() -> Self { - DataState { + DataCollector { data: Data::default(), sys: System::new_all(), prev_pid_stats: HashMap::new(), @@ -86,11 +89,23 @@ impl Default for DataState { total_rx: 0, total_tx: 0, show_average_cpu: false, + widgets_to_harvest: UsedWidgets::default(), } } } -impl DataState { +impl DataCollector { + pub fn init(&mut self) { + self.mem_total_kb = self.sys.get_total_memory(); + futures::executor::block_on(self.update_data()); + std::thread::sleep(std::time::Duration::from_millis(250)); + self.data.first_run_cleanup(); + } + + pub fn set_collected_data(&mut self, used_widgets: UsedWidgets) { + self.widgets_to_harvest = used_widgets; + } + pub fn set_temperature_type(&mut self, temperature_type: temperature::TemperatureType) { self.temperature_type = temperature_type; } @@ -103,42 +118,45 @@ impl DataState { self.show_average_cpu = show_average_cpu; } - pub fn init(&mut self) { - self.mem_total_kb = self.sys.get_total_memory(); - futures::executor::block_on(self.update_data()); - std::thread::sleep(std::time::Duration::from_millis(250)); - self.data.first_run_cleanup(); - } - pub async fn update_data(&mut self) { - self.sys.refresh_system(); + if self.widgets_to_harvest.use_cpu { + self.sys.refresh_cpu(); + } if cfg!(not(target_os = "linux")) { - self.sys.refresh_processes(); - self.sys.refresh_components(); + if self.widgets_to_harvest.use_proc { + self.sys.refresh_processes(); + } + if self.widgets_to_harvest.use_temp { + self.sys.refresh_components(); + } } - if cfg!(target_os = "windows") { + if cfg!(target_os = "windows") && self.widgets_to_harvest.use_net { self.sys.refresh_networks(); } let current_instant = std::time::Instant::now(); // CPU - self.data.cpu = cpu::get_cpu_data_list(&self.sys, self.show_average_cpu); + if self.widgets_to_harvest.use_cpu { + self.data.cpu = cpu::get_cpu_data_list(&self.sys, self.show_average_cpu); + } - // Processes. This is the longest part of the harvesting process... changing this might be - // good in the future. What was tried already: - // * Splitting the internal part into multiple scoped threads (dropped by ~.01 seconds, but upped usage) - if let Ok(process_list) = processes::get_sorted_processes_list( - &self.sys, - &mut self.prev_idle, - &mut self.prev_non_idle, - &mut self.prev_pid_stats, - self.use_current_cpu_total, - self.mem_total_kb, - current_instant, - ) { - self.data.list_of_processes = process_list; + if self.widgets_to_harvest.use_proc { + // Processes. This is the longest part of the harvesting process... changing this might be + // good in the future. What was tried already: + // * Splitting the internal part into multiple scoped threads (dropped by ~.01 seconds, but upped usage) + if let Ok(process_list) = processes::get_sorted_processes_list( + &self.sys, + &mut self.prev_idle, + &mut self.prev_non_idle, + &mut self.prev_pid_stats, + self.use_current_cpu_total, + self.mem_total_kb, + current_instant, + ) { + self.data.list_of_processes = process_list; + } } // ASYNC @@ -148,13 +166,18 @@ impl DataState { &mut self.total_rx, &mut self.total_tx, current_instant, + self.widgets_to_harvest.use_net, ); - let mem_data_fut = mem::get_mem_data_list(); - let swap_data_fut = mem::get_swap_data_list(); - let disk_data_fut = disks::get_disk_usage_list(); - let disk_io_usage_fut = disks::get_io_usage_list(false); - let temp_data_fut = temperature::get_temperature_data(&self.sys, &self.temperature_type); + let mem_data_fut = mem::get_mem_data_list(self.widgets_to_harvest.use_mem); + let swap_data_fut = mem::get_swap_data_list(self.widgets_to_harvest.use_mem); + let disk_data_fut = disks::get_disk_usage_list(self.widgets_to_harvest.use_disk); + let disk_io_usage_fut = disks::get_io_usage_list(false, self.widgets_to_harvest.use_disk); + let temp_data_fut = temperature::get_temperature_data( + &self.sys, + &self.temperature_type, + self.widgets_to_harvest.use_temp, + ); let (net_data, mem_res, swap_res, disk_res, io_res, temp_res) = join!( network_data_fut, @@ -166,27 +189,40 @@ impl DataState { ); // After async - self.data.network = net_data; - self.total_rx = self.data.network.total_rx; - self.total_tx = self.data.network.total_tx; + if let Some(net_data) = net_data { + self.data.network = net_data; + self.total_rx = self.data.network.total_rx; + self.total_tx = self.data.network.total_tx; + } if let Ok(memory) = mem_res { - self.data.memory = memory; + if let Some(memory) = memory { + self.data.memory = memory; + } } if let Ok(swap) = swap_res { - self.data.swap = swap; + if let Some(swap) = swap { + self.data.swap = swap; + } } if let Ok(disks) = disk_res { - self.data.disks = disks; + if let Some(disks) = disks { + self.data.disks = disks; + } } + if let Ok(io) = io_res { - self.data.io = io; + if let Some(io) = io { + self.data.io = io; + } } if let Ok(temp) = temp_res { - self.data.temperature_sensors = temp; + if let Some(temp) = temp { + self.data.temperature_sensors = temp; + } } // Update time diff --git a/src/app/data_harvester/disks.rs b/src/app/data_harvester/disks.rs index e8401645..93720975 100644 --- a/src/app/data_harvester/disks.rs +++ b/src/app/data_harvester/disks.rs @@ -18,7 +18,13 @@ pub struct IOData { pub type IOHarvest = std::collections::HashMap; -pub async fn get_io_usage_list(get_physical: bool) -> crate::utils::error::Result { +pub async fn get_io_usage_list( + get_physical: bool, actually_get: bool, +) -> crate::utils::error::Result> { + if !actually_get { + return Ok(None); + } + let mut io_hash: std::collections::HashMap = std::collections::HashMap::new(); if get_physical { let mut physical_counter_stream = heim::disk::io_counters_physical(); @@ -48,10 +54,16 @@ pub async fn get_io_usage_list(get_physical: bool) -> crate::utils::error::Resul } } - Ok(io_hash) + Ok(Some(io_hash)) } -pub async fn get_disk_usage_list() -> crate::utils::error::Result> { +pub async fn get_disk_usage_list( + actually_get: bool, +) -> crate::utils::error::Result>> { + if !actually_get { + return Ok(None); + } + let mut vec_disks: Vec = Vec::new(); let mut partitions_stream = heim::disk::partitions_physical(); @@ -81,5 +93,5 @@ pub async fn get_disk_usage_list() -> crate::utils::error::Result crate::utils::error::Result { +pub async fn get_mem_data_list( + actually_get: bool, +) -> crate::utils::error::Result> { + if !actually_get { + return Ok(None); + } + let memory = heim::memory::memory().await?; - Ok(MemHarvest { + Ok(Some(MemHarvest { mem_total_in_mb: memory.total().get::(), mem_used_in_mb: memory.total().get::() - memory.available().get::(), - }) + })) } -pub async fn get_swap_data_list() -> crate::utils::error::Result { +pub async fn get_swap_data_list( + actually_get: bool, +) -> crate::utils::error::Result> { + if !actually_get { + return Ok(None); + } + let memory = heim::memory::swap().await?; - Ok(MemHarvest { + Ok(Some(MemHarvest { mem_total_in_mb: memory.total().get::(), mem_used_in_mb: memory.used().get::(), - }) + })) } diff --git a/src/app/data_harvester/network.rs b/src/app/data_harvester/network.rs index c425ccd6..5e50a110 100644 --- a/src/app/data_harvester/network.rs +++ b/src/app/data_harvester/network.rs @@ -22,8 +22,12 @@ impl NetworkHarvest { pub async fn get_network_data( sys: &System, prev_net_access_time: Instant, prev_net_rx: &mut u64, prev_net_tx: &mut u64, - curr_time: Instant, -) -> NetworkHarvest { + curr_time: Instant, actually_get: bool, +) -> Option { + if !actually_get { + return None; + } + let mut io_data = net::io_counters(); let mut total_rx: u64 = 0; let mut total_tx: u64 = 0; @@ -56,10 +60,10 @@ pub async fn get_network_data( *prev_net_rx = total_rx; *prev_net_tx = total_tx; - NetworkHarvest { + Some(NetworkHarvest { rx, tx, total_rx, total_tx, - } + }) } diff --git a/src/app/data_harvester/temperature.rs b/src/app/data_harvester/temperature.rs index de3ce9d9..b0a39e3d 100644 --- a/src/app/data_harvester/temperature.rs +++ b/src/app/data_harvester/temperature.rs @@ -24,8 +24,12 @@ impl Default for TemperatureType { } pub async fn get_temperature_data( - sys: &System, temp_type: &TemperatureType, -) -> crate::utils::error::Result> { + sys: &System, temp_type: &TemperatureType, actually_get: bool, +) -> crate::utils::error::Result>> { + if !actually_get { + return Ok(None); + } + let mut temperature_vec: Vec = Vec::new(); if cfg!(target_os = "linux") { @@ -86,7 +90,7 @@ pub async fn get_temperature_data( .unwrap_or(Ordering::Equal) }); - Ok(temperature_vec) + Ok(Some(temperature_vec)) } fn convert_celsius_to_kelvin(celsius: f32) -> f32 { diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs index 41ec72b6..522fcb4c 100644 --- a/src/app/layout_manager.rs +++ b/src/app/layout_manager.rs @@ -864,7 +864,7 @@ pub struct BottomWidget { pub flex_grow: bool, } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum BottomWidgetType { Empty, Cpu, @@ -938,3 +938,13 @@ impl std::str::FromStr for BottomWidgetType { } } } + +#[derive(Clone, Default)] +pub struct UsedWidgets { + pub use_cpu: bool, + pub use_mem: bool, + pub use_net: bool, + pub use_proc: bool, + pub use_disk: bool, + pub use_temp: bool, +} diff --git a/src/main.rs b/src/main.rs index 5ffe5c86..a53408d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,7 @@ use tui::{backend::CrosstermBackend, Terminal}; use app::{ data_harvester::{self, processes::ProcessSorting}, + layout_manager::UsedWidgets, App, }; use constants::*; @@ -139,6 +140,7 @@ fn main() -> error::Result<()> { app.app_config_fields.update_rate_in_milliseconds, app.app_config_fields.temperature_type.clone(), app.app_config_fields.show_average_cpu, + app.used_widgets.clone(), ); let mut painter = canvas::Painter::init(widget_layout); @@ -170,49 +172,62 @@ fn main() -> error::Result<()> { // Convert all data into tui-compliant components // Network - let network_data = convert_network_data_points(&app.data_collection, false); - app.canvas_data.network_data_rx = network_data.rx; - app.canvas_data.network_data_tx = network_data.tx; - app.canvas_data.rx_display = network_data.rx_display; - app.canvas_data.tx_display = network_data.tx_display; - app.canvas_data.total_rx_display = network_data.total_rx_display; - app.canvas_data.total_tx_display = network_data.total_tx_display; + if app.used_widgets.use_net { + let network_data = + convert_network_data_points(&app.data_collection, false); + app.canvas_data.network_data_rx = network_data.rx; + app.canvas_data.network_data_tx = network_data.tx; + app.canvas_data.rx_display = network_data.rx_display; + app.canvas_data.tx_display = network_data.tx_display; + app.canvas_data.total_rx_display = network_data.total_rx_display; + app.canvas_data.total_tx_display = network_data.total_tx_display; + } // Disk - app.canvas_data.disk_data = convert_disk_row(&app.data_collection); + if app.used_widgets.use_disk { + app.canvas_data.disk_data = convert_disk_row(&app.data_collection); + } // Temperatures - app.canvas_data.temp_sensor_data = convert_temp_row(&app); + if app.used_widgets.use_temp { + app.canvas_data.temp_sensor_data = convert_temp_row(&app); + } // Memory - app.canvas_data.mem_data = - convert_mem_data_points(&app.data_collection, false); - app.canvas_data.swap_data = - convert_swap_data_points(&app.data_collection, false); - let memory_and_swap_labels = convert_mem_labels(&app.data_collection); - app.canvas_data.mem_label = memory_and_swap_labels.0; - app.canvas_data.swap_label = memory_and_swap_labels.1; + if app.used_widgets.use_mem { + app.canvas_data.mem_data = + convert_mem_data_points(&app.data_collection, false); + app.canvas_data.swap_data = + convert_swap_data_points(&app.data_collection, false); + let memory_and_swap_labels = convert_mem_labels(&app.data_collection); + app.canvas_data.mem_label = memory_and_swap_labels.0; + app.canvas_data.swap_label = memory_and_swap_labels.1; + } // Pre-fill CPU if needed - if first_run { - let cpu_len = app.data_collection.cpu_harvest.len(); - app.cpu_state.widget_states.values_mut().for_each(|state| { - state.core_show_vec = vec![true; cpu_len]; - state.num_cpus_shown = cpu_len; - }); - app.cpu_state.num_cpus_total = cpu_len; - first_run = false; - } + if app.used_widgets.use_cpu { + if first_run { + let cpu_len = app.data_collection.cpu_harvest.len(); + app.cpu_state.widget_states.values_mut().for_each(|state| { + state.core_show_vec = vec![true; cpu_len]; + state.num_cpus_shown = cpu_len; + }); + app.cpu_state.num_cpus_total = cpu_len; + first_run = false; + } - // CPU - app.canvas_data.cpu_data = - convert_cpu_data_points(&app.data_collection, false); + // CPU + app.canvas_data.cpu_data = + convert_cpu_data_points(&app.data_collection, false); + } // Processes - let (single, grouped) = convert_process_data(&app.data_collection); - app.canvas_data.process_data = single; - app.canvas_data.grouped_process_data = grouped; - update_all_process_lists(&mut app); + if app.used_widgets.use_proc { + let (single, grouped) = convert_process_data(&app.data_collection); + app.canvas_data.process_data = single; + app.canvas_data.grouped_process_data = grouped; + update_all_process_lists(&mut app); + } } } BottomEvent::Clean => { @@ -743,15 +758,16 @@ fn create_event_thread( >, rrx: std::sync::mpsc::Receiver, use_current_cpu_total: bool, update_rate_in_milliseconds: u64, temp_type: data_harvester::temperature::TemperatureType, - show_average_cpu: bool, + show_average_cpu: bool, used_widget_set: UsedWidgets, ) { thread::spawn(move || { let tx = tx.clone(); - let mut data_state = data_harvester::DataState::default(); - data_state.init(); + let mut data_state = data_harvester::DataCollector::default(); + data_state.set_collected_data(used_widget_set); data_state.set_temperature_type(temp_type); data_state.set_use_current_cpu_total(use_current_cpu_total); data_state.set_show_average_cpu(show_average_cpu); + data_state.init(); loop { if let Ok(message) = rrx.try_recv() { match message { diff --git a/src/options.rs b/src/options.rs index 96e1e80a..3f5d9d2c 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,5 +1,5 @@ use serde::Deserialize; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::time::Instant; use crate::{ @@ -100,6 +100,8 @@ pub fn build_app( let mut initial_widget_type = BottomWidgetType::Proc; let is_custom_layout = config.row.is_some(); + let mut used_widget_set = HashSet::new(); + for row in &widget_layout.rows { for col in &row.children { for col_row in &col.children { @@ -135,6 +137,9 @@ pub fn build_app( } } } + + used_widget_set.insert(widget.widget_type.clone()); + match widget.widget_type { BottomWidgetType::Cpu => { cpu_state_map.insert( @@ -178,7 +183,6 @@ pub fn build_app( } } - // FIXME: [MODULARITY] Don't collect if not added! let basic_table_widget_state = if use_basic_mode { Some(match initial_widget_type { BottomWidgetType::Proc | BottomWidgetType::Disk | BottomWidgetType::Temp => { @@ -213,6 +217,18 @@ pub fn build_app( autohide_time, }; + let used_widgets = UsedWidgets { + use_cpu: used_widget_set.get(&BottomWidgetType::Cpu).is_some() + || used_widget_set.get(&BottomWidgetType::BasicCpu).is_some(), + use_mem: used_widget_set.get(&BottomWidgetType::Mem).is_some() + || used_widget_set.get(&BottomWidgetType::BasicMem).is_some(), + use_net: used_widget_set.get(&BottomWidgetType::Net).is_some() + || used_widget_set.get(&BottomWidgetType::BasicNet).is_some(), + use_proc: used_widget_set.get(&BottomWidgetType::Proc).is_some(), + use_disk: used_widget_set.get(&BottomWidgetType::Disk).is_some(), + use_temp: used_widget_set.get(&BottomWidgetType::Temp).is_some(), + }; + Ok(App::builder() .app_config_fields(app_config_fields) .cpu_state(CpuState::init(cpu_state_map)) @@ -224,6 +240,7 @@ pub fn build_app( .basic_table_widget_state(basic_table_widget_state) .current_widget(widget_map.get(&initial_widget_id).unwrap().clone()) // I think the unwrap is fine here .widget_map(widget_map) + .used_widgets(used_widgets) .build()) } -- cgit v1.2.3