1
Fork 0
mirror of https://github.com/RGBCube/superfreq synced 2025-07-27 17:07:44 +00:00

cpu: clean up dynamic CPU turbo management

This commit is contained in:
NotAShelf 2025-05-17 09:10:38 +03:00
parent 6ef0a60002
commit 23c526a61e
No known key found for this signature in database
GPG key ID: 29D95B64378DB4BF
3 changed files with 50 additions and 10 deletions

View file

@ -124,6 +124,7 @@ pub struct ProfileConfigToml {
pub min_freq_mhz: Option<u32>, pub min_freq_mhz: Option<u32>,
pub max_freq_mhz: Option<u32>, pub max_freq_mhz: Option<u32>,
pub platform_profile: Option<String>, pub platform_profile: Option<String>,
pub turbo_auto_settings: Option<TurboAutoSettings>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub battery_charge_thresholds: Option<BatteryChargeThresholds>, pub battery_charge_thresholds: Option<BatteryChargeThresholds>,
} }
@ -151,6 +152,7 @@ impl Default for ProfileConfigToml {
min_freq_mhz: None, min_freq_mhz: None,
max_freq_mhz: None, max_freq_mhz: None,
platform_profile: None, platform_profile: None,
turbo_auto_settings: None,
battery_charge_thresholds: None, battery_charge_thresholds: None,
} }
} }
@ -208,7 +210,9 @@ impl From<ProfileConfigToml> for ProfileConfig {
min_freq_mhz: toml_config.min_freq_mhz, min_freq_mhz: toml_config.min_freq_mhz,
max_freq_mhz: toml_config.max_freq_mhz, max_freq_mhz: toml_config.max_freq_mhz,
platform_profile: toml_config.platform_profile, platform_profile: toml_config.platform_profile,
turbo_auto_settings: Some(TurboAutoSettings::default()), turbo_auto_settings: toml_config
.turbo_auto_settings
.or_else(|| Some(TurboAutoSettings::default())),
battery_charge_thresholds: toml_config.battery_charge_thresholds, battery_charge_thresholds: toml_config.battery_charge_thresholds,
} }
} }

View file

