From b7456841566e6e526af028368d0a0149392b176e Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Tue, 7 Mar 2023 00:18:24 -0500 Subject: refactor: more data collection cleanup (#1047) * refactor: more memory collection cleanup * more cleanup * clean up data_harvester, remove heim sensor flag Separate out most individual components to separate functions. Also remove Linux's usage of heim's sensors feature, since I wasn't using it apparently. * clean up GPU section * fix cond * fix feature flags * more cleanup * even more cleanup --- Cargo.lock | 12 --- Cargo.toml | 2 +- src/app.rs | 1 + src/app/data_farmer.rs | 14 +-- src/app/data_harvester.rs | 169 ++++++++++++++++--------------- src/app/data_harvester/memory.rs | 18 ++-- src/app/data_harvester/memory/arc.rs | 75 ++++++++++++++ src/app/data_harvester/memory/gpu.rs | 49 +++++++++ src/app/data_harvester/memory/sysinfo.rs | 131 +----------------------- 9 files changed, 226 insertions(+), 245 deletions(-) create mode 100644 src/app/data_harvester/memory/arc.rs create mode 100644 src/app/data_harvester/memory/gpu.rs diff --git a/Cargo.lock b/Cargo.lock index 42114e50..cad398fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -821,7 +821,6 @@ dependencies = [ "heim-common", "heim-disk", "heim-runtime", - "heim-sensors", ] [[package]] @@ -872,17 +871,6 @@ dependencies = [ "smol", ] -[[package]] -name = "heim-sensors" -version = "0.1.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82de7f0784d3b0c53f2e8875c63f430bf6718b03ec8ddce905c12887031158f5" -dependencies = [ - "cfg-if", - "heim-common", - "heim-runtime", -] - [[package]] name = "hermit-abi" version = "0.1.19" diff --git a/Cargo.toml b/Cargo.toml index cc4618fa..6a721237 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ unicode-width = "0.1.10" libc = "0.2.124" [target.'cfg(target_os = "linux")'.dependencies] -heim = { version = "0.1.0-rc.1", features = ["disk", "sensors"] } +heim = { version = "0.1.0-rc.1", features = ["disk"] } procfs = { version = "0.15.1", default-features = false } [target.'cfg(target_os = "macos")'.dependencies] diff --git a/src/app.rs b/src/app.rs index b83cabfa..123f991b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -147,6 +147,7 @@ pub struct App { pub filters: DataFilters, } +// TODO: Should probably set a fallback max signal/not supported for this. #[cfg(target_os = "windows")] const MAX_SIGNAL: usize = 1; #[cfg(target_os = "linux")] diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index e6a7266f..d17c0545 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -214,17 +214,13 @@ impl DataCollection { } #[cfg(feature = "zfs")] - { - if let Some(arc) = harvested_data.arc { - self.eat_arc(arc, &mut new_entry); - } + if let Some(arc) = harvested_data.arc { + self.eat_arc(arc, &mut new_entry); } #[cfg(feature = "gpu")] - { - if let Some(gpu) = harvested_data.gpu { - self.eat_gpu(gpu, &mut new_entry); - } + if let Some(gpu) = harvested_data.gpu { + self.eat_gpu(gpu, &mut new_entry); } // CPU @@ -417,7 +413,7 @@ impl DataCollection { #[cfg(feature = "gpu")] fn eat_gpu(&mut self, gpu: Vec<(String, memory::MemHarvest)>, new_entry: &mut TimedData) { // Note this only pre-calculates the data points - the names will be - // within the local copy of gpu_harvest. Since it's all sequential + // within the local copy of gpu_harvest. Since it's all sequential // it probably doesn't matter anyways. gpu.iter().for_each(|data| { new_entry.gpu_data.push(data.1.use_percent); diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index 72009b29..9d8a02a1 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -2,8 +2,6 @@ use std::time::Instant; -use futures::join; - #[cfg(target_os = "linux")] use fxhash::FxHashMap; @@ -12,7 +10,7 @@ use starship_battery::{Battery, Manager}; use sysinfo::{System, SystemExt}; -use self::memory::MemCollect; +use self::temperature::TemperatureType; use super::DataFilters; use crate::app::layout_manager::UsedWidgets; @@ -22,6 +20,7 @@ pub mod nvidia; #[cfg(feature = "battery")] pub mod batteries; + pub mod cpu; pub mod disks; pub mod memory; @@ -108,7 +107,7 @@ pub struct DataCollector { #[cfg(target_os = "linux")] prev_non_idle: f64, mem_total_kb: u64, - temperature_type: temperature::TemperatureType, + temperature_type: TemperatureType, use_current_cpu_total: bool, unnormalized_cpu: bool, last_collection_time: Instant, @@ -138,7 +137,7 @@ impl DataCollector { #[cfg(target_os = "linux")] prev_non_idle: 0_f64, mem_total_kb: 0, - temperature_type: temperature::TemperatureType::Celsius, + temperature_type: TemperatureType::Celsius, use_current_cpu_total: false, unnormalized_cpu: false, last_collection_time: Instant::now(), @@ -161,9 +160,8 @@ impl DataCollector { self.mem_total_kb = self.sys.total_memory(); // Refresh network list once at the start. - // TODO: may be worth refreshing every once in a while (maybe on a separate timer). if self.widgets_to_harvest.use_net { - self.sys.refresh_networks_list(); + self.sys.refresh_networks_list(); // TODO: refresh on a timer? } if self.widgets_to_harvest.use_proc || self.widgets_to_harvest.use_cpu { @@ -172,11 +170,9 @@ impl DataCollector { #[cfg(not(target_os = "linux"))] { - // TODO: Would be good to get this and network list running on a timer instead...? - - // Refresh components list once... + // Refresh components list once. if self.widgets_to_harvest.use_temp { - self.sys.refresh_components_list(); + self.sys.refresh_components_list(); // TODO: refresh on a timer? } if cfg!(target_os = "windows") && self.widgets_to_harvest.use_proc { @@ -207,7 +203,6 @@ impl DataCollector { futures::executor::block_on(self.update_data()); std::thread::sleep(std::time::Duration::from_millis(250)); - self.data.cleanup(); } @@ -215,7 +210,7 @@ impl DataCollector { self.widgets_to_harvest = used_widgets; } - pub fn set_temperature_type(&mut self, temperature_type: temperature::TemperatureType) { + pub fn set_temperature_type(&mut self, temperature_type: TemperatureType) { self.temperature_type = temperature_type; } @@ -249,42 +244,72 @@ impl DataCollector { if self.widgets_to_harvest.use_proc { self.sys.refresh_processes(); } + if self.widgets_to_harvest.use_temp { self.sys.refresh_components(); } + } - #[cfg(target_os = "freebsd")] - { - if self.widgets_to_harvest.use_disk { - self.sys.refresh_disks(); - } + #[cfg(target_os = "freebsd")] + if self.widgets_to_harvest.use_disk { + self.sys.refresh_disks(); + } + + let current_instant = Instant::now(); + + self.update_cpu_usage(); + self.update_processes( + #[cfg(target_os = "linux")] + current_instant, + ); + self.update_temps(); + self.update_memory_usage(); + self.update_network_usage(current_instant); + + #[cfg(feature = "battery")] + if let Some(battery_manager) = &self.battery_manager { + if let Some(battery_list) = &mut self.battery_list { + self.data.list_of_batteries = + Some(batteries::refresh_batteries(battery_manager, battery_list)); } } - let current_instant = std::time::Instant::now(); + let (disk_res, io_res) = futures::join!( + disks::get_disk_usage( + self.widgets_to_harvest.use_disk, + &self.filters.disk_filter, + &self.filters.mount_filter, + ), + disks::get_io_usage(self.widgets_to_harvest.use_disk) + ); + + if let Ok(disks) = disk_res { + self.data.disks = disks; + } + + if let Ok(io) = io_res { + self.data.io = io; + } - // CPU + // Update times for future reference. + self.last_collection_time = current_instant; + self.data.last_collection_time = current_instant; + } + + #[inline] + fn update_cpu_usage(&mut self) { if self.widgets_to_harvest.use_cpu { self.data.cpu = cpu::get_cpu_data_list(&self.sys, self.show_average_cpu).ok(); #[cfg(target_family = "unix")] { - // Load Average self.data.load_avg = cpu::get_load_avg().ok(); } } + } - // Batteries - #[cfg(feature = "battery")] - { - if let Some(battery_manager) = &self.battery_manager { - if let Some(battery_list) = &mut self.battery_list { - self.data.list_of_batteries = - Some(batteries::refresh_batteries(battery_manager, battery_list)); - } - } - } - + #[inline] + fn update_processes(&mut self, #[cfg(target_os = "linux")] current_instant: Instant) { if self.widgets_to_harvest.use_proc { if let Ok(mut process_list) = { #[cfg(target_os = "linux")] @@ -301,14 +326,16 @@ impl DataCollector { unnormalized_cpu: self.unnormalized_cpu, }; + let time_diff = current_instant + .duration_since(self.last_collection_time) + .as_secs(); + processes::get_process_data( &self.sys, prev_proc, &mut self.pid_mapping, proc_harvest_options, - current_instant - .duration_since(self.last_collection_time) - .as_secs(), + time_diff, self.mem_total_kb, &mut self.user_table, ) @@ -343,54 +370,49 @@ impl DataCollector { self.data.list_of_processes = Some(process_list); } } + } + #[inline] + fn update_temps(&mut self) { if self.widgets_to_harvest.use_temp { #[cfg(not(target_os = "linux"))] - { - if let Ok(data) = temperature::get_temperature_data( - &self.sys, - &self.temperature_type, - &self.filters.temp_filter, - ) { - self.data.temperature_sensors = data; - } + if let Ok(data) = temperature::get_temperature_data( + &self.sys, + &self.temperature_type, + &self.filters.temp_filter, + ) { + self.data.temperature_sensors = data; } #[cfg(target_os = "linux")] + if let Ok(data) = + temperature::get_temperature_data(&self.temperature_type, &self.filters.temp_filter) { - if let Ok(data) = temperature::get_temperature_data( - &self.temperature_type, - &self.filters.temp_filter, - ) { - self.data.temperature_sensors = data; - } + self.data.temperature_sensors = data; } } + } + #[inline] + fn update_memory_usage(&mut self) { if self.widgets_to_harvest.use_mem { - let MemCollect { - ram, - swap, - #[cfg(feature = "gpu")] - gpus, - #[cfg(feature = "zfs")] - arc, - } = memory::get_mem_data(&self.sys, self.widgets_to_harvest.use_gpu); - - self.data.memory = ram; - self.data.swap = swap; + self.data.memory = memory::get_ram_usage(&self.sys); + self.data.swap = memory::get_swap_usage(&self.sys); #[cfg(feature = "zfs")] { - self.data.arc = arc; + self.data.arc = memory::arc::get_arc_usage(); } #[cfg(feature = "gpu")] - { - self.data.gpu = gpus; + if self.widgets_to_harvest.use_gpu { + self.data.gpu = memory::gpu::get_gpu_mem_usage(); } } + } + #[inline] + fn update_network_usage(&mut self, current_instant: Instant) { if self.widgets_to_harvest.use_net { let net_data = network::get_network_data( &self.sys, @@ -405,27 +427,6 @@ impl DataCollector { self.total_tx = net_data.total_tx; self.data.network = Some(net_data); } - - let disk_data_fut = disks::get_disk_usage( - self.widgets_to_harvest.use_disk, - &self.filters.disk_filter, - &self.filters.mount_filter, - ); - let disk_io_usage_fut = disks::get_io_usage(self.widgets_to_harvest.use_disk); - - let (disk_res, io_res) = join!(disk_data_fut, disk_io_usage_fut,); - - if let Ok(disks) = disk_res { - self.data.disks = disks; - } - - if let Ok(io) = io_res { - self.data.io = io; - } - - // Update time - self.data.last_collection_time = current_instant; - self.last_collection_time = current_instant; } } diff --git a/src/app/data_harvester/memory.rs b/src/app/data_harvester/memory.rs index aa59e0bb..18ac94cd 100644 --- a/src/app/data_harvester/memory.rs +++ b/src/app/data_harvester/memory.rs @@ -1,7 +1,13 @@ //! Memory data collection. pub mod sysinfo; -pub(crate) use self::sysinfo::*; +pub(crate) use self::sysinfo::{get_ram_usage, get_swap_usage}; + +#[cfg(feature = "gpu")] +pub mod gpu; + +#[cfg(feature = "zfs")] +pub mod arc; #[derive(Debug, Clone, Default)] pub struct MemHarvest { @@ -9,13 +15,3 @@ pub struct MemHarvest { pub used_kib: u64, pub use_percent: Option, } - -#[derive(Debug)] -pub struct MemCollect { - pub ram: Option, - pub swap: Option, - #[cfg(feature = "zfs")] - pub arc: Option, - #[cfg(feature = "gpu")] - pub gpus: Option>, -} diff --git a/src/app/data_harvester/memory/arc.rs b/src/app/data_harvester/memory/arc.rs new file mode 100644 index 00000000..3dc26ba8 --- /dev/null +++ b/src/app/data_harvester/memory/arc.rs @@ -0,0 +1,75 @@ +use super::MemHarvest; + +/// Return ARC usage. +#[cfg(feature = "zfs")] +pub(crate) fn get_arc_usage() -> Option { + let (mem_total_in_kib, mem_used_in_kib) = { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + // TODO: [OPT] is this efficient? + use std::fs::read_to_string; + if let Ok(arc_stats) = read_to_string("/proc/spl/kstat/zfs/arcstats") { + let mut mem_arc = 0; + let mut mem_total = 0; + let mut zfs_keys_read: u8 = 0; + const ZFS_KEYS_NEEDED: u8 = 2; + + for line in arc_stats.lines() { + if let Some((label, value)) = line.split_once(' ') { + let to_write = match label { + "size" => &mut mem_arc, + "memory_all_bytes" => &mut mem_total, + _ => { + continue; + } + }; + + if let Some((_type, number)) = value.trim_start().rsplit_once(' ') { + // Parse the value, remember it's in bytes! + if let Ok(number) = number.parse::() { + *to_write = number; + // We only need a few keys, so we can bail early. + zfs_keys_read += 1; + if zfs_keys_read == ZFS_KEYS_NEEDED { + break; + } + } + } + } + } + (mem_total / 1024, mem_arc / 1024) + } else { + (0, 0) + } + } else if #[cfg(target_os = "freebsd")] { + use sysctl::Sysctl; + if let (Ok(mem_arc_value), Ok(mem_sys_value)) = ( + sysctl::Ctl::new("kstat.zfs.misc.arcstats.size"), + sysctl::Ctl::new("hw.physmem"), + ) { + if let (Ok(sysctl::CtlValue::U64(arc)), Ok(sysctl::CtlValue::Ulong(mem))) = + (mem_arc_value.value(), mem_sys_value.value()) + { + (mem / 1024, arc / 1024) + } else { + (0, 0) + } + } else { + (0, 0) + } + } else { + (0, 0) + } + } + }; + + Some(MemHarvest { + total_kib: mem_total_in_kib, + used_kib: mem_used_in_kib, + use_percent: if mem_total_in_kib == 0 { + None + } else { + Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0) + }, + }) +} diff --git a/src/app/data_harvester/memory/gpu.rs b/src/app/data_harvester/memory/gpu.rs new file mode 100644 index 00000000..86c5a8b7 --- /dev/null +++ b/src/app/data_harvester/memory/gpu.rs @@ -0,0 +1,49 @@ +use super::MemHarvest; + +/// Return GPU memory usage. +#[cfg(feature = "gpu")] +pub(crate) fn get_gpu_mem_usage() -> Option> { + // As we add more support, expand on this. + + #[cfg(feature = "nvidia")] + get_nvidia_mem_usage() +} + +/// Returns the memory usage of NVIDIA cards. +#[inline] +#[cfg(feature = "nvidia")] +fn get_nvidia_mem_usage() -> Option> { + use crate::data_harvester::nvidia::NVML_DATA; + + if let Ok(nvml) = &*NVML_DATA { + if let Ok(num_gpu) = nvml.device_count() { + let mut results = Vec::with_capacity(num_gpu as usize); + for i in 0..num_gpu { + if let Ok(device) = nvml.device_by_index(i) { + if let (Ok(name), Ok(mem)) = (device.name(), device.memory_info()) { + // add device memory in bytes + let mem_total_in_kib = mem.total / 1024; + let mem_used_in_kib = mem.used / 1024; + results.push(( + name, + MemHarvest { + total_kib: mem_total_in_kib, + used_kib: mem_used_in_kib, + use_percent: if mem_total_in_kib == 0 { + None + } else { + Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0) + }, + }, + )); + } + } + } + Some(results) + } else { + None + } + } else { + None + } +} diff --git a/src/app/data_harvester/memory/sysinfo.rs b/src/app/data_harvester/memory/sysinfo.rs index 7c04ab80..d0c5c8ca 100644 --- a/src/app/data_harvester/memory/sysinfo.rs +++ b/src/app/data_harvester/memory/sysinfo.rs @@ -2,22 +2,10 @@ use sysinfo::{System, SystemExt}; -use crate::data_harvester::memory::{MemCollect, MemHarvest}; - -/// Returns all memory data. -pub(crate) fn get_mem_data(sys: &System, _get_gpu: bool) -> MemCollect { - MemCollect { - ram: get_ram_data(sys), - swap: get_swap_data(sys), - #[cfg(feature = "zfs")] - arc: get_arc_data(), - #[cfg(feature = "gpu")] - gpus: if _get_gpu { get_gpu_data() } else { None }, - } -} +use crate::data_harvester::memory::MemHarvest; /// Returns RAM usage. -pub(crate) fn get_ram_data(sys: &System) -> Option { +pub(crate) fn get_ram_usage(sys: &System) -> Option { let mem_used_in_kib = sys.used_memory() / 1024; let mem_total_in_kib = sys.total_memory() / 1024; @@ -33,7 +21,7 @@ pub(crate) fn get_ram_data(sys: &System) -> Option { } /// Returns SWAP usage. -pub(crate) fn get_swap_data(sys: &System) -> Option { +pub(crate) fn get_swap_usage(sys: &System) -> Option { let mem_used_in_kib = sys.used_swap() / 1024; let mem_total_in_kib = sys.total_swap() / 1024; @@ -47,116 +35,3 @@ pub(crate) fn get_swap_data(sys: &System) -> Option { }, }) } - -/// Return ARC usage. -#[cfg(feature = "zfs")] -pub(crate) fn get_arc_data() -> Option { - let (mem_total_in_kib, mem_used_in_kib) = { - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] - { - // TODO: [OPT] is this efficient? - use std::fs::read_to_string; - if let Ok(arc_stats) = read_to_string("/proc/spl/kstat/zfs/arcstats") { - let mut mem_arc = 0; - let mut mem_total = 0; - let mut zfs_keys_read: u8 = 0; - const ZFS_KEYS_NEEDED: u8 = 2; - - for line in arc_stats.lines() { - if let Some((label, value)) = line.split_once(' ') { - let to_write = match label { - "size" => &mut mem_arc, - "memory_all_bytes" => &mut mem_total, - _ => { - continue; - } - }; - - if let Some((_type, number)) = value.trim_start().rsplit_once(' ') { - // Parse the value, remember it's in bytes! - if let Ok(number) = number.parse::() { - *to_write = number; - // We only need a few keys, so we can bail early. - zfs_keys_read += 1; - if zfs_keys_read == ZFS_KEYS_NEEDED { - break; - } - } - } - } - } - (mem_total / 1024, mem_arc / 1024) - } else { - (0, 0) - } - } else if #[cfg(target_os = "freebsd")] { - use sysctl::Sysctl; - if let (Ok(mem_arc_value), Ok(mem_sys_value)) = ( - sysctl::Ctl::new("kstat.zfs.misc.arcstats.size"), - sysctl::Ctl::new("hw.physmem"), - ) { - if let (Ok(sysctl::CtlValue::U64(arc)), Ok(sysctl::CtlValue::Ulong(mem))) = - (mem_arc_value.value(), mem_sys_value.value()) - { - (mem / 1024, arc / 1024) - } else { - (0, 0) - } - } else { - (0, 0) - } - } else { - (0, 0) - } - } - }; - - Some(MemHarvest { - total_kib: mem_total_in_kib, - used_kib: mem_used_in_kib, - use_percent: if mem_total_in_kib == 0 { - None - } else { - Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0) - }, - }) -} - -/// Return GPU data. Currently only supports NVIDIA cards. -#[cfg(feature = "nvidia")] -pub(crate) fn get_gpu_data() -> Option> { - use crate::data_harvester::nvidia::NVML_DATA; - - if let Ok(nvml) = &*NVML_DATA { - if let Ok(ngpu) = nvml.device_count() { - let mut results = Vec::with_capacity(ngpu as usize); - for i in 0..ngpu { - if let Ok(device) = nvml.device_by_index(i) { - if let (Ok(name), Ok(mem)) = (device.name(), device.memory_info()) { - // add device memory in bytes - let mem_total_in_kib = mem.total / 1024; - let mem_used_in_kib = mem.used / 1024; - results.push(( - name, - MemHarvest { - total_kib: mem_total_in_kib, - used_kib: mem_used_in_kib, - use_percent: if mem_total_in_kib == 0 { - None - } else { - Some(mem_used_in_kib as f64 / mem_total_in_kib as f64 * 100.0) - }, - }, - )); - } - } - } - Some(results) - } else { - None - } - } else { - None - } -} -- cgit v1.2.3