other: if in a non-D0 state, short-circuit further logic (#1355)

* other: if in a non-D0 state, short-circuit further logic

* cleanup

* add back an empty name and value

* fix for macos/windows

* some testing things
This commit is contained in:
Clement Tsang 2023-12-20 01:36:08 -05:00 committed by GitHub
parent 004c83728d
commit a67da93c5f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 73 deletions

View file

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Bug Fixes
- [#1314](https://github.com/ClementTsang/bottom/pull/1314): Fix fat32 mounts not showing up in macOS.
- [#1355](https://github.com/ClementTsang/bottom/pull/1355): Reduce chances of non-D0 devices waking up due to temperature checks on Linux.
## [0.9.6] - 2023-08-26

View file

@ -54,7 +54,7 @@ pub fn get_nvidia_vecs(
temp_vec.push(TempHarvest {
name: name.clone(),
temperature,
temperature: Some(temperature),
});
}
}

View file

@ -18,7 +18,7 @@ use crate::app::Filter;
#[derive(Default, Debug, Clone)]
pub struct TempHarvest {
pub name: String,
pub temperature: f32,
pub temperature: Option<f32>,
}
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]

View file

@ -9,7 +9,7 @@ use anyhow::Result;
use hashbrown::{HashMap, HashSet};
use super::{is_temp_filtered, TempHarvest, TemperatureType};
use crate::app::Filter;
use crate::{app::Filter, utils::error::BottomError};
const EMPTY_NAME: &str = "Unknown";
@ -24,7 +24,7 @@ fn read_temp(path: &Path) -> Result<f32> {
Ok(fs::read_to_string(path)?
.trim_end()
.parse::<f32>()
.map_err(|e| crate::utils::error::BottomError::ConversionError(e.to_string()))?
.map_err(|e| BottomError::ConversionError(e.to_string()))?
/ 1_000.0)
}
@ -131,8 +131,8 @@ fn finalize_name(
None => label,
},
(Some(name), None) => name,
(None, None) => match &fallback_sensor_name {
Some(sensor_name) => sensor_name.clone(),
(None, None) => match fallback_sensor_name {
Some(sensor_name) => sensor_name.to_owned(),
None => EMPTY_NAME.to_string(),
},
};
@ -140,6 +140,31 @@ fn finalize_name(
counted_name(seen_names, candidate_name)
}
/// Whether the temperature should *actually* be read during enumeration.
/// Will return false if the state is not D0/unknown, or if it does not support `device/power_state`.
#[inline]
fn is_device_awake(path: &Path) -> bool {
// Whether the temperature should *actually* be read during enumeration.
// Set to false if the device is in ACPI D3cold.
// Documented at https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-power_state
let device = path.join("device");
let power_state = device.join("power_state");
if power_state.exists() {
if let Ok(state) = fs::read_to_string(power_state) {
let state = state.trim();
// The zenpower3 kernel module (incorrectly?) reports "unknown", causing this check
// to fail and temperatures to appear as zero instead of having the file not exist.
//
// Their self-hosted git instance has disabled sign up, so this bug cant be reported either.
state == "D0" || state == "unknown"
} else {
true
}
} else {
true
}
}
/// Get temperature sensors from the linux sysfs interface `/sys/class/hwmon` and
/// `/sys/devices/platform/coretemp.*`. It returns all found temperature sensors, and the number
/// of checked hwmon directories (not coretemp directories).
@ -178,29 +203,15 @@ fn hwmon_temperatures(temp_type: &TemperatureType, filter: &Option<Filter>) -> H
for file_path in dirs {
let sensor_name = read_to_string_lossy(file_path.join("name"));
// Whether the temperature should *actually* be read during enumeration.
// Set to false if the device is in ACPI D3cold.
//
// If it is false, then the temperature will be set to 0.0 later down the line.
let should_read_temp = {
// Documented at https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-power_state
let device = file_path.join("device");
let power_state = device.join("power_state");
if power_state.exists() {
if let Ok(state) = fs::read_to_string(power_state) {
let state = state.trim();
// The zenpower3 kernel module (incorrectly?) reports "unknown", causing this check
// to fail and temperatures to appear as zero instead of having the file not exist.
//
// Their self-hosted git instance has disabled sign up, so this bug cant be reported either.
state == "D0" || state == "unknown"
} else {
true
}
} else {
true
if !is_device_awake(&file_path) {
if let Some(sensor_name) = sensor_name {
temperatures.push(TempHarvest {
name: sensor_name,
temperature: None,
});
}
};
continue;
}
if let Ok(dir_entries) = file_path.read_dir() {
// Enumerate the devices temperature sensors
@ -272,19 +283,15 @@ fn hwmon_temperatures(temp_type: &TemperatureType, filter: &Option<Filter>) -> H
let name = finalize_name(hwmon_name, sensor_label, &sensor_name, &mut seen_names);
if is_temp_filtered(filter, &name) {
let temp_celsius = if should_read_temp {
if let Ok(temp) = read_temp(&temp_path) {
temp
} else {
continue;
}
let temp_celsius = if let Ok(temp) = read_temp(&temp_path) {
temp
} else {
0.0
continue;
};
temperatures.push(TempHarvest {
name,
temperature: temp_type.convert_temp_unit(temp_celsius),
temperature: Some(temp_type.convert_temp_unit(temp_celsius)),
});
}
}
@ -329,7 +336,7 @@ fn add_thermal_zone_temperatures(
temperatures.push(TempHarvest {
name,
temperature: temp_type.convert_temp_unit(temp_celsius),
temperature: Some(temp_type.convert_temp_unit(temp_celsius)),
});
}
}

View file

@ -19,7 +19,7 @@ pub fn get_temperature_data(
if is_temp_filtered(filter, &name) {
temperature_vec.push(TempHarvest {
name,
temperature: temp_type.convert_temp_unit(component.temperature()),
temperature: Some(temp_type.convert_temp_unit(component.temperature())),
});
}
}
@ -36,11 +36,11 @@ pub fn get_temperature_data(
if let Some(temp) = temp.as_temperature() {
temperature_vec.push(TempHarvest {
name,
temperature: match temp_type {
temperature: Some(match temp_type {
TemperatureType::Celsius => temp.celsius(),
TemperatureType::Kelvin => temp.kelvin(),
TemperatureType::Fahrenheit => temp.fahrenheit(),
},
}),
});
}
}

View file

@ -21,10 +21,14 @@ use crossterm::{
use tui::{backend::CrosstermBackend, Terminal};
use bottom::{
args,
canvas::{self, canvas_styling::CanvasStyling},
check_if_terminal, cleanup_terminal, create_collection_thread, create_input_thread,
create_or_get_config,
data_conversion::*,
handle_key_event_or_break, handle_mouse_event,
options::*,
*,
panic_hook, read_config, try_drawing, update_data, BottomEvent,
};
// Used for heap allocation debugging purposes.
@ -38,7 +42,10 @@ fn main() -> Result<()> {
#[cfg(feature = "logging")]
{
if let Err(err) = init_logger(log::LevelFilter::Debug, std::ffi::OsStr::new("debug.log")) {
if let Err(err) = bottom::init_logger(
log::LevelFilter::Debug,
Some(std::ffi::OsStr::new("debug.log")),
) {
println!("Issue initializing logger: {err}");
}
}

View file

@ -132,7 +132,7 @@ impl ConvertedData {
data.temp_harvest.iter().for_each(|temp_harvest| {
self.temp_data.push(TempWidgetData {
sensor: KString::from_ref(&temp_harvest.name),
temperature_value: temp_harvest.temperature.ceil() as u64,
temperature_value: temp_harvest.temperature.map(|temp| temp.ceil() as u64),
temperature_type,
});
});

View file

@ -20,9 +20,9 @@ pub static OFFSET: once_cell::sync::Lazy<time::UtcOffset> = once_cell::sync::Laz
#[cfg(feature = "logging")]
pub fn init_logger(
min_level: log::LevelFilter, debug_file_name: &std::ffi::OsStr,
min_level: log::LevelFilter, debug_file_name: Option<&std::ffi::OsStr>,
) -> Result<(), fern::InitError> {
fern::Dispatch::new()
let dispatch = fern::Dispatch::new()
.format(|out, message, record| {
let offset_time = {
let utc = time::OffsetDateTime::now_utc();
@ -43,25 +43,19 @@ pub fn init_logger(
message
))
})
.level(min_level)
.chain(fern::log_file(debug_file_name)?)
.apply()?;
.level(min_level);
if let Some(debug_file_name) = debug_file_name {
dispatch.chain(fern::log_file(debug_file_name)?).apply()?;
} else {
dispatch.chain(std::io::stdout()).apply()?;
}
Ok(())
}
#[macro_export]
macro_rules! c_debug {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
log::debug!($($x)*)
}
};
}
#[macro_export]
macro_rules! c_error {
macro_rules! error {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
@ -71,7 +65,17 @@ macro_rules! c_error {
}
#[macro_export]
macro_rules! c_info {
macro_rules! warn {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
log::warn!($($x)*)
}
};
}
#[macro_export]
macro_rules! info {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
@ -81,17 +85,17 @@ macro_rules! c_info {
}
#[macro_export]
macro_rules! c_log {
macro_rules! debug {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
log::log!($($x)*)
log::debug!($($x)*)
}
};
}
#[macro_export]
macro_rules! c_trace {
macro_rules! trace {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
@ -101,11 +105,34 @@ macro_rules! c_trace {
}
#[macro_export]
macro_rules! c_warn {
macro_rules! log {
($($x:tt)*) => {
#[cfg(feature = "logging")]
{
log::warn!($($x)*)
log::log!(log::Level::Trace, $($x)*)
}
};
($level:expr, $($x:tt)*) => {
#[cfg(feature = "logging")]
{
log::log!($level, $($x)*)
}
};
}
#[cfg(test)]
mod test {
#[cfg(feature = "logging")]
#[test]
fn test_logging_macros() {
super::init_logger(log::LevelFilter::Trace, None)
.expect("initializing the logger should succeed");
error!("This is an error.");
warn!("This is a warning.");
info!("This is an info.");
debug!("This is a debug.");
info!("This is a trace.");
}
}

View file

@ -17,7 +17,7 @@ use crate::{
#[derive(Clone, Debug)]
pub struct TempWidgetData {
pub sensor: KString,
pub temperature_value: u64,
pub temperature_value: Option<u64>,
pub temperature_type: TemperatureType,
}
@ -37,13 +37,17 @@ impl ColumnHeader for TempWidgetColumn {
impl TempWidgetData {
pub fn temperature(&self) -> KString {
let temp_val = self.temperature_value.to_string();
let temp_type = match self.temperature_type {
TemperatureType::Celsius => "°C",
TemperatureType::Kelvin => "K",
TemperatureType::Fahrenheit => "°F",
};
concat_string!(temp_val, temp_type).into()
match self.temperature_value {
Some(temp_val) => {
let temp_type = match self.temperature_type {
TemperatureType::Celsius => "°C",
TemperatureType::Kelvin => "K",
TemperatureType::Fahrenheit => "°F",
};
concat_string!(temp_val.to_string(), temp_type).into()
}
None => "N/A".to_string().into(),
}
}
}