mirror of
https://github.com/RGBCube/superfreq
synced 2025-07-27 17:07:44 +00:00
monitor&engine: delete
This commit is contained in:
parent
ce83ba3c91
commit
86b2f5581f
6 changed files with 63 additions and 493 deletions
1
build.rs
1
build.rs
|
@ -6,6 +6,7 @@ const MULTICALL_NAMES: &[&str] = &["cpu", "power"];
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed=target");
|
||||||
|
|
||||||
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
|
let out_dir = PathBuf::from(env::var("OUT_DIR")?);
|
||||||
let target = out_dir
|
let target = out_dir
|
||||||
|
|
|
@ -123,7 +123,7 @@ impl Cpu {
|
||||||
let cache = CpuRescanCache::default();
|
let cache = CpuRescanCache::default();
|
||||||
|
|
||||||
for entry in fs::read_dir(PATH)
|
for entry in fs::read_dir(PATH)
|
||||||
.with_context(|| format!("failed to read CPU entries from '{PATH}'"))?
|
.context("failed to read CPU entries")?
|
||||||
.with_context(|| format!("'{PATH}' doesn't exist, are you on linux?"))?
|
.with_context(|| format!("'{PATH}' doesn't exist, are you on linux?"))?
|
||||||
{
|
{
|
||||||
let entry = entry.with_context(|| format!("failed to read entry of '{PATH}'"))?;
|
let entry = entry.with_context(|| format!("failed to read entry of '{PATH}'"))?;
|
||||||
|
|
465
src/engine.rs
465
src/engine.rs
|
@ -1,465 +0,0 @@
|
||||||
use crate::config::{AppConfig, ProfileConfig, TurboAutoSettings};
|
|
||||||
use crate::core::{OperationalMode, SystemReport};
|
|
||||||
use crate::cpu::{self};
|
|
||||||
use crate::power_supply;
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
/// Track turbo boost state for AC and battery power modes
|
|
||||||
struct TurboHysteresisStates {
|
|
||||||
/// State for when on AC power
|
|
||||||
charger: TurboHysteresis,
|
|
||||||
/// State for when on battery power
|
|
||||||
battery: TurboHysteresis,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TurboHysteresisStates {
|
|
||||||
const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
charger: TurboHysteresis::new(),
|
|
||||||
battery: TurboHysteresis::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn get_for_power_state(&self, is_on_ac: bool) -> &TurboHysteresis {
|
|
||||||
if is_on_ac {
|
|
||||||
&self.charger
|
|
||||||
} else {
|
|
||||||
&self.battery
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TURBO_STATES: OnceLock<TurboHysteresisStates> = OnceLock::new();
|
|
||||||
|
|
||||||
/// Get or initialize the global turbo states
|
|
||||||
fn get_turbo_states() -> &'static TurboHysteresisStates {
|
|
||||||
TURBO_STATES.get_or_init(TurboHysteresisStates::new)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Manage turbo boost hysteresis state.
|
|
||||||
/// Contains the state needed to implement hysteresis
|
|
||||||
/// for the dynamic turbo management feature
|
|
||||||
struct TurboHysteresis {
|
|
||||||
/// Whether turbo was enabled in the previous cycle
|
|
||||||
previous_state: AtomicBool,
|
|
||||||
/// Whether the hysteresis state has been initialized
|
|
||||||
initialized: AtomicBool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TurboHysteresis {
|
|
||||||
const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
previous_state: AtomicBool::new(false),
|
|
||||||
initialized: AtomicBool::new(false),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the previous turbo state, if initialized
|
|
||||||
fn get_previous_state(&self) -> Option<bool> {
|
|
||||||
if self.initialized.load(Ordering::Acquire) {
|
|
||||||
Some(self.previous_state.load(Ordering::Acquire))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize the state with a specific value if not already initialized
|
|
||||||
/// Only one thread should be able to initialize the state
|
|
||||||
fn initialize_with(&self, initial_state: bool) -> bool {
|
|
||||||
// First, try to atomically change initialized from false to true
|
|
||||||
// Only one thread can win the initialization race
|
|
||||||
match self.initialized.compare_exchange(
|
|
||||||
false, // expected: not initialized
|
|
||||||
true, // desired: mark as initialized
|
|
||||||
Ordering::Release, // success: release for memory visibility
|
|
||||||
Ordering::Acquire, // failure: just need to acquire the current value
|
|
||||||
) {
|
|
||||||
Ok(_) => {
|
|
||||||
// We won the race to initialize
|
|
||||||
// Now it's safe to set the initial state since we know we're the only
|
|
||||||
// thread that has successfully marked this as initialized
|
|
||||||
self.previous_state.store(initial_state, Ordering::Release);
|
|
||||||
initial_state
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
// Another thread already initialized it.
|
|
||||||
// Just read the current state value that was set by the winning thread
|
|
||||||
self.previous_state.load(Ordering::Acquire)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update the turbo state for hysteresis
|
|
||||||
fn update_state(&self, new_state: bool) {
|
|
||||||
// First store the new state, then mark as initialized
|
|
||||||
// With this, any thread seeing initialized=true will also see the correct state
|
|
||||||
self.previous_state.store(new_state, Ordering::Release);
|
|
||||||
|
|
||||||
// Already initialized, no need for compare_exchange
|
|
||||||
if self.initialized.load(Ordering::Relaxed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, try to set initialized=true (but only if it was false)
|
|
||||||
self.initialized
|
|
||||||
.compare_exchange(
|
|
||||||
false, // expected: not initialized
|
|
||||||
true, // desired: mark as initialized
|
|
||||||
Ordering::Release, // success: release for memory visibility
|
|
||||||
Ordering::Relaxed, // failure: we don't care about the current value on failure
|
|
||||||
)
|
|
||||||
.ok(); // Ignore the result. If it fails, it means another thread already initialized it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try applying a CPU feature and handle common error cases. Centralizes the where we
|
|
||||||
/// previously did:
|
|
||||||
/// 1. Try to apply a feature setting
|
|
||||||
/// 2. If not supported, log a warning and continue
|
|
||||||
/// 3. If other error, propagate the error
|
|
||||||
fn try_apply_feature<F: FnOnce() -> anyhow::Result<()>, T>(
|
|
||||||
feature_name: &str,
|
|
||||||
value_description: &str,
|
|
||||||
apply_fn: F,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
log::info!("Setting {feature_name} to '{value_description}'");
|
|
||||||
|
|
||||||
apply_fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines the appropriate CPU profile based on power status or forced mode,
|
|
||||||
/// and applies the settings (via helpers defined in the `cpu` module)
|
|
||||||
pub fn determine_and_apply_settings(
|
|
||||||
report: &SystemReport,
|
|
||||||
config: &AppConfig,
|
|
||||||
force_mode: Option<OperationalMode>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
// // First, check if there's a governor override set
|
|
||||||
// if let Some(override_governor) = cpu::get_governor_override() {
|
|
||||||
// log::info!(
|
|
||||||
// "Governor override is active: '{}'. Setting governor.",
|
|
||||||
// override_governor.trim()
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Apply the override governor setting
|
|
||||||
// try_apply_feature("override governor", override_governor.trim(), || {
|
|
||||||
// cpu::set_governor(override_governor.trim(), None)
|
|
||||||
// })?;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Determine AC/Battery status once, early in the function
|
|
||||||
// For desktops (no batteries), we should always use the AC power profile
|
|
||||||
// For laptops, we check if all batteries report connected to AC
|
|
||||||
let on_ac_power = if report.batteries.is_empty() {
|
|
||||||
// No batteries means desktop/server, always on AC
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
// Check if all batteries report AC connected
|
|
||||||
report.batteries.iter().all(|b| b.ac_connected)
|
|
||||||
};
|
|
||||||
|
|
||||||
let selected_profile_config: &ProfileConfig;
|
|
||||||
|
|
||||||
if let Some(mode) = force_mode {
|
|
||||||
match mode {
|
|
||||||
OperationalMode::Powersave => {
|
|
||||||
log::info!("Forced Powersave mode selected. Applying 'battery' profile.");
|
|
||||||
selected_profile_config = &config.battery;
|
|
||||||
}
|
|
||||||
OperationalMode::Performance => {
|
|
||||||
log::info!("Forced Performance mode selected. Applying 'charger' profile.");
|
|
||||||
selected_profile_config = &config.charger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Use the previously computed on_ac_power value
|
|
||||||
if on_ac_power {
|
|
||||||
log::info!("On AC power, selecting Charger profile.");
|
|
||||||
selected_profile_config = &config.charger;
|
|
||||||
} else {
|
|
||||||
log::info!("On Battery power, selecting Battery profile.");
|
|
||||||
selected_profile_config = &config.battery;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply settings from selected_profile_config
|
|
||||||
if let Some(governor) = &selected_profile_config.governor {
|
|
||||||
log::info!("Setting governor to '{governor}'");
|
|
||||||
for cpu in cpu::Cpu::all()? {
|
|
||||||
// Let set_governor handle the validation
|
|
||||||
if let Err(error) = cpu.set_governor(governor) {
|
|
||||||
// If the governor is not available, log a warning
|
|
||||||
log::warn!("{error}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(turbo_setting) = selected_profile_config.turbo {
|
|
||||||
log::info!("Setting turbo to '{turbo_setting:?}'");
|
|
||||||
match turbo_setting {
|
|
||||||
TurboSetting::Auto => {
|
|
||||||
if selected_profile_config.enable_auto_turbo {
|
|
||||||
log::debug!("Managing turbo in auto mode based on system conditions");
|
|
||||||
manage_auto_turbo(report, selected_profile_config, on_ac_power)?;
|
|
||||||
} else {
|
|
||||||
log::debug!(
|
|
||||||
"Watt's dynamic turbo management is disabled by configuration. Ensuring system uses its default behavior for automatic turbo control."
|
|
||||||
);
|
|
||||||
// Make sure the system is set to its default automatic turbo mode.
|
|
||||||
// This is important if turbo was previously forced off.
|
|
||||||
try_apply_feature("Turbo boost", "system default (Auto)", || {
|
|
||||||
cpu::set_turbo(TurboSetting::Auto)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
try_apply_feature("Turbo boost", &format!("{turbo_setting:?}"), || {
|
|
||||||
cpu::set_turbo(turbo_setting)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(epp) = &selected_profile_config.epp {
|
|
||||||
try_apply_feature("EPP", epp, || cpu::set_epp(epp, None))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(epb) = &selected_profile_config.epb {
|
|
||||||
try_apply_feature("EPB", epb, || cpu::set_epb(epb, None))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(min_freq) = selected_profile_config.min_freq_mhz {
|
|
||||||
try_apply_feature("min frequency", &format!("{min_freq} MHz"), || {
|
|
||||||
cpu::set_frequency_minimum(min_freq, None)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(max_freq) = selected_profile_config.max_freq_mhz {
|
|
||||||
try_apply_feature("max frequency", &format!("{max_freq} MHz"), || {
|
|
||||||
cpu::set_frequency_maximum(max_freq, None)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(profile) = &selected_profile_config.platform_profile {
|
|
||||||
try_apply_feature("platform profile", profile, || {
|
|
||||||
cpu::set_platform_profile(profile)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set battery charge thresholds if configured
|
|
||||||
if let Some(thresholds) = &selected_profile_config.battery_charge_thresholds {
|
|
||||||
let start_threshold = thresholds.start;
|
|
||||||
let stop_threshold = thresholds.stop;
|
|
||||||
|
|
||||||
if start_threshold < stop_threshold && stop_threshold <= 100 {
|
|
||||||
log::info!("Setting battery charge thresholds: {start_threshold}-{stop_threshold}%");
|
|
||||||
match power_supply::set_battery_charge_thresholds(start_threshold, stop_threshold) {
|
|
||||||
Ok(()) => log::debug!("Battery charge thresholds set successfully"),
|
|
||||||
Err(e) => log::warn!("Failed to set battery charge thresholds: {e}"),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::warn!(
|
|
||||||
"Invalid battery threshold values: start={start_threshold}, stop={stop_threshold}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log::debug!("Profile settings applied successfully.");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn manage_auto_turbo(
|
|
||||||
report: &SystemReport,
|
|
||||||
config: &ProfileConfig,
|
|
||||||
on_ac_power: bool,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
// Get the auto turbo settings from the config
|
|
||||||
let turbo_settings = &config.turbo_auto_settings;
|
|
||||||
|
|
||||||
// Validate the complete configuration to ensure it's usable
|
|
||||||
validate_turbo_auto_settings(turbo_settings)?;
|
|
||||||
|
|
||||||
// Get average CPU temperature and CPU load
|
|
||||||
let cpu_temp = report.cpu_global.average_temperature_celsius;
|
|
||||||
|
|
||||||
// Check if we have CPU usage data available
|
|
||||||
let avg_cpu_usage = if report.cpu_cores.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let sum: f32 = report
|
|
||||||
.cpu_cores
|
|
||||||
.iter()
|
|
||||||
.filter_map(|core| core.usage_percent)
|
|
||||||
.sum();
|
|
||||||
let count = report
|
|
||||||
.cpu_cores
|
|
||||||
.iter()
|
|
||||||
.filter(|core| core.usage_percent.is_some())
|
|
||||||
.count();
|
|
||||||
|
|
||||||
if count > 0 {
|
|
||||||
Some(sum / count as f32)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get the previous state or initialize with the configured initial state
|
|
||||||
let previous_turbo_enabled = {
|
|
||||||
let turbo_states = get_turbo_states();
|
|
||||||
let hysteresis = turbo_states.get_for_power_state(on_ac_power);
|
|
||||||
if let Some(state) = hysteresis.get_previous_state() {
|
|
||||||
state
|
|
||||||
} else {
|
|
||||||
// Initialize with the configured initial state and return it
|
|
||||||
hysteresis.initialize_with(turbo_settings.initial_turbo_state)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Decision logic for enabling/disabling turbo with hysteresis
|
|
||||||
let enable_turbo = match (cpu_temp, avg_cpu_usage, previous_turbo_enabled) {
|
|
||||||
// If temperature is too high, disable turbo regardless of load
|
|
||||||
(Some(temp), _, _) if temp >= turbo_settings.temp_threshold_high => {
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Disabled due to high temperature ({:.1}°C >= {:.1}°C)",
|
|
||||||
temp,
|
|
||||||
turbo_settings.temp_threshold_high
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
// If load is high enough, enable turbo (unless temp already caused it to disable)
|
|
||||||
(_, Some(usage), _) if usage >= turbo_settings.load_threshold_high => {
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Enabled due to high CPU load ({:.1}% >= {:.1}%)",
|
|
||||||
usage,
|
|
||||||
turbo_settings.load_threshold_high
|
|
||||||
);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// If load is low, disable turbo
|
|
||||||
(_, Some(usage), _) if usage <= turbo_settings.load_threshold_low => {
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Disabled due to low CPU load ({:.1}% <= {:.1}%)",
|
|
||||||
usage,
|
|
||||||
turbo_settings.load_threshold_low
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
// In intermediate load range, maintain previous state (hysteresis)
|
|
||||||
(_, Some(usage), prev_state)
|
|
||||||
if usage > turbo_settings.load_threshold_low
|
|
||||||
&& usage < turbo_settings.load_threshold_high =>
|
|
||||||
{
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Maintaining previous state ({}) due to intermediate load ({:.1}%)",
|
|
||||||
if prev_state { "enabled" } else { "disabled" },
|
|
||||||
usage
|
|
||||||
);
|
|
||||||
prev_state
|
|
||||||
}
|
|
||||||
|
|
||||||
// When CPU load data is present but temperature is missing, use the same hysteresis logic
|
|
||||||
(None, Some(usage), prev_state) => {
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Maintaining previous state ({}) due to missing temperature data (load: {:.1}%)",
|
|
||||||
if prev_state { "enabled" } else { "disabled" },
|
|
||||||
usage
|
|
||||||
);
|
|
||||||
prev_state
|
|
||||||
}
|
|
||||||
|
|
||||||
// When all metrics are missing, maintain the previous state
|
|
||||||
(None, None, prev_state) => {
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Maintaining previous state ({}) due to missing all CPU metrics",
|
|
||||||
if prev_state { "enabled" } else { "disabled" }
|
|
||||||
);
|
|
||||||
prev_state
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any other cases with partial metrics, maintain previous state for stability
|
|
||||||
(_, _, prev_state) => {
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Maintaining previous state ({}) due to incomplete CPU metrics",
|
|
||||||
if prev_state { "enabled" } else { "disabled" }
|
|
||||||
);
|
|
||||||
prev_state
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save the current state for next time
|
|
||||||
{
|
|
||||||
let turbo_states = get_turbo_states();
|
|
||||||
let hysteresis = turbo_states.get_for_power_state(on_ac_power);
|
|
||||||
hysteresis.update_state(enable_turbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only apply the setting if the state has changed
|
|
||||||
let changed = previous_turbo_enabled != enable_turbo;
|
|
||||||
if changed {
|
|
||||||
let turbo_setting = if enable_turbo {
|
|
||||||
TurboSetting::Always
|
|
||||||
} else {
|
|
||||||
TurboSetting::Never
|
|
||||||
};
|
|
||||||
|
|
||||||
log::info!(
|
|
||||||
"Auto Turbo: Applying turbo change from {} to {}",
|
|
||||||
if previous_turbo_enabled {
|
|
||||||
"enabled"
|
|
||||||
} else {
|
|
||||||
"disabled"
|
|
||||||
},
|
|
||||||
if enable_turbo { "enabled" } else { "disabled" }
|
|
||||||
);
|
|
||||||
|
|
||||||
match cpu::set_turbo(turbo_setting) {
|
|
||||||
Ok(()) => {
|
|
||||||
log::debug!(
|
|
||||||
"Auto Turbo: Successfully set turbo to {}",
|
|
||||||
if enable_turbo { "enabled" } else { "disabled" }
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(e) => Err(EngineError::ControlError(e)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::debug!(
|
|
||||||
"Auto Turbo: Maintaining turbo state ({}) - no change needed",
|
|
||||||
if enable_turbo { "enabled" } else { "disabled" }
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate_turbo_auto_settings(settings: &TurboAutoSettings) -> Result<(), EngineError> {
|
|
||||||
if settings.load_threshold_high <= settings.load_threshold_low
|
|
||||||
|| settings.load_threshold_high > 100.0
|
|
||||||
|| settings.load_threshold_high < 0.0
|
|
||||||
|| settings.load_threshold_low < 0.0
|
|
||||||
|| settings.load_threshold_low > 100.0
|
|
||||||
{
|
|
||||||
return Err(EngineError::ConfigurationError(
|
|
||||||
"Invalid turbo auto settings: load thresholds must be between 0 % and 100 % with high > low"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate temperature threshold (realistic range for CPU temps in Celsius)
|
|
||||||
// TODO: different CPUs have different temperature thresholds. While 110 is a good example
|
|
||||||
// "extreme" case, the upper barrier might be *lower* for some devices. We'll want to fix
|
|
||||||
// this eventually, or make it configurable.
|
|
||||||
if settings.temp_threshold_high <= 0.0 || settings.temp_threshold_high > 110.0 {
|
|
||||||
return Err(EngineError::ConfigurationError(
|
|
||||||
"Invalid turbo auto settings: temperature threshold must be between 0°C and 110°C"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Try /sys/devices/platform paths for thermal zones as a last resort
|
|
||||||
// if temperature_celsius.is_none() {
|
|
||||||
// if let Ok(thermal_zones) = fs::read_dir("/sys/devices/virtual/thermal") {
|
|
||||||
// for entry in thermal_zones.flatten() {
|
|
||||||
// let zone_path = entry.path();
|
|
||||||
// let name = entry.file_name().into_string().unwrap_or_default();
|
|
||||||
|
|
||||||
// if name.starts_with("thermal_zone") {
|
|
||||||
// // Try to match by type
|
|
||||||
// if let Ok(zone_type) = read_sysfs_file_trimmed(zone_path.join("type")) {
|
|
||||||
// if zone_type.contains("cpu")
|
|
||||||
// || zone_type.contains("x86")
|
|
||||||
// || zone_type.contains("core")
|
|
||||||
// {
|
|
||||||
// if let Ok(temp_mc) = read_sysfs_value::<i32>(zone_path.join("temp")) {
|
|
||||||
// temperature_celsius = Some(temp_mc as f32 / 1000.0);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -154,7 +154,7 @@ impl PowerSupply {
|
||||||
let mut power_supplies = Vec::new();
|
let mut power_supplies = Vec::new();
|
||||||
|
|
||||||
for entry in fs::read_dir(POWER_SUPPLY_PATH)
|
for entry in fs::read_dir(POWER_SUPPLY_PATH)
|
||||||
.with_context(|| format!("failed to read '{POWER_SUPPLY_PATH}'"))?
|
.context("failed to read power supply entries")?
|
||||||
.with_context(|| format!("'{POWER_SUPPLY_PATH}' doesn't exist, are you on linux?"))?
|
.with_context(|| format!("'{POWER_SUPPLY_PATH}' doesn't exist, are you on linux?"))?
|
||||||
{
|
{
|
||||||
let entry = match entry {
|
let entry = match entry {
|
||||||
|
|
|
@ -115,7 +115,7 @@ impl System {
|
||||||
let mut temperatures = HashMap::new();
|
let mut temperatures = HashMap::new();
|
||||||
|
|
||||||
for entry in fs::read_dir(PATH)
|
for entry in fs::read_dir(PATH)
|
||||||
.with_context(|| format!("failed to read hardware information from '{PATH}'"))?
|
.context("failed to read hardware information")?
|
||||||
.with_context(|| format!("'{PATH}' doesn't exist, are you on linux?"))?
|
.with_context(|| format!("'{PATH}' doesn't exist, are you on linux?"))?
|
||||||
{
|
{
|
||||||
let entry = entry.with_context(|| format!("failed to read entry of '{PATH}'"))?;
|
let entry = entry.with_context(|| format!("failed to read entry of '{PATH}'"))?;
|
||||||
|
@ -147,6 +147,64 @@ impl System {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if temperatures.is_empty() {
|
||||||
|
const PATH: &str = "/sys/devices/virtual/thermal";
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"failed to get CPU temperature information by using hwmon, falling back to '{PATH}'"
|
||||||
|
);
|
||||||
|
|
||||||
|
let Some(thermal_zones) =
|
||||||
|
fs::read_dir(PATH).context("failed to read thermal information")?
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in thermal_zones {
|
||||||
|
let entry = entry.with_context(|| format!("failed to read entry of '{PATH}'"))?;
|
||||||
|
|
||||||
|
let entry_path = entry.path();
|
||||||
|
|
||||||
|
let entry_name = entry.file_name();
|
||||||
|
let entry_name = entry_name.to_string_lossy();
|
||||||
|
|
||||||
|
if !entry_name.starts_with("thermal_zone") {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(entry_type) = fs::read(entry_path.join("type")).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"failed to read type of zone at '{path}'",
|
||||||
|
path = entry_path.display(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
if !entry_type.contains("cpu")
|
||||||
|
&& !entry_type.contains("x86")
|
||||||
|
&& !entry_type.contains("core")
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(temperature_mc) = fs::read_n::<i64>(entry_path.join("temp"))
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"failed to read temperature of zone at '{path}'",
|
||||||
|
path = entry_path.display(),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Magic value to see that it is from the thermal zones.
|
||||||
|
temperatures.insert(777, temperature_mc as f64 / 1000.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.cpu_temperatures = temperatures;
|
self.cpu_temperatures = temperatures;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -185,7 +243,7 @@ impl System {
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
log::debug!("label content: {number}");
|
log::debug!("label content: {label}");
|
||||||
|
|
||||||
// Match various common label formats:
|
// Match various common label formats:
|
||||||
// "Core X", "core X", "Core-X", "CPU Core X", etc.
|
// "Core X", "core X", "Core-X", "CPU Core X", etc.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue