feat: GetPowerStates daemon implementation

This commit is contained in:
Ilya Zlobintsev
2023-11-18 10:20:10 +02:00
parent 08f83babfb
commit e692ecde99
6 changed files with 84 additions and 5 deletions

View File

@@ -1,7 +1,9 @@
use crate::server::gpu_controller::fan_control::FanCurve;
use anyhow::Context;
use lact_schema::{
amdgpu_sysfs::gpu_handle::PerformanceLevel, default_fan_curve, request::SetClocksCommand,
amdgpu_sysfs::gpu_handle::{PerformanceLevel, PowerLevelKind},
default_fan_curve,
request::SetClocksCommand,
FanControlMode,
};
use nix::unistd::getuid;
@@ -64,6 +66,7 @@ pub struct Gpu {
pub max_voltage: Option<i32>,
pub voltage_offset: Option<i32>,
pub power_profile_mode_index: Option<u16>,
pub power_states: HashMap<PowerLevelKind, Vec<u8>>,
}
impl Gpu {

View File

@@ -9,13 +9,13 @@ use lact_schema::{
error::Error,
gpu_handle::{
overdrive::{ClocksTable, ClocksTableGen},
GpuHandle, PerformanceLevel,
GpuHandle, PerformanceLevel, PowerLevelKind, PowerLevels,
},
hw_mon::{FanControlMethod, HwMon},
sysfs::SysFS,
},
ClocksInfo, ClockspeedStats, DeviceInfo, DeviceStats, DrmInfo, FanStats, GpuPciInfo, LinkInfo,
PciInfo, PowerStats, VoltageStats, VramStats,
PciInfo, PowerState, PowerStates, PowerStats, VoltageStats, VramStats,
};
use pciid_parser::Database;
use std::{
@@ -23,6 +23,7 @@ use std::{
cell::RefCell,
path::{Path, PathBuf},
rc::Rc,
str::FromStr,
time::Duration,
};
use tokio::{select, sync::Notify, task::JoinHandle, time::sleep};
@@ -37,7 +38,7 @@ use {
type FanControlHandle = (Rc<Notify>, JoinHandle<()>);
pub struct GpuController {
pub handle: GpuHandle,
pub(super) handle: GpuHandle,
#[cfg(feature = "libdrm_amdgpu_sys")]
pub drm_handle: Option<DrmHandle>,
pub pci_info: Option<GpuPciInfo>,
@@ -410,6 +411,42 @@ impl GpuController {
Ok(())
}
pub fn get_power_states(&self, gpu_config: Option<&config::Gpu>) -> PowerStates {
let core = self.get_power_states_kind(gpu_config, PowerLevelKind::CoreClock);
let memory = self.get_power_states_kind(gpu_config, PowerLevelKind::MemoryClock);
PowerStates { core, memory }
}
fn get_power_states_kind<T>(
&self,
gpu_config: Option<&config::Gpu>,
kind: PowerLevelKind,
) -> Vec<PowerState<T>>
where
T: FromStr,
<T as std::str::FromStr>::Err: std::fmt::Display,
{
let enabled_states = gpu_config.and_then(|gpu| gpu.power_states.get(&kind));
let levels = self
.handle
.get_clock_levels::<T>(kind)
.unwrap_or_else(|_| PowerLevels {
levels: Vec::new(),
active: None,
})
.levels;
levels
.into_iter()
.enumerate()
.map(|(i, value)| {
let i = u8::try_from(i).unwrap();
let enabled = enabled_states.map_or(true, |enabled| enabled.contains(&i));
PowerState { enabled, value }
})
.collect()
}
pub async fn apply_config(&self, config: &config::Gpu) -> anyhow::Result<()> {
if config.fan_control_enabled {
if let Some(ref settings) = config.fan_control_settings {
@@ -510,6 +547,18 @@ impl GpuController {
.context("Could not write clocks table")?;
}
for (kind, states) in &config.power_states {
if config.performance_level != Some(PerformanceLevel::Manual) {
return Err(anyhow!(
"Performance level has to be set to `manual` to configure power states"
));
}
self.handle
.set_enabled_power_levels(*kind, states)
.with_context(|| format!("Could not set {kind:?} power states"))?;
}
Ok(())
}
}

View File

@@ -5,7 +5,7 @@ use lact_schema::{
amdgpu_sysfs::gpu_handle::{power_profile_mode::PowerProfileModesTable, PerformanceLevel},
default_fan_curve,
request::{ConfirmCommand, SetClocksCommand},
ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap,
ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanControlMode, FanCurveMap, PowerStates,
};
use std::{cell::RefCell, collections::BTreeMap, env, path::PathBuf, rc::Rc, time::Duration};
use tokio::{sync::oneshot, time::sleep};
@@ -281,6 +281,17 @@ impl<'a> Handler {
.await
}
pub fn get_power_states(&self, id: &str) -> anyhow::Result<PowerStates> {
let config = self
.config
.try_borrow()
.map_err(|err| anyhow!("Could not read config: {err:?}"))?;
let gpu_config = config.gpus.get(id);
let states = self.controller_by_id(id)?.get_power_states(gpu_config);
Ok(states)
}
pub async fn set_performance_level(
&self,
id: &str,

View File

@@ -113,6 +113,7 @@ async fn handle_request<'a>(request: Request<'a>, handler: &'a Handler) -> anyho
Request::SetPowerProfileMode { id, index } => {
ok_response(handler.set_power_profile_mode(id, index).await?)
}
Request::GetPowerStates { id } => ok_response(handler.get_power_states(id)?),
Request::EnableOverdrive => ok_response(system::enable_overdrive()?),
Request::ConfirmPendingConfig(command) => {
ok_response(handler.confirm_pending_config(command)?)

View File

@@ -224,3 +224,15 @@ pub struct PowerStats {
pub cap_min: Option<f64>,
pub cap_default: Option<f64>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PowerStates {
pub core: Vec<PowerState<u64>>,
pub memory: Vec<PowerState<u64>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct PowerState<T> {
pub enabled: bool,
pub value: T,
}

View File

@@ -47,6 +47,9 @@ pub enum Request<'a> {
id: &'a str,
index: Option<u16>,
},
GetPowerStates {
id: &'a str,
},
EnableOverdrive,
ConfirmPendingConfig(ConfirmCommand),
}