diff options
author | Justin Martin <jaming@protonmail.com> | 2022-10-15 15:08:48 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-15 15:08:48 -0400 |
commit | bd35bbdc9c539e035bc4bf91c799d85e566a6921 (patch) | |
tree | 7de767f70396f4fb51d1fb2d0d011e8cd6350744 /src | |
parent | 41970d9c64ba0a442cd8314456785b4bb6c2f7b7 (diff) |
feature: add gpu ram collector for nvidia feature flag (#794)
* add gpu ram collector for nvidia feature flag
* add row for TX in basic layout
* size gpu point_vec
* use vec for mem basic widget drawing
* remove to_owned
* code review: change mem tuple to struct with cfg fields, rename mem_basic ratio and use vec macro for layout
* build on freebsd
Diffstat (limited to 'src')
-rw-r--r-- | src/app/data_farmer.rs | 30 | ||||
-rw-r--r-- | src/app/data_harvester.rs | 22 | ||||
-rw-r--r-- | src/app/data_harvester/cpu/sysinfo.rs | 12 | ||||
-rw-r--r-- | src/app/data_harvester/memory/general.rs | 10 | ||||
-rw-r--r-- | src/app/data_harvester/memory/general/heim.rs | 76 | ||||
-rw-r--r-- | src/app/data_harvester/memory/general/sysinfo.rs | 73 | ||||
-rw-r--r-- | src/app/data_harvester/nvidia.rs | 3 | ||||
-rw-r--r-- | src/app/data_harvester/temperature/nvidia.rs | 6 | ||||
-rw-r--r-- | src/bin/main.rs | 5 | ||||
-rw-r--r-- | src/canvas.rs | 24 | ||||
-rw-r--r-- | src/canvas/canvas_colours.rs | 23 | ||||
-rw-r--r-- | src/canvas/widgets/mem_basic.rs | 164 | ||||
-rw-r--r-- | src/canvas/widgets/mem_graph.rs | 59 | ||||
-rw-r--r-- | src/constants.rs | 47 | ||||
-rw-r--r-- | src/data_conversion.rs | 96 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/options.rs | 1 |
17 files changed, 523 insertions, 132 deletions
diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index e409957f..a89af0a7 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -43,6 +43,8 @@ pub struct TimedData { pub swap_data: Option<Value>, #[cfg(feature = "zfs")] pub arc_data: Option<Value>, + #[cfg(feature = "gpu")] + pub gpu_data: Vec<Option<Value>>, } #[derive(Clone, Debug, Default)] @@ -133,6 +135,8 @@ pub struct DataCollection { pub battery_harvest: Vec<batteries::BatteryHarvest>, #[cfg(feature = "zfs")] pub arc_harvest: memory::MemHarvest, + #[cfg(feature = "gpu")] + pub gpu_harvest: Vec<(String, memory::MemHarvest)>, } impl Default for DataCollection { @@ -155,6 +159,8 @@ impl Default for DataCollection { battery_harvest: Vec::default(), #[cfg(feature = "zfs")] arc_harvest: memory::MemHarvest::default(), + #[cfg(feature = "gpu")] + gpu_harvest: Vec::default(), } } } @@ -179,6 +185,10 @@ impl DataCollection { { self.arc_harvest = memory::MemHarvest::default(); } + #[cfg(feature = "gpu")] + { + self.gpu_harvest = Vec::default(); + } } pub fn clean_data(&mut self, max_time_millis: u64) { @@ -222,6 +232,14 @@ impl DataCollection { self.eat_arc(arc, &mut new_entry); } } + + #[cfg(feature = "gpu")] + { + if let Some(gpu) = harvested_data.gpu { + self.eat_gpu(gpu, &mut new_entry); + } + } + // CPU if let Some(cpu) = harvested_data.cpu { self.eat_cpu(cpu, &mut new_entry); @@ -405,8 +423,18 @@ impl DataCollection { #[cfg(feature = "zfs")] fn eat_arc(&mut self, arc: memory::MemHarvest, new_entry: &mut TimedData) { - // Arc new_entry.arc_data = arc.use_percent; self.arc_harvest = arc; } + + #[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 + // it probably doesn't matter anyways. + gpu.iter().for_each(|data| { + new_entry.gpu_data.push(data.1.use_percent); + }); + self.gpu_harvest = gpu.to_vec(); + } } diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index cb02bdb1..4f163755 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -17,6 +17,9 @@ use futures::join; use super::DataFilters; +#[cfg(feature = "nvidia")] +pub mod nvidia; + #[cfg(feature = "battery")] pub mod batteries; pub mod cpu; @@ -42,6 +45,8 @@ pub struct Data { pub list_of_batteries: Option<Vec<batteries::BatteryHarvest>>, #[cfg(feature = "zfs")] pub arc: Option<memory::MemHarvest>, + #[cfg(feature = "gpu")] + pub gpu: Option<Vec<(String, memory::MemHarvest)>>, } impl Default for Data { @@ -61,6 +66,8 @@ impl Default for Data { list_of_batteries: None, #[cfg(feature = "zfs")] arc: None, + #[cfg(feature = "gpu")] + gpu: None, } } } @@ -83,6 +90,10 @@ impl Data { { self.arc = None; } + #[cfg(feature = "gpu")] + { + self.gpu = None; + } } } @@ -423,19 +434,24 @@ impl DataCollector { self.data.network = net_data; } - if let Ok(memory) = mem_res.0 { + if let Ok(memory) = mem_res.ram { self.data.memory = memory; } - if let Ok(swap) = mem_res.1 { + if let Ok(swap) = mem_res.swap { self.data.swap = swap; } #[cfg(feature = "zfs")] - if let Ok(arc) = mem_res.2 { + if let Ok(arc) = mem_res.arc { self.data.arc = arc; } + #[cfg(feature = "gpu")] + if let Ok(gpu) = mem_res.gpus { + self.data.gpu = gpu; + } + if let Ok(disks) = disk_res { self.data.disks = disks; } diff --git a/src/app/data_harvester/cpu/sysinfo.rs b/src/app/data_harvester/cpu/sysinfo.rs index a5f363b8..54318e1b 100644 --- a/src/app/data_harvester/cpu/sysinfo.rs +++ b/src/app/data_harvester/cpu/sysinfo.rs @@ -3,9 +3,9 @@ use std::collections::VecDeque; -use sysinfo::{LoadAvg, System, SystemExt}; +use sysinfo::{CpuExt, LoadAvg, System, SystemExt}; -use super::{CpuData, CpuHarvest, PastCpuTotal, PastCpuWork}; +use super::{CpuData, CpuDataType, CpuHarvest, PastCpuTotal, PastCpuWork}; use crate::app::data_harvester::cpu::LoadAvgHarvest; pub async fn get_cpu_data_list( @@ -14,12 +14,11 @@ pub async fn get_cpu_data_list( _previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>, ) -> crate::error::Result<CpuHarvest> { let mut cpu_deque: VecDeque<_> = sys - .processors() + .cpus() .iter() .enumerate() .map(|(i, cpu)| CpuData { - cpu_prefix: "CPU".to_string(), - cpu_count: Some(i), + data_type: CpuDataType::Cpu(i), cpu_usage: cpu.cpu_usage() as f64, }) .collect(); @@ -28,8 +27,7 @@ pub async fn get_cpu_data_list( let cpu = sys.global_cpu_info(); cpu_deque.push_front(CpuData { - cpu_prefix: "AVG".to_string(), - cpu_count: None, + data_type: CpuDataType::Avg, cpu_usage: cpu.cpu_usage() as f64, }) } diff --git a/src/app/data_harvester/memory/general.rs b/src/app/data_harvester/memory/general.rs index 45fb5fdd..84ac1e0d 100644 --- a/src/app/data_harvester/memory/general.rs +++ b/src/app/data_harvester/memory/general.rs @@ -14,3 +14,13 @@ pub struct MemHarvest { pub mem_used_in_kib: u64, pub use_percent: Option<f64>, } + +#[derive(Debug)] +pub struct MemCollect { + pub ram: crate::utils::error::Result<Option<MemHarvest>>, + pub swap: crate::utils::error::Result<Option<MemHarvest>>, + #[cfg(feature = "zfs")] + pub arc: crate::utils::error::Result<Option<MemHarvest>>, + #[cfg(feature = "gpu")] + pub gpus: crate::utils::error::Result<Option<Vec<(String, MemHarvest)>>>, +} diff --git a/src/app/data_harvester/memory/general/heim.rs b/src/app/data_harvester/memory/general/heim.rs index 71a68430..83f78ae4 100644 --- a/src/app/data_harvester/memory/general/heim.rs +++ b/src/app/data_harvester/memory/general/heim.rs @@ -1,20 +1,26 @@ //! Data collection for memory via heim. -use crate::data_harvester::memory::MemHarvest; - -pub async fn get_mem_data( - actually_get: bool, -) -> ( - crate::utils::error::Result<Option<MemHarvest>>, - crate::utils::error::Result<Option<MemHarvest>>, - crate::utils::error::Result<Option<MemHarvest>>, -) { - use futures::join; +use crate::data_harvester::memory::{MemCollect, MemHarvest}; +pub async fn get_mem_data(actually_get: bool) -> MemCollect { if !actually_get { - (Ok(None), Ok(None), Ok(None)) + MemCollect { + ram: Ok(None), + swap: Ok(None), + #[cfg(feature = "zfs")] + arc: Ok(None), + #[cfg(feature = "gpu")] + gpus: Ok(None), + } } else { - join!(get_ram_data(), get_swap_data(), get_arc_data()) + MemCollect { + ram: get_ram_data().await, + swap: get_swap_data().await, + #[cfg(feature = "zfs")] + arc: get_arc_data().await, + #[cfg(feature = "gpu")] + gpus: get_gpu_data().await, + } } } @@ -170,16 +176,15 @@ pub async fn get_swap_data() -> crate::utils::error::Result<Option<MemHarvest>> })) } +#[cfg(feature = "zfs")] pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> { - #[cfg(not(feature = "zfs"))] - let (mem_total_in_kib, mem_used_in_kib) = (0, 0); - - #[cfg(feature = "zfs")] let (mem_total_in_kib, mem_used_in_kib) = { #[cfg(target_os = "linux")] { let mut mem_arc = 0; let mut mem_total = 0; + let mut zfs_keys_read: u8 = 0; + const ZFS_KEYS_NEEDED: u8 = 2; use smol::fs::read_to_string; let arcinfo = read_to_string("/proc/spl/kstat/zfs/arcstats").await?; for line in arcinfo.lines() { @@ -191,8 +196,7 @@ pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> { continue; } }; - let mut zfs_keys_read: u8 = 0; - const ZFS_KEYS_NEEDED: u8 = 2; + if let Some((_type, number)) = value.trim_start().rsplit_once(' ') { // Parse the value, remember it's in bytes! if let Ok(number) = number.parse::<u64>() { @@ -247,3 +251,39 @@ pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> { }, })) } + +#[cfg(feature = "nvidia")] +pub async fn get_gpu_data() -> crate::utils::error::Result<Option<Vec<(String, MemHarvest)>>> { + 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 { + mem_total_in_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) + }, + }, + )); + } + } + } + Ok(Some(results)) + } else { + Ok(None) + } + } else { + Ok(None) + } +} diff --git a/src/app/data_harvester/memory/general/sysinfo.rs b/src/app/data_harvester/memory/general/sysinfo.rs index da4bd812..cf80c206 100644 --- a/src/app/data_harvester/memory/general/sysinfo.rs +++ b/src/app/data_harvester/memory/general/sysinfo.rs @@ -1,26 +1,32 @@ //! Data collection for memory via sysinfo. -use crate::data_harvester::memory::MemHarvest; +use crate::data_harvester::memory::{MemCollect, MemHarvest}; use sysinfo::{System, SystemExt}; -pub async fn get_mem_data( - sys: &System, actually_get: bool, -) -> ( - crate::utils::error::Result<Option<MemHarvest>>, - crate::utils::error::Result<Option<MemHarvest>>, - crate::utils::error::Result<Option<MemHarvest>>, -) { - use futures::join; - +pub async fn get_mem_data(sys: &System, actually_get: bool) -> MemCollect { if !actually_get { - (Ok(None), Ok(None), Ok(None)) + MemCollect { + ram: Ok(None), + swap: Ok(None), + #[cfg(feature = "zfs")] + arc: Ok(None), + #[cfg(feature = "gpu")] + gpus: Ok(None), + } } else { - join!(get_ram_data(sys), get_swap_data(sys), get_arc_data()) + MemCollect { + ram: get_ram_data(sys).await, + swap: get_swap_data(sys).await, + #[cfg(feature = "zfs")] + arc: get_arc_data().await, + #[cfg(feature = "gpu")] + gpus: get_gpu_data().await, + } } } pub async fn get_ram_data(sys: &System) -> crate::utils::error::Result<Option<MemHarvest>> { - let (mem_total_in_kib, mem_used_in_kib) = (sys.total_memory() / 1024, sys.used_memory()) / 1024; + let (mem_total_in_kib, mem_used_in_kib) = (sys.total_memory() / 1024, sys.used_memory() / 1024); Ok(Some(MemHarvest { mem_total_in_kib, @@ -47,11 +53,8 @@ pub async fn get_swap_data(sys: &System) -> crate::utils::error::Result<Option<M })) } +#[cfg(feature = "zfs")] pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> { - #[cfg(not(feature = "zfs"))] - let (mem_total_in_kib, mem_used_in_kib) = (0, 0); - - #[cfg(feature = "zfs")] let (mem_total_in_kib, mem_used_in_kib) = { #[cfg(target_os = "freebsd")] { @@ -82,3 +85,39 @@ pub async fn get_arc_data() -> crate::utils::error::Result<Option<MemHarvest>> { }, })) } + +#[cfg(feature = "nvidia")] +pub async fn get_gpu_data() -> crate::utils::error::Result<Option<Vec<(String, MemHarvest)>>> { + 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 { + mem_total_in_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) + }, + }, + )); + } + } + } + Ok(Some(results)) + } else { + Ok(None) + } + } else { + Ok(None) + } +} diff --git a/src/app/data_harvester/nvidia.rs b/src/app/data_harvester/nvidia.rs new file mode 100644 index 00000000..72928a7c --- /dev/null +++ b/src/app/data_harvester/nvidia.rs @@ -0,0 +1,3 @@ +use nvml_wrapper::{error::NvmlError, NVML}; +use once_cell::sync::Lazy; +pub static NVML_DATA: Lazy<Result<NVML, NvmlError>> = Lazy::new(NVML::init); diff --git a/src/app/data_harvester/temperature/nvidia.rs b/src/app/data_harvester/temperature/nvidia.rs index c30345ab..049708b7 100644 --- a/src/app/data_harvester/temperature/nvidia.rs +++ b/src/app/data_harvester/temperature/nvidia.rs @@ -5,12 +5,14 @@ use super::{ TemperatureType, }; -use nvml_wrapper::{enum_wrappers::device::TemperatureSensor, NVML}; +use nvml_wrapper::enum_wrappers::device::TemperatureSensor; + +use crate::data_harvester::nvidia::NVML_DATA; pub fn add_nvidia_data( temperature_vec: &mut Vec<TempHarvest>, temp_type: &TemperatureType, filter: &Option<Filter>, ) -> crate::utils::error::Result<()> { - if let Ok(nvml) = NVML::init() { + if let Ok(nvml) = &*NVML_DATA { if let Ok(ngpu) = nvml.device_count() { for i in 0..ngpu { if let Ok(device) = nvml.device_by_index(i) { diff --git a/src/bin/main.rs b/src/bin/main.rs index 4d7a0a34..a5473b00 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -210,6 +210,11 @@ fn main() -> Result<()> { app.converted_data.arc_data = convert_arc_data_points(&app.data_collection); } + #[cfg(feature = "gpu")] + { + app.converted_data.gpu_data = + convert_gpu_data(&app.data_collection); + } let (memory_labels, swap_labels) = convert_mem_labels(&app.data_collection); diff --git a/src/canvas.rs b/src/canvas.rs index f171bddd..c9312700 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -451,19 +451,29 @@ impl Painter { } }; - let mut mem_rows = 0; + let mut mem_rows = 1; + + if app_state.converted_data.swap_labels.is_some() { + mem_rows += 1; // add row for swap + } #[cfg(feature = "zfs")] { - let arc_data = &app_state.converted_data.arc_data; - if let Some(arc) = arc_data.last() { - if arc.1 != 0.0 { - mem_rows += 1; // add row for arc - } + if app_state.converted_data.arc_labels.is_some() { + mem_rows += 1; // add row for arc + } + } + + #[cfg(feature = "gpu")] + { + if let Some(gpu_data) = &app_state.converted_data.gpu_data { + mem_rows += gpu_data.len() as u16; // add row(s) for gpu } } - mem_rows += 2; // add rows for SWAP and MEM + if mem_rows == 1 { + mem_rows += 1; // need at least 2 rows for RX and TX + } let vertical_chunks = Layout::default() .direction(Direction::Vertical) diff --git a/src/canvas/canvas_colours.rs b/src/canvas/canvas_colours.rs index 9630cc42..ab9b079e 100644 --- a/src/canvas/canvas_colours.rs +++ b/src/canvas/canvas_colours.rs @@ -18,6 +18,7 @@ pub struct CanvasColours { pub ram_style: Style, pub swap_style: Style, pub arc_style: Style, + pub gpu_colour_styles: Vec<Style>, pub rx_style: Style, pub tx_style: Style, pub total_rx_style: Style, @@ -51,6 +52,15 @@ impl Default for CanvasColours { ram_style: Style::default().fg(STANDARD_FIRST_COLOUR), swap_style: Style::default().fg(STANDARD_SECOND_COLOUR), arc_style: Style::default().fg(STANDARD_THIRD_COLOUR), + gpu_colour_styles: vec![ + Style::default().fg(STANDARD_FOURTH_COLOUR), + Style::default().fg(Color::LightBlue), + Style::default().fg(Color::LightRed), + Style::default().fg(Color::Cyan), + Style::default().fg(Color::Green), + Style::default().fg(Color::Blue), + Style::default().fg(Color::Red), + ], rx_style: Style::default().fg(STANDARD_FIRST_COLOUR), tx_style: Style::default().fg(STANDARD_SECOND_COLOUR), total_rx_style: Style::default().fg(STANDARD_THIRD_COLOUR), @@ -160,6 +170,11 @@ impl CanvasColours { .context("Update 'arc_color' in your config file..")?; } + if let Some(gpu_core_colors) = &colours.gpu_core_colors { + self.set_gpu_colours(gpu_core_colors) + .context("Update 'gpu_core_colors' in your config file..")?; + } + if let Some(rx_color) = &colours.rx_color { self.set_rx_colour(rx_color) .context("Update 'rx_color' in your config file..")?; @@ -268,6 +283,14 @@ impl CanvasColours { Ok(()) } + pub fn set_gpu_colours(&mut self, colours: &[String]) -> error::Result<()> { + self.gpu_colour_styles = colours + .iter() + .map(|colour| get_style_from_config(colour)) + .collect::<error::Result<Vec<Style>>>()?; + Ok(()) + } + pub fn set_rx_colour(&mut self, colour: &str) -> error::Result<()> { self.rx_style = get_style_from_config(colour)?; Ok(()) diff --git a/src/canvas/widgets/mem_basic.rs b/src/canvas/widgets/mem_basic.rs index 3e5e585d..8f372eff 100644 --- a/src/canvas/widgets/mem_basic.rs +++ b/src/canvas/widgets/mem_basic.rs @@ -14,23 +14,7 @@ impl Painter { &self, f: &mut Frame<'_, B>, app_state: &mut App, draw_loc: Rect, widget_id: u64, ) { let mem_data = &app_state.converted_data.mem_data; - let swap_data = &app_state.converted_data.swap_data; - - let margined_loc = Layout::default() - .constraints({ - #[cfg(feature = "zfs")] - { - [Constraint::Length(1); 3] - } - - #[cfg(not(feature = "zfs"))] - { - [Constraint::Length(1); 2] - } - }) - .direction(Direction::Vertical) - .horizontal_margin(1) - .split(draw_loc); + let mut draw_widgets: Vec<PipeGauge<'_>> = Vec::new(); if app_state.current_widget.widget_id == widget_id { f.render_widget( @@ -41,13 +25,8 @@ impl Painter { ); } - let ram_ratio = if let Some(mem) = mem_data.last() { - mem.1 / 100.0 - } else { - 0.0 - }; - let swap_ratio = if let Some(swap) = swap_data.last() { - swap.1 / 100.0 + let ram_percentage = if let Some(mem) = mem_data.last() { + mem.1 } else { 0.0 }; @@ -56,64 +35,129 @@ impl Painter { let memory_fraction_label = if let Some((_, label_frac)) = &app_state.converted_data.mem_labels { - label_frac.trim() - } else { - EMPTY_MEMORY_FRAC_STRING - }; - - let swap_fraction_label = - if let Some((_, label_frac)) = &app_state.converted_data.swap_labels { - label_frac.trim() + if app_state.basic_mode_use_percent { + format!("{:3.0}%", ram_percentage.round()) + } else { + label_frac.trim().to_string() + } } else { - EMPTY_MEMORY_FRAC_STRING + EMPTY_MEMORY_FRAC_STRING.to_string() }; - f.render_widget( + draw_widgets.push( PipeGauge::default() - .ratio(ram_ratio) + .ratio(ram_percentage / 100.0) .start_label("RAM") .inner_label(memory_fraction_label) .label_style(self.colours.ram_style) .gauge_style(self.colours.ram_style), - margined_loc[0], ); - f.render_widget( - PipeGauge::default() - .ratio(swap_ratio) - .start_label("SWP") - .inner_label(swap_fraction_label) - .label_style(self.colours.swap_style) - .gauge_style(self.colours.swap_style), - margined_loc[1], - ); + let swap_data = &app_state.converted_data.swap_data; + + let swap_percentage = if let Some(swap) = swap_data.last() { + swap.1 + } else { + 0.0 + }; + + if let Some((_, label_frac)) = &app_state.converted_data.swap_labels { + let swap_fraction_label = if app_state.basic_mode_use_percent { + format!("{:3.0}%", swap_percentage.round()) + } else { + label_frac.trim().to_string() + }; + draw_widgets.push( + PipeGauge::default() + .ratio(swap_percentage / 100.0) + .start_label("SWP") + .inner_label(swap_fraction_label) + .label_style(self.colours.swap_style) + .gauge_style(self.colours.swap_style), + ); + } #[cfg(feature = "zfs")] { let arc_data = &app_state.converted_data.arc_data; - let arc_ratio = if let Some(arc) = arc_data.last() { - arc.1 / 100.0 + let arc_percentage = if let Some(arc) = arc_data.last() { + arc.1 } else { 0.0 }; - let arc_fraction_label = - if let Some((_, label_frac)) = &app_state.converted_data.arc_labels { - label_frac.trim() + if let Some((_, label_frac)) = &app_state.converted_data.arc_labels { + let arc_fraction_label = if app_state.basic_mode_use_percent { + format!("{:3.0}%", arc_percentage.round()) } else { - EMPTY_MEMORY_FRAC_STRING + label_frac.trim().to_string() }; + draw_widgets.push( + PipeGauge::default() + .ratio(arc_percentage / 100.0) + .start_label("ARC") + .inner_label(arc_fraction_label) + .label_style(self.colours.arc_style) + .gauge_style(self.colours.arc_style), + ); + } + } - f.render_widget( - PipeGauge::default() - .ratio(arc_ratio) - .start_label("ARC") - .inner_label(arc_fraction_label) - .label_style(self.colours.arc_style) - .gauge_style(self.colours.arc_style), - margined_loc[2], - ); + #[cfg(feature = "gpu")] + { + let gpu_styles = &self.colours.gpu_colour_styles; + let mut color_index = 0; + if let Some(gpu_data) = &app_state.converted_data.gpu_data { + gpu_data.iter().for_each(|gpu_data_vec| { + let gpu_data = gpu_data_vec.points.as_slice(); + let gpu_percentage = if let Some(gpu) = gpu_data.last() { + gpu.1 + } else { + 0.0 + }; + let trimmed_gpu_frac = { + if app_state.basic_mode_use_percent { + format!("{:3.0}%", gpu_percentage.round()) + } else { + gpu_data_vec.mem_total.trim().to_string() + } + }; + let style = { + if gpu_styles.is_empty() { + tui::style::Style::default() + } else if color_index >= gpu_styles.len() { + // cycle styles + color_index = 1; + gpu_styles[color_index - 1] + } else { + color_index += 1; + gpu_styles[color_index - 1] + } + }; + draw_widgets.push( + PipeGauge::default() + .ratio(gpu_percentage / 100.0) + .start_label("GPU") + .inner_label(trimmed_gpu_frac) + .label_style(style) + .gauge_style(style), + ); + }); + } } + let margined_loc = Layout::default() + .constraints(vec![Constraint::Length(1); draw_widgets.len()]) + .direction(Direction::Vertical) + .horizontal_margin(1) + .split(draw_loc); + + draw_widgets + .into_iter() + .enumerate() + .for_each(|(index, widget)| { + f.render_widget(widget, margined_loc[index]); + }); + // Update draw loc in widget map if app_state.should_get_widget_bounds() { if let Some(widget) = app_state.widget_map.get_mut(&widget_id) { diff --git a/src/canvas/widgets/mem_graph.rs b/src/canvas/widgets/mem_graph.rs index bd959d28..c156fbaa 100644 --- a/src/canvas/widgets/mem_graph.rs +++ b/src/canvas/widgets/mem_graph.rs @@ -29,18 +29,22 @@ impl Painter { draw_loc, ); let points = { - let mut size = 0; + let mut size = 1; + if app_state.converted_data.swap_labels.is_some() { + size += 1; // add capacity for SWAP + } #[cfg(feature = "zfs")] { - let arc_data = &app_state.converted_data.arc_data; - if let Some(arc) = arc_data.last() { - if arc.1 != 0.0 { - size += 1; // add capacity for ARC - } + if app_state.converted_data.arc_labels.is_some() { + size += 1; // add capacity for ARC + } + } + #[cfg(feature = "gpu")] + { + if let Some(gpu_data) = &app_state.converted_data.gpu_data { + size += gpu_data.len(); // add row(s) for gpu } } - - size += 2; // add capacity for RAM and SWP let mut points = Vec::with_capacity(size); if let Some((label_p |