feat: persist fan curve when toggling fan control, avoid applying fan settings when there is no fan

This commit is contained in:
Ilya Zlobintsev
2023-02-20 08:44:19 +02:00
parent 6ec725ffd5
commit ede4886da9
5 changed files with 47 additions and 43 deletions

View File

@@ -24,7 +24,7 @@ use std::{
use tokio::{select, sync::Notify, task::JoinHandle, time::sleep};
use tracing::{debug, error, trace, warn};
type FanControlHandle = (Arc<Notify>, JoinHandle<()>, FanCurve);
type FanControlHandle = (Arc<Notify>, JoinHandle<()>);
pub struct GpuController {
handle: GpuHandle,
@@ -156,18 +156,19 @@ impl GpuController {
}
}
pub fn get_stats(&self) -> anyhow::Result<DeviceStats> {
let fan_control_guard = self
pub fn get_stats(&self, gpu_config: Option<&GpuConfig>) -> anyhow::Result<DeviceStats> {
let fan_control_enabled = self
.fan_control_handle
.lock()
.map_err(|err| anyhow!("Could not lock fan control mutex: {err}"))?;
.map_err(|err| anyhow!("Could not lock fan control mutex: {err}"))?
.is_some();
Ok(DeviceStats {
fan: FanStats {
control_enabled: fan_control_guard.is_some(),
curve: fan_control_guard
.as_ref()
.map(|(_, _, curve)| curve.0.clone()),
control_enabled: fan_control_enabled,
curve: gpu_config
.and_then(|config| config.fan_control_settings.as_ref())
.map(|settings| settings.curve.0.clone()),
speed_current: self.hw_mon_and_then(HwMon::get_fan_current),
speed_max: self.hw_mon_and_then(HwMon::get_fan_max),
speed_min: self.hw_mon_and_then(HwMon::get_fan_min),
@@ -242,8 +243,6 @@ impl GpuController {
let notify = Arc::new(Notify::new());
let task_notify = notify.clone();
let task_curve = curve.clone();
debug!("using curve {curve:?}");
let handle = tokio::spawn(async move {
loop {
@@ -256,7 +255,7 @@ impl GpuController {
let temp = temps
.remove(&temp_key)
.expect("Could not get temperature by given key");
let target_pwm = task_curve.pwm_at_temp(temp);
let target_pwm = curve.pwm_at_temp(temp);
trace!("fan control tick: setting pwm to {target_pwm}");
if let Err(err) = hw_mon.set_fan_pwm(target_pwm) {
@@ -267,7 +266,7 @@ impl GpuController {
debug!("exited fan control task");
});
*notify_guard = Some((notify, handle, curve));
*notify_guard = Some((notify, handle));
debug!(
"started fan control with interval {}ms",
@@ -283,7 +282,7 @@ impl GpuController {
.lock()
.map_err(|err| anyhow!("Lock error: {err}"))?
.take();
if let Some((notify, handle, _)) = maybe_notify {
if let Some((notify, handle)) = maybe_notify {
notify.notify_one();
handle.await?;

View File

@@ -131,7 +131,12 @@ impl<'a> Handler {
}
pub fn get_gpu_stats(&'a self, id: &str) -> anyhow::Result<DeviceStats> {
self.controller_by_id(id)?.get_stats()
let config = self
.config
.read()
.map_err(|err| anyhow!("Could not read config: {err:?}"))?;
let gpu_config = config.gpus.get(id);
self.controller_by_id(id)?.get_stats(gpu_config)
}
pub fn get_clocks_info(&'a self, id: &str) -> anyhow::Result<ClocksInfo> {
@@ -144,9 +149,9 @@ impl<'a> Handler {
enabled: bool,
curve: Option<FanCurveMap>,
) -> anyhow::Result<()> {
let settings = if enabled {
let settings = {
let curve = curve.map_or_else(FanCurve::default, FanCurve);
let settings = match curve {
Some(raw_curve) => {
let curve = FanCurve(raw_curve);
curve.validate()?;
let mut config_guard = self.config.write().map_err(|err| anyhow!("{err}"))?;
@@ -154,18 +159,16 @@ impl<'a> Handler {
if let Some(mut existing_settings) = gpu_config.fan_control_settings.clone() {
existing_settings.curve = curve;
existing_settings
Some(existing_settings)
} else {
FanControlSettings {
Some(FanControlSettings {
curve,
temperature_key: "edge".to_owned(),
interval_ms: 500,
}
})
}
};
Some(settings)
} else {
None
}
None => None,
};
self.edit_gpu_config(id.to_owned(), |config| {

View File

@@ -315,16 +315,17 @@ impl App {
.context("Failed to set power profile")?;
}
let thermals_settings = self.root_stack.thermals_page.get_thermals_settings();
debug!("applying thermal settings: {thermals_settings:?}");
if let Some(thermals_settings) = self.root_stack.thermals_page.get_thermals_settings() {
debug!("applying thermal settings: {thermals_settings:?}");
self.daemon_client
.set_fan_control(
&gpu_id,
thermals_settings.manual_fan_control,
thermals_settings.curve,
)
.context("Could not set fan control")?;
self.daemon_client
.set_fan_control(
&gpu_id,
thermals_settings.manual_fan_control,
thermals_settings.curve,
)
.context("Could not set fan control")?;
}
self.set_initial(&gpu_id);

View File

@@ -176,7 +176,7 @@ fn show_list_window(title: &str, items: &[FeatureModel]) {
.build();
let base_model = gio::ListStore::new(FeatureModel::static_type());
base_model.extend_from_slice(&items);
base_model.extend_from_slice(items);
let expression = PropertyExpression::new(FeatureModel::static_type(), Expression::NONE, "name");
let filter = StringFilter::builder()

View File

@@ -181,17 +181,18 @@ impl ThermalsPage {
});
}
pub fn get_thermals_settings(&self) -> ThermalsSettings {
let manual_fan_control = !self.fan_control_enabled_switch.state();
let curve = if manual_fan_control {
Some(self.fan_curve_frame.get_curve())
pub fn get_thermals_settings(&self) -> Option<ThermalsSettings> {
if self.fan_control_enabled_switch.is_sensitive() {
let manual_fan_control = !self.fan_control_enabled_switch.state();
let curve = self.fan_curve_frame.get_curve();
let curve = if curve.is_empty() { None } else { Some(curve) };
Some(ThermalsSettings {
manual_fan_control,
curve,
})
} else {
None
};
ThermalsSettings {
manual_fan_control,
curve,
}
}
}