From 9ad8b7ec9f257455624f3ccbbfca77ef657dce41 Mon Sep 17 00:00:00 2001 From: nokyan Date: Tue, 30 Jul 2024 23:22:12 +0200 Subject: [PATCH] Protect against NaN and infinities better and in more places --- src/ui/pages/cpu.rs | 7 +++-- src/ui/pages/gpu.rs | 4 +-- src/ui/pages/memory.rs | 4 +-- src/utils/app.rs | 8 ++--- src/utils/mod.rs | 68 +++++++++++++++++++++++++++++++++++------- src/utils/process.rs | 11 +++---- 6 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/ui/pages/cpu.rs b/src/ui/pages/cpu.rs index 62c81d8b..6f9d19e9 100644 --- a/src/ui/pages/cpu.rs +++ b/src/ui/pages/cpu.rs @@ -8,7 +8,7 @@ use crate::ui::widgets::graph_box::ResGraphBox; use crate::utils::cpu::{CpuData, CpuInfo}; use crate::utils::settings::SETTINGS; use crate::utils::units::{convert_frequency, convert_temperature}; -use crate::utils::{cpu, NaNDefault, NUM_CPUS}; +use crate::utils::{cpu, FiniteOr, NUM_CPUS}; mod imp { use std::cell::{Cell, RefCell}; @@ -347,7 +347,8 @@ impl ResCPU { .saturating_sub(imp.old_total_usage.get().1); let work_total_time = sum_total_delta.saturating_sub(idle_total_delta); - let total_fraction = ((work_total_time as f64) / (sum_total_delta as f64)).nan_default(0.0); + let total_fraction = + ((work_total_time as f64) / (sum_total_delta as f64)).finite_or_default(); imp.total_cpu.graph().push_data_point(total_fraction); @@ -375,7 +376,7 @@ impl ResCPU { let work_thread_time = sum_thread_delta.saturating_sub(idle_thread_delta); let curr_threadbox = &imp.thread_graphs.borrow()[i]; let thread_fraction = - ((work_thread_time as f64) / (sum_thread_delta as f64)).nan_default(0.0); + ((work_thread_time as f64) / (sum_thread_delta as f64)).finite_or_default(); curr_threadbox.graph().push_data_point(thread_fraction); curr_threadbox.set_subtitle(&format!("{} %", (thread_fraction * 100.0).round())); diff --git a/src/ui/pages/gpu.rs b/src/ui/pages/gpu.rs index 85621ecb..afb4e595 100644 --- a/src/ui/pages/gpu.rs +++ b/src/ui/pages/gpu.rs @@ -5,7 +5,7 @@ use crate::config::PROFILE; use crate::i18n::{i18n, i18n_f}; use crate::utils::gpu::{Gpu, GpuData}; use crate::utils::units::{convert_frequency, convert_power, convert_storage, convert_temperature}; -use crate::utils::{pci, NaNDefault}; +use crate::utils::{pci, FiniteOr}; mod imp { use std::cell::{Cell, RefCell}; @@ -361,7 +361,7 @@ impl ResGPU { let used_vram_fraction = if let (Some(total_vram), Some(used_vram)) = (total_vram, used_vram) { - Some((*used_vram as f64 / *total_vram as f64).nan_default(0.0)) + Some((*used_vram as f64 / *total_vram as f64).finite_or_default()) } else { None }; diff --git a/src/ui/pages/memory.rs b/src/ui/pages/memory.rs index 13c1b5d2..0749a186 100644 --- a/src/ui/pages/memory.rs +++ b/src/ui/pages/memory.rs @@ -5,7 +5,7 @@ use crate::config::PROFILE; use crate::i18n::{i18n, i18n_f}; use crate::utils::memory::{self, MemoryData, MemoryDevice}; use crate::utils::units::convert_storage; -use crate::utils::NaNDefault; +use crate::utils::FiniteOr; mod imp { use std::cell::{Cell, RefCell}; @@ -331,7 +331,7 @@ impl ResMemory { let used_swap = total_swap.saturating_sub(free_swap); let memory_fraction = used_mem as f64 / total_mem as f64; - let swap_fraction = (used_swap as f64 / total_swap as f64).nan_default(0.0); + let swap_fraction = (used_swap as f64 / total_swap as f64).finite_or_default(); let formatted_used_mem = convert_storage(used_mem as f64, false); let formatted_total_mem = convert_storage(total_mem as f64, false); diff --git a/src/utils/app.rs b/src/utils/app.rs index 337a8d14..65d1d62e 100644 --- a/src/utils/app.rs +++ b/src/utils/app.rs @@ -19,7 +19,7 @@ use crate::i18n::i18n; use super::{ boot_time, process::{Process, ProcessAction, ProcessItem}, - NaNDefault, TICK_RATE, + FiniteOr, TICK_RATE, }; // This contains executable names that are blacklisted from being recognized as applications @@ -479,7 +479,7 @@ impl AppsContext { } else { ((new.gfx.saturating_sub(old.gfx) as f32) / (timestamp.saturating_sub(timestamp_last) as f32)) - .nan_default(0.0) + .finite_or_default() / 1_000_000.0 } }) @@ -517,7 +517,7 @@ impl AppsContext { } else { ((new.enc.saturating_sub(old.enc) as f32) / (timestamp.saturating_sub(timestamp_last) as f32)) - .nan_default(0.0) + .finite_or_default() / 1_000_000.0 } }) @@ -555,7 +555,7 @@ impl AppsContext { } else { ((new.dec.saturating_sub(old.dec) as f32) / (timestamp.saturating_sub(timestamp_last) as f32)) - .nan_default(0.0) + .finite_or_default() / 1_000_000.0 } }) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 924b1079..204da785 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -83,27 +83,73 @@ pub fn boot_time() -> Result { }) } -pub trait NaNDefault { - /// Returns the given `default` value if the variable is NaN, +pub trait FiniteOr { + /// Returns the given `x` value if the variable is NaN or infinite, /// and returns itself otherwise. #[must_use] - fn nan_default(&self, default: Self) -> Self; + fn finite_or(&self, x: Self) -> Self; + + /// Returns itself is the variable is finite (i.e. neither NaN nor infinite), otherwise returns its default + fn finite_or_default(&self) -> Self; + + /// Returns itself is the variable is finite (i.e. neither NaN nor infinite), otherwise runs `f` + fn finite_or_else Self>(&self, f: F) -> Self + where + Self: Sized; } -impl NaNDefault for f64 { - fn nan_default(&self, default: Self) -> Self { - if self.is_nan() { - default +impl FiniteOr for f64 { + fn finite_or(&self, x: Self) -> Self { + if !self.is_finite() { + x + } else { + *self + } + } + + fn finite_or_default(&self) -> Self { + if !self.is_finite() { + Self::default() + } else { + *self + } + } + + fn finite_or_else Self>(&self, f: F) -> Self + where + Self: Sized, + { + if !self.is_finite() { + f(*self) } else { *self } } } -impl NaNDefault for f32 { - fn nan_default(&self, default: Self) -> Self { - if self.is_nan() { - default +impl FiniteOr for f32 { + fn finite_or(&self, x: Self) -> Self { + if !self.is_finite() { + x + } else { + *self + } + } + + fn finite_or_default(&self) -> Self { + if !self.is_finite() { + Self::default() + } else { + *self + } + } + + fn finite_or_else Self>(&self, f: F) -> Self + where + Self: Sized, + { + if !self.is_finite() { + f(*self) } else { *self } diff --git a/src/utils/process.rs b/src/utils/process.rs index 58fe18fc..619f3406 100644 --- a/src/utils/process.rs +++ b/src/utils/process.rs @@ -14,7 +14,7 @@ use gtk::gio::{Icon, ThemedIcon}; use crate::config; -use super::{NaNDefault, FLATPAK_APP_PATH, FLATPAK_SPAWN, IS_FLATPAK, NUM_CPUS, TICK_RATE}; +use super::{FiniteOr, FLATPAK_APP_PATH, FLATPAK_SPAWN, IS_FLATPAK, NUM_CPUS, TICK_RATE}; static OTHER_PROCESS: LazyLock> = LazyLock::new(|| { let proxy_path = if *IS_FLATPAK { @@ -289,7 +289,8 @@ impl Process { * 1000.0; let delta_time = self.data.timestamp.saturating_sub(self.timestamp_last); - delta_cpu_time / (delta_time * *TICK_RATE as u64 * *NUM_CPUS as u64) as f32 + (delta_cpu_time / (delta_time * *TICK_RATE as u64 * *NUM_CPUS as u64) as f32) + .finite_or_default() } } @@ -339,7 +340,7 @@ impl Process { } else { ((usage.gfx.saturating_sub(old_usage.gfx) as f32) / (self.data.timestamp.saturating_sub(self.timestamp_last) as f32) - .nan_default(0.0)) + .finite_or_default()) / 1_000_000.0 }; @@ -364,7 +365,7 @@ impl Process { } else { ((usage.enc.saturating_sub(old_usage.enc) as f32) / (self.data.timestamp.saturating_sub(self.timestamp_last) as f32) - .nan_default(0.0)) + .finite_or_default()) / 1_000_000.0 }; @@ -389,7 +390,7 @@ impl Process { } else { ((usage.dec.saturating_sub(old_usage.dec) as f32) / (self.data.timestamp.saturating_sub(self.timestamp_last) as f32) - .nan_default(0.0)) + .finite_or_default()) / 1_000_000.0 };