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:
parent
6ef0a60002
commit
23c526a61e
3 changed files with 50 additions and 10 deletions
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/cpu.rs
12
src/cpu.rs
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue