From 6e0bc960939d4c74343f83500cba2acbdac441c9 Mon Sep 17 00:00:00 2001 From: Justin Martin Date: Mon, 22 Aug 2022 02:47:22 -0400 Subject: [PATCH] feature: Add zfs feature flag for arc memory (#784) * freebsd clippy * add arc support * Code Review: moved runtime cfg checks to compile time and formatting * remove compile platform checks * add zfs feature flag to get_arc_data --- Cargo.lock | 34 ++++++++ Cargo.toml | 4 +- src/app/data_farmer.rs | 23 +++++ src/app/data_harvester.rs | 13 +++ src/app/data_harvester/cpu/sysinfo.rs | 2 +- src/app/data_harvester/memory/general/heim.rs | 83 ++++++++++++++++++- .../data_harvester/memory/general/sysinfo.rs | 41 ++++++++- src/bin/main.rs | 10 +++ src/canvas.rs | 16 +++- src/canvas/canvas_colours.rs | 12 +++ src/canvas/widgets/mem_basic.rs | 35 ++++++++ src/canvas/widgets/mem_graph.rs | 29 ++++++- src/constants.rs | 7 ++ src/data_conversion.rs | 69 +++++++++++++++ src/lib.rs | 4 + src/options.rs | 1 + 16 files changed, 375 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afa29d97..12745410 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,6 +236,7 @@ dependencies = [ "serde_json", "smol", "starship-battery", + "sysctl", "sysinfo", "thiserror", "time", @@ -1358,6 +1359,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1511,6 +1521,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sysctl" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225e483f02d0ad107168dc57381a8a40c3aeea6abe47f37506931f861643cfa8" +dependencies = [ + "bitflags", + "byteorder", + "libc", + "thiserror", + "walkdir", +] + [[package]] name = "sysinfo" version = "0.23.10" @@ -1681,6 +1704,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 8befb5c2..12819efd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,11 +41,12 @@ opt-level = 3 codegen-units = 1 [features] -default = ["fern", "log", "battery", "gpu"] +default = ["fern", "log", "battery", "gpu", "zfs"] battery = ["starship-battery"] deploy = ["battery", "gpu"] gpu = ["nvidia"] nvidia = ["nvml-wrapper"] +zfs = ["sysctl"] [dependencies] anyhow = "1.0.57" @@ -96,6 +97,7 @@ winapi = "0.3.9" [target.'cfg(target_os = "freebsd")'.dependencies] serde_json = { version = "1.0.82" } +sysctl = { version = "0.4.6", optional = true } [dev-dependencies] assert_cmd = "2.0.4" diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs index 0f9d65d7..3b6f6dc1 100644 --- a/src/app/data_farmer.rs +++ b/src/app/data_farmer.rs @@ -41,6 +41,8 @@ pub struct TimedData { pub load_avg_data: [f32; 3], pub mem_data: Option, pub swap_data: Option, + #[cfg(feature = "zfs")] + pub arc_data: Option, } pub type StringPidMap = FxHashMap>; @@ -161,6 +163,8 @@ pub struct DataCollection { pub temp_harvest: Vec, #[cfg(feature = "battery")] pub battery_harvest: Vec, + #[cfg(feature = "zfs")] + pub arc_harvest: memory::MemHarvest, } impl Default for DataCollection { @@ -182,6 +186,8 @@ impl Default for DataCollection { temp_harvest: Vec::default(), #[cfg(feature = "battery")] battery_harvest: Vec::default(), + #[cfg(feature = "zfs")] + arc_harvest: memory::MemHarvest::default(), } } } @@ -202,6 +208,10 @@ impl DataCollection { { self.battery_harvest = Vec::default(); } + #[cfg(feature = "zfs")] + { + self.arc_harvest = memory::MemHarvest::default(); + } } pub fn freeze(&mut self) { @@ -247,6 +257,12 @@ impl DataCollection { self.eat_memory_and_swap(memory, swap, &mut new_entry); } + #[cfg(feature = "zfs")] + { + if let Some(arc) = harvested_data.arc { + self.eat_arc(arc, &mut new_entry); + } + } // CPU if let Some(cpu) = harvested_data.cpu { self.eat_cpu(cpu, &mut new_entry); @@ -427,4 +443,11 @@ impl DataCollection { fn eat_battery(&mut self, list_of_batteries: Vec) { self.battery_harvest = list_of_batteries; } + + #[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; + } } diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs index 3342ed17..a15be6e8 100644 --- a/src/app/data_harvester.rs +++ b/src/app/data_harvester.rs @@ -40,6 +40,8 @@ pub struct Data { pub io: Option, #[cfg(feature = "battery")] pub list_of_batteries: Option>, + #[cfg(feature = "zfs")] + pub arc: Option, } impl Default for Data { @@ -57,6 +59,8 @@ impl Default for Data { network: None, #[cfg(feature = "battery")] list_of_batteries: None, + #[cfg(feature = "zfs")] + arc: None, } } } @@ -75,6 +79,10 @@ impl Data { if let Some(network) = &mut self.network { network.first_run_cleanup(); } + #[cfg(feature = "zfs")] + { + self.arc = None; + } } } @@ -421,6 +429,11 @@ impl DataCollector { self.data.swap = swap; } + #[cfg(feature = "zfs")] + if let Ok(arc) = mem_res.2 { + self.data.arc = arc; + } + 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 3096e556..864161d4 100644 --- a/src/app/data_harvester/cpu/sysinfo.rs +++ b/src/app/data_harvester/cpu/sysinfo.rs @@ -10,7 +10,7 @@ use crate::app::data_harvester::cpu::LoadAvgHarvest; pub async fn get_cpu_data_list( sys: &sysinfo::System, show_average_cpu: bool, - _previous_cpu_times: &mut Vec<(PastCpuWork, PastCpuTotal)>, + _previous_cpu_times: &mut [(PastCpuWork, PastCpuTotal)], _previous_average_cpu_time: &mut Option<(PastCpuWork, PastCpuTotal)>, ) -> crate::error::Result { let mut cpu_deque: VecDeque<_> = sys diff --git a/src/app/data_harvester/memory/general/heim.rs b/src/app/data_harvester/memory/general/heim.rs index 9f845b27..71a68430 100644 --- a/src/app/data_harvester/memory/general/heim.rs +++ b/src/app/data_harvester/memory/general/heim.rs @@ -7,13 +7,14 @@ pub async fn get_mem_data( ) -> ( crate::utils::error::Result>, crate::utils::error::Result>, + crate::utils::error::Result>, ) { use futures::join; if !actually_get { - (Ok(None), Ok(None)) + (Ok(None), Ok(None), Ok(None)) } else { - join!(get_ram_data(), get_swap_data()) + join!(get_ram_data(), get_swap_data(), get_arc_data()) } } @@ -168,3 +169,81 @@ pub async fn get_swap_data() -> crate::utils::error::Result> }, })) } + +pub async fn get_arc_data() -> crate::utils::error::Result> { + #[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; + use smol::fs::read_to_string; + let arcinfo = read_to_string("/proc/spl/kstat/zfs/arcstats").await?; + for line in arcinfo.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; + } + }; + 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::() { + *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) + } + + #[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) + } + } + #[cfg(target_os = "macos")] + { + (0, 0) + } + #[cfg(target_os = "windows")] + { + (0, 0) + } + }; + + Ok(Some(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) + }, + })) +} diff --git a/src/app/data_harvester/memory/general/sysinfo.rs b/src/app/data_harvester/memory/general/sysinfo.rs index 8ff3bcab..761757e1 100644 --- a/src/app/data_harvester/memory/general/sysinfo.rs +++ b/src/app/data_harvester/memory/general/sysinfo.rs @@ -8,13 +8,14 @@ pub async fn get_mem_data( ) -> ( crate::utils::error::Result>, crate::utils::error::Result>, + crate::utils::error::Result>, ) { use futures::join; if !actually_get { - (Ok(None), Ok(None)) + (Ok(None), Ok(None), Ok(None)) } else { - join!(get_ram_data(sys), get_swap_data(sys)) + join!(get_ram_data(sys), get_swap_data(sys), get_arc_data()) } } @@ -45,3 +46,39 @@ pub async fn get_swap_data(sys: &System) -> crate::utils::error::Result crate::utils::error::Result> { + #[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")] + { + 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) + } + } + }; + Ok(Some(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) + }, + })) +} diff --git a/src/bin/main.rs b/src/bin/main.rs index 4e274ca0..9ac593ff 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -191,11 +191,21 @@ fn main() -> Result<()> { convert_mem_data_points(&app.data_collection); app.converted_data.swap_data = convert_swap_data_points(&app.data_collection); + #[cfg(feature = "zfs")] + { + app.converted_data.arc_data = + convert_arc_data_points(&app.data_collection); + } let (memory_labels, swap_labels) = convert_mem_labels(&app.data_collection); app.converted_data.mem_labels = memory_labels; app.converted_data.swap_labels = swap_labels; + #[cfg(feature = "zfs")] + { + let arc_labels = convert_arc_labels(&app.data_collection); + app.converted_data.arc_labels = arc_labels; + } } if app.used_widgets.use_cpu { diff --git a/src/canvas.rs b/src/canvas.rs index f5ee4488..3a3549a2 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -502,12 +502,26 @@ impl Painter { } }; + let mut mem_rows = 0; + + #[cfg(feature = "zfs")] + { + let arc_data: &[(f64, f64)] = &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 + } + } + } + + mem_rows += 2; // add rows for SWAP and MEM + let vertical_chunks = Layout::default() .direction(Direction::Vertical) .margin(0) .constraints([ Constraint::Length(cpu_height), - Constraint::Length(2), + Constraint::Length(mem_rows), Constraint::Length(2), Constraint::Min(5), ]) diff --git a/src/canvas/canvas_colours.rs b/src/canvas/canvas_colours.rs index 316b8e3c..ff595dce 100644 --- a/src/canvas/canvas_colours.rs +++ b/src/canvas/canvas_colours.rs @@ -11,6 +11,7 @@ pub struct CanvasColours { pub table_header_style: Style, pub ram_style: Style, pub swap_style: Style, + pub arc_style: Style, pub rx_style: Style, pub tx_style: Style, pub total_rx_style: Style, @@ -43,6 +44,7 @@ impl Default for CanvasColours { table_header_style: Style::default().fg(STANDARD_HIGHLIGHT_COLOUR), ram_style: Style::default().fg(STANDARD_FIRST_COLOUR), swap_style: Style::default().fg(STANDARD_SECOND_COLOUR), + arc_style: Style::default().fg(STANDARD_THIRD_COLOUR), 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), @@ -117,6 +119,11 @@ impl CanvasColours { .context("Update 'swap_color' in your config file..")?; } + if let Some(arc_color) = &colours.arc_color { + self.set_arc_colour(arc_color) + .context("Update 'arc_color' 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..")?; @@ -220,6 +227,11 @@ impl CanvasColours { Ok(()) } + pub fn set_arc_colour(&mut self, colour: &str) -> error::Result<()> { + self.arc_style = get_style_from_config(colour)?; + 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 ae2b7f1f..60f35f09 100644 --- a/src/canvas/widgets/mem_basic.rs +++ b/src/canvas/widgets/mem_basic.rs @@ -105,6 +105,41 @@ impl Painter { let mem_text = vec![ Spans::from(Span::styled(mem_label, self.colours.ram_style)), Spans::from(Span::styled(swap_label, self.colours.swap_style)), + #[cfg(feature = "zfs")] + { + let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data; + let arc_use_percentage = if let Some(arc) = arc_data.last() { + arc.1 + } else { + 0.0 + }; + let trimmed_arc_frac = if let Some((_label_percent, label_frac)) = + &app_state.converted_data.arc_labels + { + label_frac.trim() + } else { + EMPTY_MEMORY_FRAC_STRING + }; + let arc_bar_length = usize::from(draw_loc.width.saturating_sub(7)) + .saturating_sub(trimmed_arc_frac.len()); + let num_bars_arc = calculate_basic_use_bars(arc_use_percentage, arc_bar_length); + let arc_label = if app_state.basic_mode_use_percent { + format!( + "ARC[{}{}{:3.0}%]", + "|".repeat(num_bars_arc), + " ".repeat(arc_bar_length - num_bars_arc + trimmed_arc_frac.len() - 4), + arc_use_percentage.round() + ) + } else { + format!( + "ARC[{}{}{}]", + "|".repeat(num_bars_arc), + " ".repeat(arc_bar_length - num_bars_arc), + trimmed_arc_frac + ) + }; + Spans::from(Span::styled(arc_label, self.colours.arc_style)) + }, ]; f.render_widget( diff --git a/src/canvas/widgets/mem_graph.rs b/src/canvas/widgets/mem_graph.rs index 7ef2fff4..25ca272e 100644 --- a/src/canvas/widgets/mem_graph.rs +++ b/src/canvas/widgets/mem_graph.rs @@ -29,7 +29,20 @@ impl Painter { draw_loc, ); let points = { - let mut points = Vec::with_capacity(2); + let mut size = 0; + #[cfg(feature = "zfs")] + { + let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data; + if let Some(arc) = arc_data.last() { + if arc.1 != 0.0 { + size += 1; // add capacity for ARC + } + } + } + + size += 2; // add capacity for RAM and SWP + + let mut points = Vec::with_capacity(size); if let Some((label_percent, label_frac)) = &app_state.converted_data.mem_labels { let mem_label = format!("RAM:{}{}", label_percent, label_frac); points.push(GraphData { @@ -46,6 +59,20 @@ impl Painter { name: Some(swap_label.into()), }); } + #[cfg(feature = "zfs")] + if let Some((label_percent, label_frac)) = &app_state.converted_data.arc_labels { + let arc_data: &[(f64, f64)] = &app_state.converted_data.arc_data; + if let Some(arc) = arc_data.last() { + if arc.1 != 0.0 { + let arc_label = format!("ARC:{}{}", label_percent, label_frac); + points.push(GraphData { + points: &app_state.converted_data.arc_data, + style: self.colours.arc_style, + name: Some(arc_label.into()), + }); + } + } + } points }; diff --git a/src/constants.rs b/src/constants.rs index f77c1864..a10b766b 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -40,6 +40,7 @@ pub static DEFAULT_LIGHT_MODE_COLOUR_PALETTE: Lazy = Lazy::new(|| disabled_text_color: Some("gray".to_string()), ram_color: Some("blue".to_string()), swap_color: Some("red".to_string()), + arc_color: Some("LightBlue".to_string()), rx_color: Some("blue".to_string()), tx_color: Some("red".to_string()), rx_total_color: Some("LightBlue".to_string()), @@ -84,6 +85,7 @@ pub static GRUVBOX_COLOUR_PALETTE: Lazy = Lazy::new(|| ConfigColo ]), ram_color: Some("#8ec07c".to_string()), swap_color: Some("#fabd2f".to_string()), + arc_color: Some("#689d6a".to_string()), rx_color: Some("#8ec07c".to_string()), tx_color: Some("#fabd2f".to_string()), rx_total_color: Some("#689d6a".to_string()), @@ -129,6 +131,7 @@ pub static GRUVBOX_LIGHT_COLOUR_PALETTE: Lazy = Lazy::new(|| Conf ]), ram_color: Some("#427b58".to_string()), swap_color: Some("#cc241d".to_string()), + arc_color: Some("#689d6a".to_string()), rx_color: Some("#427b58".to_string()), tx_color: Some("#cc241d".to_string()), rx_total_color: Some("#689d6a".to_string()), @@ -162,6 +165,7 @@ pub static NORD_COLOUR_PALETTE: Lazy = Lazy::new(|| ConfigColours ]), ram_color: Some("#88c0d0".to_string()), swap_color: Some("#d08770".to_string()), + arc_color: Some("#5e81ac".to_string()), rx_color: Some("#88c0d0".to_string()), tx_color: Some("#d08770".to_string()), rx_total_color: Some("#5e81ac".to_string()), @@ -195,6 +199,7 @@ pub static NORD_LIGHT_COLOUR_PALETTE: Lazy = Lazy::new(|| ConfigC ]), ram_color: Some("#81a1c1".to_string()), swap_color: Some("#d08770".to_string()), + arc_color: Some("#5e81ac".to_string()), rx_color: Some("#81a1c1".to_string()), tx_color: Some("#d08770".to_string()), rx_total_color: Some("#5e81ac".to_string()), @@ -513,6 +518,8 @@ pub const CONFIG_TEXT: &str = r##"# This is a default config file for bottom. A #ram_color="LightMagenta" # Represents the colour SWAP will use in the memory legend and graph. #swap_color="LightYellow" +# Represents the colour ARC will use in the memory legend and graph. +#arc_color="LightCyan" # Represents the colour rx will use in the network legend and graph. #rx_color="LightCyan" # Represents the colour tx will use in the network legend and graph. diff --git a/src/data_conversion.rs b/src/data_conversion.rs index 96e7bdfa..23d0502d 100644 --- a/src/data_conversion.rs +++ b/src/data_conversion.rs @@ -89,9 +89,11 @@ pub struct ConvertedData { pub mem_labels: Option<(String, String)>, pub swap_labels: Option<(String, String)>, + pub arc_labels: Option<(String, String)>, pub mem_data: Vec, // TODO: Switch this and all data points over to a better data structure... pub swap_data: Vec, + pub arc_data: Vec, pub load_avg_data: [f32; 3], pub cpu_data: Vec, pub battery_data: Vec, @@ -654,6 +656,73 @@ pub fn convert_battery_harvest( .collect() } +#[cfg(feature = "zfs")] +pub fn convert_arc_labels(current_data: &data_farmer::DataCollection) -> Option<(String, String)> { + /// Returns the unit type and denominator for given total amount of memory in kibibytes. + fn return_unit_and_denominator_for_mem_kib(mem_total_kib: u64) -> (&'static str, f64) { + if mem_total_kib < 1024 { + // Stay with KiB + ("KiB", 1.0) + } else if mem_total_kib < MEBI_LIMIT { + // Use MiB + ("MiB", KIBI_LIMIT_F64) + } else if mem_total_kib < GIBI_LIMIT { + // Use GiB + ("GiB", MEBI_LIMIT_F64) + } else { + // Use TiB + ("TiB", GIBI_LIMIT_F64) + } + } + + if current_data.arc_harvest.mem_total_in_kib > 0 { + Some(( + format!( + "{:3.0}%", + current_data.arc_harvest.use_percent.unwrap_or(0.0) + ), + { + let (unit, denominator) = return_unit_and_denominator_for_mem_kib( + current_data.arc_harvest.mem_total_in_kib, + ); + + format!( + " {:.1}{}/{:.1}{}", + current_data.arc_harvest.mem_used_in_kib as f64 / denominator, + unit, + (current_data.arc_harvest.mem_total_in_kib as f64 / denominator), + unit + ) + }, + )) + } else { + None + } +} + +#[cfg(feature = "zfs")] +pub fn convert_arc_data_points(current_data: &data_farmer::DataCollection) -> Vec { + let mut result: Vec = Vec::new(); + let current_time = if let Some(frozen_instant) = current_data.frozen_instant { + frozen_instant + } else { + current_data.current_instant + }; + + for (time, data) in ¤t_data.timed_data_vec { + if let Some(arc_data) = data.arc_data { + let time_from_start: f64 = + (current_time.duration_since(*time).as_millis() as f64).floor(); + result.push((-time_from_start, arc_data)); + if *time == current_time { + break; + } + } + } + + result +} + #[cfg(test)] mod test { use super::*; diff --git a/src/lib.rs b/src/lib.rs index 4c5c099b..f8ddcd99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -339,6 +339,10 @@ pub fn update_data(app: &mut App) { if app.mem_state.force_update.is_some() { app.converted_data.mem_data = convert_mem_data_points(&app.data_collection); app.converted_data.swap_data = convert_swap_data_points(&app.data_collection); + #[cfg(feature = "zfs")] + { + app.converted_data.arc_data = convert_arc_data_points(&app.data_collection); + } app.mem_state.force_update = None; } diff --git a/src/options.rs b/src/options.rs index 30a12f08..12b05372 100644 --- a/src/options.rs +++ b/src/options.rs @@ -199,6 +199,7 @@ pub struct ConfigColours { pub cpu_core_colors: Option>, pub ram_color: Option, pub swap_color: Option, + pub arc_color: Option, pub rx_color: Option, pub tx_color: Option, pub rx_total_color: Option, // These only affect basic mode.