@ -1,6 +1,7 @@
use crate::core::{GovernorOverrideMode, TurboSetting}; use crate::core::{GovernorOverrideMode, TurboSetting};
use crate::util::error::ControlError; use crate::util::error::ControlError;
use core::str; use core::str;
use log::debug;
use std::{fs, io, path::Path, string::ToString}; use std::{fs, io, path::Path, string::ToString};
pub type Result<T, E = ControlError> = std::result::Result<T, E>; pub type Result<T, E = ControlError> = std::result::Result<T, E>;
@ -216,12 +217,19 @@ pub fn set_turbo(setting: TurboSetting) -> Result<()> {
let value_pstate = match setting { let value_pstate = match setting {
TurboSetting::Always => "0", // no_turbo = 0 means turbo is enabled TurboSetting::Always => "0", // no_turbo = 0 means turbo is enabled
TurboSetting::Never => "1", // no_turbo = 1 means turbo is disabled TurboSetting::Never => "1", // no_turbo = 1 means turbo is disabled
TurboSetting::Auto => return Err(ControlError::InvalidValueError("Turbo Auto cannot be directly set via intel_pstate/no_turbo or cpufreq/boost. System default.".to_string())), // Auto mode is handled at the engine level, not directly at the sysfs level
TurboSetting::Auto => {
debug!("Turbo Auto mode is managed by engine logic based on system conditions");
return Ok(());
}
}; };
let value_boost = match setting { let value_boost = match setting {
TurboSetting::Always => "1", // boost = 1 means turbo is enabled TurboSetting::Always => "1", // boost = 1 means turbo is enabled
TurboSetting::Never => "0", // boost = 0 means turbo is disabled TurboSetting::Never => "0", // boost = 0 means turbo is disabled
TurboSetting::Auto => return Err(ControlError::InvalidValueError("Turbo Auto cannot be directly set via intel_pstate/no_turbo or cpufreq/boost. System default.".to_string())), TurboSetting::Auto => {
debug!("Turbo Auto mode is managed by engine logic based on system conditions");
return Ok(());
}
}; };
// AMD specific paths // AMD specific paths

View file

@ -4,6 +4,7 @@ use crate::core::{OperationalMode, SystemReport, TurboSetting};
use crate::cpu::{self}; use crate::cpu::{self};
use crate::util::error::{ControlError, EngineError}; use crate::util::error::{ControlError, EngineError};
use log::{debug, info, warn}; use log::{debug, info, warn};
use std::sync::atomic::{AtomicBool, Ordering};
/// Try applying a CPU feature and handle common error cases. Centralizes the where we /// Try applying a CPU feature and handle common error cases. Centralizes the where we
/// previously did: /// previously did:
@ -172,6 +173,10 @@ pub fn determine_and_apply_settings(
Ok(()) Ok(())
} }
// Keep track of current auto turbo state for hysteresis using thread-safe atomics
static PREVIOUS_TURBO_STATE: AtomicBool = AtomicBool::new(false);
static TURBO_STATE_INITIALIZED: AtomicBool = AtomicBool::new(false);
fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<(), EngineError> { fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<(), EngineError> {
// Get the auto turbo settings from the config, or use defaults // Get the auto turbo settings from the config, or use defaults
let turbo_settings = config.turbo_auto_settings.clone().unwrap_or_default(); let turbo_settings = config.turbo_auto_settings.clone().unwrap_or_default();
@ -204,10 +209,18 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
} }
}; };
// Decision logic for enabling/disabling turbo // Get previous state safely using atomic operations
let enable_turbo = match (cpu_temp, avg_cpu_usage) { let has_previous_state = TURBO_STATE_INITIALIZED.load(Ordering::Relaxed);
let previous_turbo_enabled = if has_previous_state {
Some(PREVIOUS_TURBO_STATE.load(Ordering::Relaxed))
} else {
None
};
// 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 // If temperature is too high, disable turbo regardless of load
(Some(temp), _) if temp >= turbo_settings.temp_threshold_high => { (Some(temp), _, _) if temp >= turbo_settings.temp_threshold_high => {
info!( info!(
"Auto Turbo: Disabled due to high temperature ({:.1}°C >= {:.1}°C)", "Auto Turbo: Disabled due to high temperature ({:.1}°C >= {:.1}°C)",
temp, turbo_settings.temp_threshold_high temp, turbo_settings.temp_threshold_high
@ -215,7 +228,7 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
false false
} }
// If load is high enough, enable turbo (unless temp already caused it to disable) // If load is high enough, enable turbo (unless temp already caused it to disable)
(_, Some(usage)) if usage >= turbo_settings.load_threshold_high => { (_, Some(usage), _) if usage >= turbo_settings.load_threshold_high => {
info!( info!(
"Auto Turbo: Enabled due to high CPU load ({:.1}% >= {:.1}%)", "Auto Turbo: Enabled due to high CPU load ({:.1}% >= {:.1}%)",
usage, turbo_settings.load_threshold_high usage, turbo_settings.load_threshold_high
@ -223,21 +236,36 @@ fn manage_auto_turbo(report: &SystemReport, config: &ProfileConfig) -> Result<()
true true
} }
// If load is low, disable turbo // If load is low, disable turbo
(_, Some(usage)) if usage <= turbo_settings.load_threshold_low => { (_, Some(usage), _) if usage <= turbo_settings.load_threshold_low => {
info!( info!(
"Auto Turbo: Disabled due to low CPU load ({:.1}% <= {:.1}%)", "Auto Turbo: Disabled due to low CPU load ({:.1}% <= {:.1}%)",
usage, turbo_settings.load_threshold_low usage, turbo_settings.load_threshold_low
); );
false false
} }
// In intermediate load scenarios or if we can't determine, leave turbo in current state // In intermediate load range, maintain previous state (hysteresis)
// For now, we'll disable it as a safe default (_, Some(usage), Some(prev_state))
if usage > turbo_settings.load_threshold_low
&& usage < turbo_settings.load_threshold_high =>
{
info!(
"Auto Turbo: Maintaining previous state ({}) due to intermediate load ({:.1}%)",
if prev_state { "enabled" } else { "disabled" },
usage
);
prev_state
}
// In indeterminate states or unknown previous state, default to disabled
_ => { _ => {
info!("Auto Turbo: Disabled (default for indeterminate state)"); info!("Auto Turbo: Disabled (default for indeterminate state)");
false false
} }
}; };
// Save the current state for next time using atomic operations
PREVIOUS_TURBO_STATE.store(enable_turbo, Ordering::Relaxed);
TURBO_STATE_INITIALIZED.store(true, Ordering::Relaxed);
// Apply the turbo setting // Apply the turbo setting
let turbo_setting = if enable_turbo { let turbo_setting = if enable_turbo {
TurboSetting::Always TurboSetting::Always