mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-24 21:23:08 +00:00
other: show N/A for Nvidia GPUs if we detect one but can't get temps (#1557)
* other: show N/A for Nvidia GPUs if we detect one but can't get the temperature * refactor: driveby refactor of filter system and code for temp * missed one
This commit is contained in:
parent
c65121c43a
commit
d9d9e1df9f
8 changed files with 64 additions and 62 deletions
|
@ -1,21 +1,32 @@
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
/// Filters used by widgets to filter out certain entries.
|
/// Filters used by widgets to filter out certain entries.
|
||||||
/// TODO: Move this out maybe?
|
/// TODO: Move this out maybe?
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Filter {
|
pub struct Filter {
|
||||||
/// Whether the filter _accepts_ all entries that match `list`,
|
/// Whether the filter _accepts_ all entries that match `list`,
|
||||||
/// or _denies_ any entries that match it.
|
/// or _denies_ any entries that match it.
|
||||||
pub is_list_ignored: bool, // TODO: Maybe change to "ignore_matches"?
|
is_list_ignored: bool, // TODO: Maybe change to "ignore_matches"?
|
||||||
|
|
||||||
/// The list of regexes to match against. Whether it goes through
|
/// The list of regexes to match against. Whether it goes through
|
||||||
/// the filter or not depends on `is_list_ignored`.
|
/// the filter or not depends on `is_list_ignored`.
|
||||||
pub list: Vec<regex::Regex>,
|
list: Vec<Regex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filter {
|
impl Filter {
|
||||||
|
/// Create a new filter.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn new(ignore_matches: bool, list: Vec<Regex>) -> Self {
|
||||||
|
Self {
|
||||||
|
is_list_ignored: ignore_matches,
|
||||||
|
list,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the filter should keep the entry or reject it.
|
/// Whether the filter should keep the entry or reject it.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn keep_entry(&self, value: &str) -> bool {
|
pub(crate) fn should_keep(&self, entry: &str) -> bool {
|
||||||
if self.has_match(value) {
|
if self.has_match(entry) {
|
||||||
// If a match is found, then if we wanted to ignore if we match, return false.
|
// If a match is found, then if we wanted to ignore if we match, return false.
|
||||||
// If we want to keep if we match, return true. Thus, return the
|
// If we want to keep if we match, return true. Thus, return the
|
||||||
// inverse of `is_list_ignored`.
|
// inverse of `is_list_ignored`.
|
||||||
|
@ -30,6 +41,21 @@ impl Filter {
|
||||||
pub(crate) fn has_match(&self, value: &str) -> bool {
|
pub(crate) fn has_match(&self, value: &str) -> bool {
|
||||||
self.list.iter().any(|regex| regex.is_match(value))
|
self.list.iter().any(|regex| regex.is_match(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether entries matching the list should be ignored or kept.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn ignore_matches(&self) -> bool {
|
||||||
|
self.is_list_ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check a filter if it exists, otherwise accept if it is [`None`].
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn optional_should_keep(filter: &Option<Self>, entry: &str) -> bool {
|
||||||
|
filter
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.should_keep(entry))
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -56,7 +82,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| ignore_true.keep_entry(r))
|
.filter(|r| ignore_true.should_keep(r))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec!["wifi_0", "amd gpu"]
|
vec!["wifi_0", "amd gpu"]
|
||||||
);
|
);
|
||||||
|
@ -69,7 +95,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| ignore_false.keep_entry(r))
|
.filter(|r| ignore_false.should_keep(r))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec!["CPU socket temperature", "motherboard temperature"]
|
vec!["CPU socket temperature", "motherboard temperature"]
|
||||||
);
|
);
|
||||||
|
@ -85,7 +111,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| multi_true.keep_entry(r))
|
.filter(|r| multi_true.should_keep(r))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec!["wifi_0", "amd gpu"]
|
vec!["wifi_0", "amd gpu"]
|
||||||
);
|
);
|
||||||
|
@ -101,7 +127,7 @@ mod test {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
results
|
results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|r| multi_false.keep_entry(r))
|
.filter(|r| multi_false.should_keep(r))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
vec!["CPU socket temperature", "motherboard temperature"]
|
vec!["CPU socket temperature", "motherboard temperature"]
|
||||||
);
|
);
|
||||||
|
|
|
@ -103,26 +103,26 @@ pub fn keep_disk_entry(
|
||||||
disk_name: &str, mount_point: &str, disk_filter: &Option<Filter>, mount_filter: &Option<Filter>,
|
disk_name: &str, mount_point: &str, disk_filter: &Option<Filter>, mount_filter: &Option<Filter>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match (disk_filter, mount_filter) {
|
match (disk_filter, mount_filter) {
|
||||||
(Some(d), Some(m)) => match (d.is_list_ignored, m.is_list_ignored) {
|
(Some(d), Some(m)) => match (d.ignore_matches(), m.ignore_matches()) {
|
||||||
(true, true) => !(d.has_match(disk_name) || m.has_match(mount_point)),
|
(true, true) => !(d.has_match(disk_name) || m.has_match(mount_point)),
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
if m.has_match(mount_point) {
|
if m.has_match(mount_point) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
d.keep_entry(disk_name)
|
d.should_keep(disk_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
if d.has_match(disk_name) {
|
if d.has_match(disk_name) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
m.keep_entry(mount_point)
|
m.should_keep(mount_point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(false, false) => d.has_match(disk_name) || m.has_match(mount_point),
|
(false, false) => d.has_match(disk_name) || m.has_match(mount_point),
|
||||||
},
|
},
|
||||||
(Some(d), None) => d.keep_entry(disk_name),
|
(Some(d), None) => d.should_keep(disk_name),
|
||||||
(None, Some(m)) => m.keep_entry(mount_point),
|
(None, Some(m)) => m.should_keep(mount_point),
|
||||||
(None, None) => true,
|
(None, None) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,25 +158,10 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_keeping_disk_entry() {
|
fn test_keeping_disk_entry() {
|
||||||
let disk_ignore = Some(Filter {
|
let disk_ignore = Some(Filter::new(true, vec![Regex::new("nvme").unwrap()]));
|
||||||
is_list_ignored: true,
|
let disk_keep = Some(Filter::new(false, vec![Regex::new("nvme").unwrap()]));
|
||||||
list: vec![Regex::new("nvme").unwrap()],
|
let mount_ignore = Some(Filter::new(true, vec![Regex::new("boot").unwrap()]));
|
||||||
});
|
let mount_keep = Some(Filter::new(false, vec![Regex::new("boot").unwrap()]));
|
||||||
|
|
||||||
let disk_keep = Some(Filter {
|
|
||||||
is_list_ignored: false,
|
|
||||||
list: vec![Regex::new("nvme").unwrap()],
|
|
||||||
});
|
|
||||||
|
|
||||||
let mount_ignore = Some(Filter {
|
|
||||||
is_list_ignored: true,
|
|
||||||
list: vec![Regex::new("boot").unwrap()],
|
|
||||||
});
|
|
||||||
|
|
||||||
let mount_keep = Some(Filter {
|
|
||||||
is_list_ignored: false,
|
|
||||||
list: vec![Regex::new("boot").unwrap()],
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(run_filter(&None, &None), vec![0, 1, 2, 3, 4]);
|
assert_eq!(run_filter(&None, &None), vec![0, 1, 2, 3, 4]);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub fn get_network_data(
|
||||||
|
|
||||||
for (name, network) in networks {
|
for (name, network) in networks {
|
||||||
let to_keep = if let Some(filter) = filter {
|
let to_keep = if let Some(filter) = filter {
|
||||||
filter.keep_entry(name)
|
filter.should_keep(name)
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
app::{filter::Filter, layout_manager::UsedWidgets},
|
app::{filter::Filter, layout_manager::UsedWidgets},
|
||||||
data_collection::{
|
data_collection::{
|
||||||
memory::MemHarvest,
|
memory::MemHarvest,
|
||||||
temperature::{is_temp_filtered, TempHarvest, TemperatureType},
|
temperature::{TempHarvest, TemperatureType},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ pub fn get_nvidia_vecs(
|
||||||
let mut mem_vec = Vec::with_capacity(num_gpu as usize);
|
let mut mem_vec = Vec::with_capacity(num_gpu as usize);
|
||||||
let mut proc_vec = Vec::with_capacity(num_gpu as usize);
|
let mut proc_vec = Vec::with_capacity(num_gpu as usize);
|
||||||
let mut total_mem = 0;
|
let mut total_mem = 0;
|
||||||
|
|
||||||
for i in 0..num_gpu {
|
for i in 0..num_gpu {
|
||||||
if let Ok(device) = nvml.device_by_index(i) {
|
if let Ok(device) = nvml.device_by_index(i) {
|
||||||
if let Ok(name) = device.name() {
|
if let Ok(name) = device.name() {
|
||||||
|
@ -51,17 +52,26 @@ pub fn get_nvidia_vecs(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if widgets_to_harvest.use_temp && is_temp_filtered(filter, &name) {
|
|
||||||
|
if widgets_to_harvest.use_temp
|
||||||
|
&& Filter::optional_should_keep(filter, &name)
|
||||||
|
{
|
||||||
if let Ok(temperature) = device.temperature(TemperatureSensor::Gpu) {
|
if let Ok(temperature) = device.temperature(TemperatureSensor::Gpu) {
|
||||||
let temperature = temp_type.convert_temp_unit(temperature as f32);
|
let temperature = temp_type.convert_temp_unit(temperature as f32);
|
||||||
|
|
||||||
temp_vec.push(TempHarvest {
|
temp_vec.push(TempHarvest {
|
||||||
name: name.clone(),
|
name,
|
||||||
temperature: Some(temperature),
|
temperature: Some(temperature),
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
temp_vec.push(TempHarvest {
|
||||||
|
name,
|
||||||
|
temperature: None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if widgets_to_harvest.use_proc {
|
if widgets_to_harvest.use_proc {
|
||||||
let mut procs = HashMap::new();
|
let mut procs = HashMap::new();
|
||||||
|
|
||||||
|
@ -130,6 +140,7 @@ pub fn get_nvidia_vecs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(GpusData {
|
Some(GpusData {
|
||||||
memory: if !mem_vec.is_empty() {
|
memory: if !mem_vec.is_empty() {
|
||||||
Some(mem_vec)
|
Some(mem_vec)
|
||||||
|
|
|
@ -15,8 +15,6 @@ cfg_if::cfg_if! {
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::app::filter::Filter;
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct TempHarvest {
|
pub struct TempHarvest {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -66,21 +64,6 @@ impl TemperatureType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_temp_filtered(filter: &Option<Filter>, text: &str) -> bool {
|
|
||||||
if let Some(filter) = filter {
|
|
||||||
let mut ret = filter.is_list_ignored;
|
|
||||||
for r in &filter.list {
|
|
||||||
if r.is_match(text) {
|
|
||||||
ret = !filter.is_list_ignored;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::data_collection::temperature::TemperatureType;
|
use crate::data_collection::temperature::TemperatureType;
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
|
||||||
use super::{is_temp_filtered, TempHarvest, TemperatureType};
|
use super::{TempHarvest, TemperatureType};
|
||||||
use crate::app::filter::Filter;
|
use crate::app::filter::Filter;
|
||||||
|
|
||||||
const EMPTY_NAME: &str = "Unknown";
|
const EMPTY_NAME: &str = "Unknown";
|
||||||
|
@ -327,7 +327,7 @@ fn hwmon_temperatures(temp_type: &TemperatureType, filter: &Option<Filter>) -> H
|
||||||
|
|
||||||
// TODO: It's possible we may want to move the filter check further up to avoid
|
// TODO: It's possible we may want to move the filter check further up to avoid
|
||||||
// probing hwmon if not needed?
|
// probing hwmon if not needed?
|
||||||
if is_temp_filtered(filter, &name) {
|
if Filter::optional_should_keep(filter, &name) {
|
||||||
if let Ok(temp_celsius) = parse_temp(&temp_path) {
|
if let Ok(temp_celsius) = parse_temp(&temp_path) {
|
||||||
temperatures.push(TempHarvest {
|
temperatures.push(TempHarvest {
|
||||||
name,
|
name,
|
||||||
|
@ -377,7 +377,7 @@ fn add_thermal_zone_temperatures(
|
||||||
name
|
name
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_temp_filtered(filter, &name) {
|
if Filter::optional_should_keep(filter, &name) {
|
||||||
let temp_path = file_path.join("temp");
|
let temp_path = file_path.join("temp");
|
||||||
if let Ok(temp_celsius) = parse_temp(&temp_path) {
|
if let Ok(temp_celsius) = parse_temp(&temp_path) {
|
||||||
let name = counted_name(&mut seen_names, name);
|
let name = counted_name(&mut seen_names, name);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use super::{is_temp_filtered, TempHarvest, TemperatureType};
|
use super::{TempHarvest, TemperatureType};
|
||||||
use crate::app::filter::Filter;
|
use crate::app::filter::Filter;
|
||||||
|
|
||||||
pub fn get_temperature_data(
|
pub fn get_temperature_data(
|
||||||
|
@ -13,7 +13,7 @@ pub fn get_temperature_data(
|
||||||
for component in components {
|
for component in components {
|
||||||
let name = component.label().to_string();
|
let name = component.label().to_string();
|
||||||
|
|
||||||
if is_temp_filtered(filter, &name) {
|
if Filter::optional_should_keep(filter, &name) {
|
||||||
temperature_vec.push(TempHarvest {
|
temperature_vec.push(TempHarvest {
|
||||||
name,
|
name,
|
||||||
temperature: Some(temp_type.convert_temp_unit(component.temperature())),
|
temperature: Some(temp_type.convert_temp_unit(component.temperature())),
|
||||||
|
|
|
@ -868,10 +868,7 @@ fn get_ignore_list(ignore_list: &Option<IgnoreList>) -> OptionResult<Option<Filt
|
||||||
|
|
||||||
let list = list.map_err(|err| OptionError::config(err.to_string()))?;
|
let list = list.map_err(|err| OptionError::config(err.to_string()))?;
|
||||||
|
|
||||||
Ok(Some(Filter {
|
Ok(Some(Filter::new(ignore_list.is_list_ignored, list)))
|
||||||
list,
|
|
||||||
is_list_ignored: ignore_list.is_list_ignored,
|
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue