manager: Implement new API

This commit is contained in:
Vicki Pfau 2024-03-28 16:23:31 -07:00
parent 6a5e693e5b
commit 69e6477053
5 changed files with 419 additions and 196 deletions

View file

@ -5,7 +5,8 @@
* SPDX-License-Identifier: MIT
*/
use anyhow::{bail, ensure, Result};
use anyhow::{anyhow, bail, ensure, Error, Result};
use std::str::FromStr;
use tokio::fs::{self, File};
use tokio::io::AsyncWriteExt;
use tracing::error;
@ -18,22 +19,81 @@ const GPU_PERFORMANCE_LEVEL_PATH: &str =
"/sys/class/drm/card0/device/power_dpm_force_performance_level";
const GPU_CLOCKS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
pub async fn set_gpu_performance_level(level: i32) -> Result<()> {
// Set given GPU performance level
// Levels are defined below
// return true if able to write, false otherwise or if level is out of range, etc.
let levels = ["auto", "low", "high", "manual", "peak_performance"];
ensure!(
level >= 0 && level < levels.len() as i32,
"Invalid performance level"
);
#[derive(PartialEq, Debug, Copy, Clone)]
#[repr(u32)]
pub enum GPUPerformanceLevel {
UnsupportedFeature = 0,
Auto = 1,
Low = 2,
High = 3,
Manual = 4,
ProfilePeak = 5,
}
impl TryFrom<u32> for GPUPerformanceLevel {
type Error = &'static str;
fn try_from(v: u32) -> Result<Self, Self::Error> {
match v {
x if x == GPUPerformanceLevel::UnsupportedFeature as u32 => {
Ok(GPUPerformanceLevel::UnsupportedFeature)
}
x if x == GPUPerformanceLevel::Auto as u32 => Ok(GPUPerformanceLevel::Auto),
x if x == GPUPerformanceLevel::Low as u32 => Ok(GPUPerformanceLevel::Low),
x if x == GPUPerformanceLevel::High as u32 => Ok(GPUPerformanceLevel::High),
x if x == GPUPerformanceLevel::Manual as u32 => Ok(GPUPerformanceLevel::Manual),
x if x == GPUPerformanceLevel::ProfilePeak as u32 => {
Ok(GPUPerformanceLevel::ProfilePeak)
}
_ => Err("No enum match for value {v}"),
}
}
}
impl FromStr for GPUPerformanceLevel {
type Err = Error;
fn from_str(input: &str) -> Result<GPUPerformanceLevel, Self::Err> {
match input {
"auto" => Ok(GPUPerformanceLevel::Auto),
"low" => Ok(GPUPerformanceLevel::Low),
"high" => Ok(GPUPerformanceLevel::High),
"manual" => Ok(GPUPerformanceLevel::Manual),
"peak_performance" => Ok(GPUPerformanceLevel::ProfilePeak),
v => Err(anyhow!("No enum match for value {v}")),
}
}
}
impl TryInto<String> for GPUPerformanceLevel {
type Error = Error;
fn try_into(self) -> Result<String, Self::Error> {
Ok(String::from(match self {
GPUPerformanceLevel::Auto => "auto",
GPUPerformanceLevel::Low => "low",
GPUPerformanceLevel::High => "high",
GPUPerformanceLevel::Manual => "manual",
GPUPerformanceLevel::ProfilePeak => "peak_performance",
GPUPerformanceLevel::UnsupportedFeature => bail!("No valid string representation"),
}))
}
}
pub async fn get_gpu_performance_level() -> Result<GPUPerformanceLevel> {
let level = fs::read_to_string(GPU_PERFORMANCE_LEVEL_PATH)
.await
.inspect_err(|message| error!("Error opening sysfs file for reading: {message}"))?;
GPUPerformanceLevel::from_str(level.as_ref())
}
pub async fn set_gpu_performance_level(level: GPUPerformanceLevel) -> Result<()> {
let mut myfile = File::create(GPU_PERFORMANCE_LEVEL_PATH)
.await
.inspect_err(|message| error!("Error opening sysfs file for writing: {message}"))?;
let level: String = level.try_into()?;
myfile
.write_all(levels[level as usize].as_bytes())
.write_all(level.as_bytes())
.await
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))?;
Ok(())