diff --git a/local/recipes/system/redbear-power/source/src/app.rs b/local/recipes/system/redbear-power/source/src/app.rs index 83d4ee514f..baf135fe03 100644 --- a/local/recipes/system/redbear-power/source/src/app.rs +++ b/local/recipes/system/redbear-power/source/src/app.rs @@ -121,7 +121,7 @@ pub struct App { pub load_available: bool, pub governor_available: bool, pub hwmon_available: bool, - pub pkg_thermal: PackageThermal, + pub package_thermal: Option, pub dbus_disconnected: bool, pub cpuid_info: CpuId, pub simd: String, @@ -423,7 +423,7 @@ impl App { load_available, governor_available, hwmon_available, - pkg_thermal: PackageThermal::default(), + package_thermal: None, dbus_disconnected: false, cpuid_info, simd, @@ -882,11 +882,15 @@ impl App { } // Re-read cpufreq state (catches external governor changes). self.cpufreq.refresh(); - if let Some(pkg) = read_package_thermal_status(self.cpus[0].id) { - self.pkg_thermal = PackageThermal::from_msr(pkg); + self.package_thermal = self + .cpus + .first() + .and_then(|cpu| read_package_thermal_status(cpu.id)) + .map(PackageThermal::from_msr); + if let Some(pkg) = self.package_thermal.as_ref() { // PROCHOT at the package level means the entire chip is // throttling. Surface that in the global header. - let prochot_now = pkg & THERM_STATUS_PROCHOT != 0; + let prochot_now = pkg.prochot; let prochot_was = matches!(self.throttle, ThrottleMode::ForcedMin); if prochot_now && !prochot_was { self.flash_toast("PROCHOT triggered \u{2014} throttling active"); diff --git a/local/recipes/system/redbear-power/source/src/msr.rs b/local/recipes/system/redbear-power/source/src/msr.rs index 1a8627a511..cf6147742c 100644 --- a/local/recipes/system/redbear-power/source/src/msr.rs +++ b/local/recipes/system/redbear-power/source/src/msr.rs @@ -23,17 +23,21 @@ use std::sync::Mutex; static MSR_FAILED: Mutex> = Mutex::new(Vec::new()); fn msr_failed_for(cpu: u32) -> bool { - let cache = MSR_FAILED.lock().unwrap(); - cpu as usize >= cache.len() || cache[cpu as usize] + if let Ok(cache) = MSR_FAILED.lock() { + cpu as usize >= cache.len() || cache[cpu as usize] + } else { + false + } } fn mark_msr_failed(cpu: u32) { - let mut cache = MSR_FAILED.lock().unwrap(); - let idx = cpu as usize; - if idx >= cache.len() { - cache.resize(idx + 1, false); + if let Ok(mut cache) = MSR_FAILED.lock() { + let idx = cpu as usize; + if idx >= cache.len() { + cache.resize(idx + 1, false); + } + cache[idx] = true; } - cache[idx] = true; } /// Clear the MSR failure cache. Call periodically (every ~30s) so that @@ -261,7 +265,6 @@ pub fn read_hwp_status(cpu: u32) -> Option { /// Decoded view of `IA32_PACKAGE_THERM_STATUS`. Built from the raw MSR /// value in `app.rs:refresh()`. Empty/default when the MSR is unreadable. #[derive(Clone, Copy, Debug, Default)] -#[allow(dead_code)] pub struct PackageThermal { pub temp_c: Option, pub valid: bool, diff --git a/local/recipes/system/redbear-power/source/src/render.rs b/local/recipes/system/redbear-power/source/src/render.rs index 74a1cc4cb0..082b2234f5 100644 --- a/local/recipes/system/redbear-power/source/src/render.rs +++ b/local/recipes/system/redbear-power/source/src/render.rs @@ -166,12 +166,28 @@ pub fn render_toast<'a>(app: &'a App) -> Option> { pub fn render_header<'a>(app: &'a App, focused: bool) -> Paragraph<'a> { let theme = &app.theme; let pkg_temp = app - .cpus - .iter() - .filter_map(|c| c.temp_c) - .max() + .package_thermal + .and_then(|pkg| pkg.temp_c) + .or_else(|| app.cpus.iter().filter_map(|c| c.temp_c).max()) .map(|t| format!("{t}°C")) .unwrap_or_else(|| "n/a".into()); + let pkg_thermal = app.package_thermal.map(|pkg| { + let label = pkg.short_label(); + let style = if pkg.valid + && (pkg.prochot + || pkg.power_limit_1 + || pkg.power_limit_2 + || pkg.critical + || pkg.hfi + || pkg.thermal_throttle_1 + || pkg.thermal_throttle_2) + { + theme.value_hot + } else { + theme.value_off + }; + (label, style) + }); let lines = vec![ Line::from(vec![ "Vendor: ".set_style(theme.label), @@ -214,6 +230,20 @@ pub fn render_header<'a>(app: &'a App, focused: bool) -> Paragraph<'a> { "P-state source: ".set_style(theme.label), app.pss_source.as_str().into(), ]), + Line::from(vec![ + "PkgTherm: ".set_style(theme.label), + match pkg_thermal { + Some((label, style)) => label.set_style(style), + None => "n/a".set_style(theme.value_off), + }, + " ".into(), + "D-Bus: ".set_style(theme.label), + if app.dbus_disconnected { + "DISCONNECTED".set_style(theme.status_warn) + } else { + "ok".set_style(theme.value_ok) + }, + ]), Line::from(vec![ "SIMD: ".set_style(theme.label), app.simd.as_str().set_style(theme.value),