refactor: use nonzero in mem data (#1673)

* refactor: use nonzerou64 for mem data

* clippy

* comment
This commit is contained in:
Clement Tsang 2025-02-12 00:58:15 -05:00 committed by GitHub
parent 22fbd7d630
commit 702775f58d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 124 additions and 141 deletions

View File

@ -7,7 +7,7 @@ use std::{
use crate::collection::batteries; use crate::collection::batteries;
use crate::{ use crate::{
app::AppConfigFields, app::AppConfigFields,
collection::{cpu, disks, memory::MemHarvest, network, Data}, collection::{cpu, disks, memory::MemData, network, Data},
dec_bytes_per_second_string, dec_bytes_per_second_string,
utils::data_units::DataUnit, utils::data_units::DataUnit,
widgets::{DiskWidgetData, TempWidgetData}, widgets::{DiskWidgetData, TempWidgetData},
@ -23,14 +23,14 @@ pub struct StoredData {
pub last_update_time: Instant, // FIXME: (points_rework_v1) remove this? pub last_update_time: Instant, // FIXME: (points_rework_v1) remove this?
pub timeseries_data: TimeSeriesData, // FIXME: (points_rework_v1) Skip in basic? pub timeseries_data: TimeSeriesData, // FIXME: (points_rework_v1) Skip in basic?
pub network_harvest: network::NetworkHarvest, pub network_harvest: network::NetworkHarvest,
pub ram_harvest: MemHarvest, pub ram_harvest: Option<MemData>,
pub swap_harvest: Option<MemHarvest>, pub swap_harvest: Option<MemData>,
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub cache_harvest: Option<MemHarvest>, pub cache_harvest: Option<MemData>,
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
pub arc_harvest: Option<MemHarvest>, pub arc_harvest: Option<MemData>,
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
pub gpu_harvest: Vec<(String, MemHarvest)>, pub gpu_harvest: Vec<(String, MemData)>,
pub cpu_harvest: cpu::CpuHarvest, pub cpu_harvest: cpu::CpuHarvest,
pub load_avg_harvest: cpu::LoadAvgHarvest, pub load_avg_harvest: cpu::LoadAvgHarvest,
pub process_data: ProcessData, pub process_data: ProcessData,
@ -48,7 +48,7 @@ impl Default for StoredData {
last_update_time: Instant::now(), last_update_time: Instant::now(),
timeseries_data: TimeSeriesData::default(), timeseries_data: TimeSeriesData::default(),
network_harvest: network::NetworkHarvest::default(), network_harvest: network::NetworkHarvest::default(),
ram_harvest: MemHarvest::default(), ram_harvest: None,
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
cache_harvest: None, cache_harvest: None,
swap_harvest: None, swap_harvest: None,
@ -96,10 +96,7 @@ impl StoredData {
self.network_harvest = network; self.network_harvest = network;
} }
if let Some(memory) = data.memory { self.ram_harvest = data.memory;
self.ram_harvest = memory;
}
self.swap_harvest = data.swap; self.swap_harvest = data.swap;
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]

View File

@ -99,13 +99,13 @@ impl TimeSeriesData {
} }
if let Some(memory) = &data.memory { if let Some(memory) = &data.memory {
self.ram.try_push(memory.checked_percent()); self.ram.push(memory.percentage());
} else { } else {
self.ram.insert_break(); self.ram.insert_break();
} }
if let Some(swap) = &data.swap { if let Some(swap) = &data.swap {
self.swap.try_push(swap.checked_percent()); self.swap.push(swap.percentage());
} else { } else {
self.swap.insert_break(); self.swap.insert_break();
} }
@ -113,7 +113,7 @@ impl TimeSeriesData {
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
{ {
if let Some(cache) = &data.cache { if let Some(cache) = &data.cache {
self.cache_mem.try_push(cache.checked_percent()); self.cache_mem.push(cache.percentage());
} else { } else {
self.cache_mem.insert_break(); self.cache_mem.insert_break();
} }
@ -122,7 +122,7 @@ impl TimeSeriesData {
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
{ {
if let Some(arc) = &data.arc { if let Some(arc) = &data.arc {
self.arc_mem.try_push(arc.checked_percent()); self.arc_mem.push(arc.percentage());
} else { } else {
self.arc_mem.insert_break(); self.arc_mem.insert_break();
} }
@ -149,7 +149,7 @@ impl TimeSeriesData {
.gpu_mem .gpu_mem
.get_mut(name) .get_mut(name)
.expect("entry must exist as it was created above"); .expect("entry must exist as it was created above");
curr.try_push(new_data.checked_percent()); curr.push(new_data.percentage());
} }
for nv in not_visited { for nv in not_visited {

View File

@ -8,37 +8,31 @@ use tui::{
use crate::{ use crate::{
app::App, app::App,
canvas::{components::pipe_gauge::PipeGauge, drawing_utils::widget_block, Painter}, canvas::{components::pipe_gauge::PipeGauge, drawing_utils::widget_block, Painter},
collection::memory::MemHarvest, collection::memory::MemData,
get_binary_unit_and_denominator, get_binary_unit_and_denominator,
}; };
/// Convert memory info into a string representing a fraction. /// Convert memory info into a string representing a fraction.
#[inline] #[inline]
fn memory_fraction_label(data: &MemHarvest) -> Cow<'static, str> { fn memory_fraction_label(data: &MemData) -> Cow<'static, str> {
if data.total_bytes > 0 { let total_bytes = data.total_bytes.get();
let (unit, denominator) = get_binary_unit_and_denominator(data.total_bytes); let (unit, denominator) = get_binary_unit_and_denominator(total_bytes);
let used = data.used_bytes as f64 / denominator; let used = data.used_bytes as f64 / denominator;
let total = data.total_bytes as f64 / denominator; let total = total_bytes as f64 / denominator;
format!("{used:.1}{unit}/{total:.1}{unit}").into() format!("{used:.1}{unit}/{total:.1}{unit}").into()
} else {
"0.0B/0.0B".into()
}
} }
/// Convert memory info into a string representing a percentage. /// Convert memory info into a string representing a percentage.
#[inline] #[inline]
fn memory_percentage_label(data: &MemHarvest) -> Cow<'static, str> { fn memory_percentage_label(data: &MemData) -> Cow<'static, str> {
if data.total_bytes > 0 { let total_bytes = data.total_bytes.get();
let percentage = data.used_bytes as f64 / data.total_bytes as f64 * 100.0; let percentage = data.used_bytes as f64 / total_bytes as f64 * 100.0;
format!("{percentage:3.0}%").into() format!("{percentage:3.0}%").into()
} else {
" 0%".into()
}
} }
#[inline] #[inline]
fn memory_label(data: &MemHarvest, is_percentage: bool) -> Cow<'static, str> { fn memory_label(data: &MemData, is_percentage: bool) -> Cow<'static, str> {
if is_percentage { if is_percentage {
memory_percentage_label(data) memory_percentage_label(data)
} else { } else {
@ -62,8 +56,21 @@ impl Painter {
let data = app_state.data_store.get_data(); let data = app_state.data_store.get_data();
let ram_percentage = data.ram_harvest.saturating_percentage(); let (ram_percentage, ram_label) = if let Some(ram_harvest) = &data.ram_harvest {
let ram_label = memory_label(&data.ram_harvest, app_state.basic_mode_use_percent); (
ram_harvest.percentage(),
memory_label(ram_harvest, app_state.basic_mode_use_percent),
)
} else {
(
0.0,
if app_state.basic_mode_use_percent {
"0.0B/0.0B".into()
} else {
" 0%".into()
},
)
};
draw_widgets.push( draw_widgets.push(
PipeGauge::default() PipeGauge::default()
@ -75,7 +82,7 @@ impl Painter {
); );
if let Some(swap_harvest) = &data.swap_harvest { if let Some(swap_harvest) = &data.swap_harvest {
let swap_percentage = swap_harvest.saturating_percentage(); let swap_percentage = swap_harvest.percentage();
let swap_label = memory_label(swap_harvest, app_state.basic_mode_use_percent); let swap_label = memory_label(swap_harvest, app_state.basic_mode_use_percent);
draw_widgets.push( draw_widgets.push(
@ -91,7 +98,7 @@ impl Painter {
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
{ {
if let Some(cache_harvest) = &data.cache_harvest { if let Some(cache_harvest) = &data.cache_harvest {
let cache_percentage = cache_harvest.saturating_percentage(); let cache_percentage = cache_harvest.percentage();
let cache_fraction_label = let cache_fraction_label =
memory_label(cache_harvest, app_state.basic_mode_use_percent); memory_label(cache_harvest, app_state.basic_mode_use_percent);
@ -109,7 +116,7 @@ impl Painter {
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
{ {
if let Some(arc_harvest) = &data.arc_harvest { if let Some(arc_harvest) = &data.arc_harvest {
let arc_percentage = arc_harvest.saturating_percentage(); let arc_percentage = arc_harvest.percentage();
let arc_fraction_label = let arc_fraction_label =
memory_label(arc_harvest, app_state.basic_mode_use_percent); memory_label(arc_harvest, app_state.basic_mode_use_percent);
@ -130,7 +137,7 @@ impl Painter {
let mut colour_index = 0; let mut colour_index = 0;
for (_, harvest) in data.gpu_harvest.iter() { for (_, harvest) in data.gpu_harvest.iter() {
let percentage = harvest.saturating_percentage(); let percentage = harvest.percentage();
let label = memory_label(harvest, app_state.basic_mode_use_percent); let label = memory_label(harvest, app_state.basic_mode_use_percent);
let style = { let style = {

View File

@ -14,24 +14,21 @@ use crate::{
drawing_utils::should_hide_x_label, drawing_utils::should_hide_x_label,
Painter, Painter,
}, },
collection::memory::MemHarvest, collection::memory::MemData,
get_binary_unit_and_denominator, get_binary_unit_and_denominator,
}; };
/// Convert memory info into a combined memory label. /// Convert memory info into a combined memory label.
#[inline] #[inline]
fn memory_legend_label(name: &str, data: Option<&MemHarvest>) -> String { fn memory_legend_label(name: &str, data: Option<&MemData>) -> String {
if let Some(data) = data { if let Some(data) = data {
if data.total_bytes > 0 { let total_bytes = data.total_bytes.get();
let percentage = data.used_bytes as f64 / data.total_bytes as f64 * 100.0; let percentage = data.used_bytes as f64 / total_bytes as f64 * 100.0;
let (unit, denominator) = get_binary_unit_and_denominator(data.total_bytes); let (unit, denominator) = get_binary_unit_and_denominator(total_bytes);
let used = data.used_bytes as f64 / denominator; let used = data.used_bytes as f64 / denominator;
let total = data.total_bytes as f64 / denominator; let total = total_bytes as f64 / denominator;
format!("{name}:{percentage:3.0}% {used:.1}{unit}/{total:.1}{unit}") format!("{name}:{percentage:3.0}% {used:.1}{unit}/{total:.1}{unit}")
} else {
format!("{name}: 0% 0.0B/0.0B")
}
} else { } else {
format!("{name}: 0% 0.0B/0.0B") format!("{name}: 0% 0.0B/0.0B")
} }
@ -40,7 +37,7 @@ fn memory_legend_label(name: &str, data: Option<&MemHarvest>) -> String {
/// Get graph data. /// Get graph data.
#[inline] #[inline]
fn graph_data<'a>( fn graph_data<'a>(
out: &mut Vec<GraphData<'a>>, name: &str, last_harvest: Option<&'a MemHarvest>, out: &mut Vec<GraphData<'a>>, name: &str, last_harvest: Option<&'a MemData>,
time: &'a [Instant], values: &'a Values, style: Style, time: &'a [Instant], values: &'a Values, style: Style,
) { ) {
if !values.no_elements() { if !values.no_elements() {
@ -97,10 +94,11 @@ impl Painter {
let timeseries = &data.timeseries_data; let timeseries = &data.timeseries_data;
let time = &timeseries.time; let time = &timeseries.time;
// TODO: Add a "no data" option here/to time graph if there is no entries
graph_data( graph_data(
&mut points, &mut points,
"RAM", "RAM",
Some(&data.ram_harvest), data.ram_harvest.as_ref(),
time, time,
&timeseries.ram, &timeseries.ram,
self.styles.ram_style, self.styles.ram_style,

View File

@ -36,10 +36,10 @@ pub struct Data {
pub collection_time: Instant, pub collection_time: Instant,
pub cpu: Option<cpu::CpuHarvest>, pub cpu: Option<cpu::CpuHarvest>,
pub load_avg: Option<cpu::LoadAvgHarvest>, pub load_avg: Option<cpu::LoadAvgHarvest>,
pub memory: Option<memory::MemHarvest>, pub memory: Option<memory::MemData>,
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub cache: Option<memory::MemHarvest>, pub cache: Option<memory::MemData>,
pub swap: Option<memory::MemHarvest>, pub swap: Option<memory::MemData>,
pub temperature_sensors: Option<Vec<temperature::TempSensorData>>, pub temperature_sensors: Option<Vec<temperature::TempSensorData>>,
pub network: Option<network::NetworkHarvest>, pub network: Option<network::NetworkHarvest>,
pub list_of_processes: Option<Vec<processes::ProcessHarvest>>, pub list_of_processes: Option<Vec<processes::ProcessHarvest>>,
@ -48,9 +48,9 @@ pub struct Data {
#[cfg(feature = "battery")] #[cfg(feature = "battery")]
pub list_of_batteries: Option<Vec<batteries::BatteryData>>, pub list_of_batteries: Option<Vec<batteries::BatteryData>>,
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
pub arc: Option<memory::MemHarvest>, pub arc: Option<memory::MemData>,
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
pub gpu: Option<Vec<(String, memory::MemHarvest)>>, pub gpu: Option<Vec<(String, memory::MemData)>>,
} }
impl Default for Data { impl Default for Data {
@ -345,7 +345,7 @@ impl DataCollector {
#[inline] #[inline]
fn update_gpus(&mut self) { fn update_gpus(&mut self) {
if self.widgets_to_harvest.use_gpu { if self.widgets_to_harvest.use_gpu {
let mut local_gpu: Vec<(String, memory::MemHarvest)> = Vec::new(); let mut local_gpu: Vec<(String, memory::MemData)> = Vec::new();
let mut local_gpu_pids: Vec<HashMap<u32, (u64, u32)>> = Vec::new(); let mut local_gpu_pids: Vec<HashMap<u32, (u64, u32)>> = Vec::new();
let mut local_gpu_total_mem: u64 = 0; let mut local_gpu_total_mem: u64 = 0;
@ -501,7 +501,7 @@ impl DataCollector {
#[inline] #[inline]
fn total_memory(&self) -> u64 { fn total_memory(&self) -> u64 {
if let Some(memory) = &self.data.memory { if let Some(memory) = &self.data.memory {
memory.total_bytes memory.total_bytes.get()
} else { } else {
self.sys.system.total_memory() self.sys.system.total_memory()
} }

View File

@ -2,19 +2,20 @@ mod amdgpu_marketing;
use crate::{ use crate::{
app::{filter::Filter, layout_manager::UsedWidgets}, app::{filter::Filter, layout_manager::UsedWidgets},
collection::{memory::MemHarvest, temperature::TempSensorData}, collection::{memory::MemData, temperature::TempSensorData},
}; };
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use std::{ use std::{
fs, fs::{self, read_to_string},
fs::read_to_string, num::NonZeroU64,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{LazyLock, Mutex}, sync::{LazyLock, Mutex},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
// TODO: May be able to clean up some of these, Option<Vec> for example is a bit redundant.
pub struct AMDGPUData { pub struct AMDGPUData {
pub memory: Option<Vec<(String, MemHarvest)>>, pub memory: Option<Vec<(String, MemData)>>,
pub temperature: Option<Vec<TempSensorData>>, pub temperature: Option<Vec<TempSensorData>>,
pub procs: Option<(u64, Vec<HashMap<u32, (u64, u32)>>)>, pub procs: Option<(u64, Vec<HashMap<u32, (u64, u32)>>)>,
} }
@ -415,13 +416,15 @@ pub fn get_amd_vecs(
if let Some(mem) = get_amd_vram(&device_path) { if let Some(mem) = get_amd_vram(&device_path) {
if widgets_to_harvest.use_mem { if widgets_to_harvest.use_mem {
mem_vec.push(( if let Some(total_bytes) = NonZeroU64::new(mem.total) {
device_name.clone(), mem_vec.push((
MemHarvest { device_name.clone(),
total_bytes: mem.total, MemData {
used_bytes: mem.used, total_bytes,
}, used_bytes: mem.used,
)); },
));
}
} }
total_mem += mem.total total_mem += mem.total

View File

@ -1,10 +1,13 @@
//! Memory data collection. //! Memory data collection.
use std::num::NonZeroU64;
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub(crate) use self::sysinfo::get_cache_usage; pub(crate) use self::sysinfo::get_cache_usage;
pub(crate) use self::sysinfo::{get_ram_usage, get_swap_usage}; pub(crate) use self::sysinfo::{get_ram_usage, get_swap_usage};
pub mod sysinfo; pub mod sysinfo;
// cfg_if::cfg_if! { // cfg_if::cfg_if! {
// if #[cfg(target_os = "windows")] { // if #[cfg(target_os = "windows")] {
// mod windows; // mod windows;
@ -15,36 +18,19 @@ pub mod sysinfo;
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
pub mod arc; pub mod arc;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone)]
pub struct MemHarvest { pub struct MemData {
pub used_bytes: u64, pub used_bytes: u64,
pub total_bytes: u64, pub total_bytes: NonZeroU64,
} }
impl MemHarvest { impl MemData {
/// Return the use percentage. If the total bytes is 0, then this returns `None`. /// Return the use percentage.
#[inline] #[inline]
pub fn checked_percent(&self) -> Option<f64> { pub fn percentage(&self) -> f64 {
let used = self.used_bytes as f64; let used = self.used_bytes as f64;
let total = self.total_bytes as f64; let total = self.total_bytes.get() as f64;
if total == 0.0 { used / total * 100.0
None
} else {
Some(used / total * 100.0)
}
}
/// Return the use percentage. If the total bytes is 0, then this returns 0.0.
#[inline]
pub fn saturating_percentage(&self) -> f64 {
let used = self.used_bytes as f64;
let total = self.total_bytes as f64;
if total == 0.0 {
0.0
} else {
used / total * 100.0
}
} }
} }

View File

@ -1,8 +1,10 @@
use super::MemHarvest; use super::MemData;
/// Return ARC usage. /// Return ARC usage.
#[cfg(feature = "zfs")] #[cfg(feature = "zfs")]
pub(crate) fn get_arc_usage() -> Option<MemHarvest> { pub(crate) fn get_arc_usage() -> Option<MemData> {
use std::num::NonZeroU64;
let (mem_total, mem_used) = { let (mem_total, mem_used) = {
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] { if #[cfg(target_os = "linux")] {
@ -63,12 +65,8 @@ pub(crate) fn get_arc_usage() -> Option<MemHarvest> {
} }
}; };
if mem_total > 0 { NonZeroU64::new(mem_total).map(|total_bytes| MemData {
Some(MemHarvest { total_bytes,
total_bytes: mem_total, used_bytes: mem_used,
used_bytes: mem_used, })
})
} else {
None
}
} }

View File

@ -1,32 +1,27 @@
//! Collecting memory data using sysinfo. //! Collecting memory data using sysinfo.
use std::num::NonZeroU64;
use sysinfo::System; use sysinfo::System;
use crate::collection::memory::MemHarvest; use crate::collection::memory::MemData;
/// Returns RAM usage. #[inline]
pub(crate) fn get_ram_usage(sys: &System) -> Option<MemHarvest> { fn get_usage(used: u64, total: u64) -> Option<MemData> {
let mem_used = sys.used_memory(); NonZeroU64::new(total).map(|total_bytes| MemData {
let mem_total = sys.total_memory(); total_bytes,
used_bytes: used,
Some(MemHarvest {
used_bytes: mem_used,
total_bytes: mem_total,
}) })
} }
/// Returns RAM usage.
pub(crate) fn get_ram_usage(sys: &System) -> Option<MemData> {
get_usage(sys.used_memory(), sys.total_memory())
}
/// Returns SWAP usage. /// Returns SWAP usage.
pub(crate) fn get_swap_usage(sys: &System) -> Option<MemHarvest> { pub(crate) fn get_swap_usage(sys: &System) -> Option<MemData> {
let mem_used = sys.used_swap(); get_usage(sys.used_swap(), sys.total_swap())
let mem_total = sys.total_swap();
if mem_total > 0 {
Some(MemHarvest {
used_bytes: mem_used,
total_bytes: mem_total,
})
} else {
None
}
} }
/// Returns cache usage. sysinfo has no way to do this directly but it should /// Returns cache usage. sysinfo has no way to do this directly but it should
@ -37,12 +32,9 @@ pub(crate) fn get_swap_usage(sys: &System) -> Option<MemHarvest> {
/// Windows, this will always be 0. For more information, see [docs](https://docs.rs/sysinfo/latest/sysinfo/struct.System.html#method.available_memory) /// Windows, this will always be 0. For more information, see [docs](https://docs.rs/sysinfo/latest/sysinfo/struct.System.html#method.available_memory)
/// and [memory explanation](https://askubuntu.com/questions/867068/what-is-available-memory-while-using-free-command) /// and [memory explanation](https://askubuntu.com/questions/867068/what-is-available-memory-while-using-free-command)
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub(crate) fn get_cache_usage(sys: &System) -> Option<MemHarvest> { pub(crate) fn get_cache_usage(sys: &System) -> Option<MemData> {
let mem_used = sys.available_memory().saturating_sub(sys.free_memory()); let mem_used = sys.available_memory().saturating_sub(sys.free_memory());
let mem_total = sys.total_memory(); let mem_total = sys.total_memory();
Some(MemHarvest { get_usage(mem_used, mem_total)
total_bytes: mem_total,
used_bytes: mem_used,
})
} }

View File

@ -1,4 +1,4 @@
use std::sync::OnceLock; use std::{num::NonZeroU64, sync::OnceLock};
use hashbrown::HashMap; use hashbrown::HashMap;
use nvml_wrapper::{ use nvml_wrapper::{
@ -7,13 +7,13 @@ use nvml_wrapper::{
use crate::{ use crate::{
app::{filter::Filter, layout_manager::UsedWidgets}, app::{filter::Filter, layout_manager::UsedWidgets},
collection::{memory::MemHarvest, temperature::TempSensorData}, collection::{memory::MemData, temperature::TempSensorData},
}; };
pub static NVML_DATA: OnceLock<Result<Nvml, NvmlError>> = OnceLock::new(); pub static NVML_DATA: OnceLock<Result<Nvml, NvmlError>> = OnceLock::new();
pub struct GpusData { pub struct GpusData {
pub memory: Option<Vec<(String, MemHarvest)>>, pub memory: Option<Vec<(String, MemData)>>,
pub temperature: Option<Vec<TempSensorData>>, pub temperature: Option<Vec<TempSensorData>>,
pub procs: Option<(u64, Vec<HashMap<u32, (u64, u32)>>)>, pub procs: Option<(u64, Vec<HashMap<u32, (u64, u32)>>)>,
} }
@ -58,13 +58,15 @@ pub fn get_nvidia_vecs(
if let Ok(name) = device.name() { if let Ok(name) = device.name() {
if widgets_to_harvest.use_mem { if widgets_to_harvest.use_mem {
if let Ok(mem) = device.memory_info() { if let Ok(mem) = device.memory_info() {
mem_vec.push(( if let Some(total_bytes) = NonZeroU64::new(mem.total) {
name.clone(), mem_vec.push((
MemHarvest { name.clone(),
total_bytes: mem.total, MemData {
used_bytes: mem.used, total_bytes,
}, used_bytes: mem.used,
)); },
));
}
} }
} }