mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-12 09:22:26 -04:00
power: Combine GPU prefix lookups into simpler helpers
Previously we had two diferent lookup functions for finding the GPU in /sys/class/drm/card* and /sys/class/hwmon/hwmon*, but for the former we only used paths under it in device/. In both these cases, the device/ directory is a symbolic link to the same directory, so in the case of one AMD GPU in a machine, these operations were equivalent. This MR removes the /sys/class/drm version as well as refactoring some of the utility code to reduce code duplication.
This commit is contained in:
parent
93e153079d
commit
5e8b4160d2
1 changed files with 17 additions and 40 deletions
57
src/power.rs
57
src/power.rs
|
@ -8,7 +8,7 @@
|
||||||
use anyhow::{anyhow, bail, ensure, Error, Result};
|
use anyhow::{anyhow, bail, ensure, Error, Result};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
use tokio::fs::{self, File};
|
use tokio::fs::{self, File};
|
||||||
|
@ -20,8 +20,6 @@ use crate::{path, write_synced};
|
||||||
|
|
||||||
const GPU_HWMON_PREFIX: &str = "/sys/class/hwmon";
|
const GPU_HWMON_PREFIX: &str = "/sys/class/hwmon";
|
||||||
const GPU_HWMON_NAME: &str = "amdgpu";
|
const GPU_HWMON_NAME: &str = "amdgpu";
|
||||||
const GPU_DRM_PREFIX: &str = "/sys/class/drm";
|
|
||||||
const GPU_VENDOR: &str = "0x1002";
|
|
||||||
const CPU_PREFIX: &str = "/sys/devices/system/cpu/cpufreq";
|
const CPU_PREFIX: &str = "/sys/devices/system/cpu/cpufreq";
|
||||||
|
|
||||||
const CPU0_NAME: &str = "policy0";
|
const CPU0_NAME: &str = "policy0";
|
||||||
|
@ -161,14 +159,21 @@ pub enum CPUScalingGovernor {
|
||||||
SchedUtil,
|
SchedUtil,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_gpu_sysfs_contents() -> Result<String> {
|
async fn read_gpu_sysfs_contents<S: AsRef<Path>>(suffix: S) -> Result<String> {
|
||||||
// check which profile is current and return if possible
|
// Read a given suffix for the GPU
|
||||||
let base = find_gpu_prefix().await?;
|
let base = find_hwmon().await?;
|
||||||
fs::read_to_string(base.join(GPU_POWER_PROFILE_SUFFIX))
|
fs::read_to_string(base.join(suffix.as_ref()))
|
||||||
.await
|
.await
|
||||||
.map_err(|message| anyhow!("Error opening sysfs file for reading {message}"))
|
.map_err(|message| anyhow!("Error opening sysfs file for reading {message}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn write_gpu_sysfs_contents<S: AsRef<Path>>(suffix: S, data: &[u8]) -> Result<()> {
|
||||||
|
let base = find_hwmon().await?;
|
||||||
|
write_synced(base.join(suffix), data)
|
||||||
|
.await
|
||||||
|
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))
|
||||||
|
}
|
||||||
|
|
||||||
async fn read_cpu_governor_sysfs_available_contents() -> Result<String> {
|
async fn read_cpu_governor_sysfs_available_contents() -> Result<String> {
|
||||||
let base = path(CPU_PREFIX);
|
let base = path(CPU_PREFIX);
|
||||||
Ok(fs::read_to_string(
|
Ok(fs::read_to_string(
|
||||||
|
@ -219,7 +224,7 @@ async fn write_cpu_governor_sysfs_contents(contents: String) -> Result<()> {
|
||||||
|
|
||||||
pub(crate) async fn get_gpu_power_profile() -> Result<GPUPowerProfile> {
|
pub(crate) async fn get_gpu_power_profile() -> Result<GPUPowerProfile> {
|
||||||
// check which profile is current and return if possible
|
// check which profile is current and return if possible
|
||||||
let contents = read_gpu_sysfs_contents().await?;
|
let contents = read_gpu_sysfs_contents(GPU_POWER_PROFILE_SUFFIX).await?;
|
||||||
|
|
||||||
// NOTE: We don't filter based on is_deck here because the sysfs
|
// NOTE: We don't filter based on is_deck here because the sysfs
|
||||||
// firmware support setting the value to no-op values.
|
// firmware support setting the value to no-op values.
|
||||||
|
@ -249,7 +254,7 @@ pub(crate) async fn get_gpu_power_profile() -> Result<GPUPowerProfile> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_gpu_power_profiles() -> Result<HashMap<u32, String>> {
|
pub(crate) async fn get_gpu_power_profiles() -> Result<HashMap<u32, String>> {
|
||||||
let contents = read_gpu_sysfs_contents().await?;
|
let contents = read_gpu_sysfs_contents(GPU_POWER_PROFILE_SUFFIX).await?;
|
||||||
let deck = is_deck().await?;
|
let deck = is_deck().await?;
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
@ -285,27 +290,17 @@ pub(crate) async fn get_gpu_power_profiles() -> Result<HashMap<u32, String>> {
|
||||||
|
|
||||||
pub(crate) async fn set_gpu_power_profile(value: GPUPowerProfile) -> Result<()> {
|
pub(crate) async fn set_gpu_power_profile(value: GPUPowerProfile) -> Result<()> {
|
||||||
let profile = (value as u32).to_string();
|
let profile = (value as u32).to_string();
|
||||||
let base = find_gpu_prefix().await?;
|
write_gpu_sysfs_contents(GPU_POWER_PROFILE_SUFFIX, profile.as_bytes()).await
|
||||||
write_synced(base.join(GPU_POWER_PROFILE_SUFFIX), profile.as_bytes())
|
|
||||||
.await
|
|
||||||
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_gpu_performance_level() -> Result<GPUPerformanceLevel> {
|
pub(crate) async fn get_gpu_performance_level() -> Result<GPUPerformanceLevel> {
|
||||||
let base = find_hwmon().await?;
|
let level = read_gpu_sysfs_contents(GPU_PERFORMANCE_LEVEL_SUFFIX).await?;
|
||||||
let level = fs::read_to_string(base.join(GPU_PERFORMANCE_LEVEL_SUFFIX))
|
|
||||||
.await
|
|
||||||
.inspect_err(|message| error!("Error opening sysfs file for reading: {message}"))?;
|
|
||||||
|
|
||||||
GPUPerformanceLevel::from_str(level.trim())
|
GPUPerformanceLevel::from_str(level.trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn set_gpu_performance_level(level: GPUPerformanceLevel) -> Result<()> {
|
pub(crate) async fn set_gpu_performance_level(level: GPUPerformanceLevel) -> Result<()> {
|
||||||
let level: String = level.to_string();
|
let level: String = level.to_string();
|
||||||
let base = find_hwmon().await?;
|
write_gpu_sysfs_contents(GPU_PERFORMANCE_LEVEL_SUFFIX, level.as_bytes()).await
|
||||||
write_synced(base.join(GPU_PERFORMANCE_LEVEL_SUFFIX), level.as_bytes())
|
|
||||||
.await
|
|
||||||
.inspect_err(|message| error!("Error writing to sysfs file: {message}"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_available_cpu_scaling_governors() -> Result<Vec<CPUScalingGovernor>> {
|
pub(crate) async fn get_available_cpu_scaling_governors() -> Result<Vec<CPUScalingGovernor>> {
|
||||||
|
@ -399,24 +394,6 @@ pub(crate) async fn get_gpu_clocks() -> Result<u32> {
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_gpu_prefix() -> Result<PathBuf> {
|
|
||||||
let mut dir = fs::read_dir(path(GPU_DRM_PREFIX)).await?;
|
|
||||||
loop {
|
|
||||||
let base = match dir.next_entry().await? {
|
|
||||||
Some(entry) => entry.path(),
|
|
||||||
None => bail!("GPU node not found"),
|
|
||||||
};
|
|
||||||
let file_name = base.join("device").join("vendor");
|
|
||||||
let vendor = fs::read_to_string(file_name.as_path())
|
|
||||||
.await?
|
|
||||||
.trim()
|
|
||||||
.to_string();
|
|
||||||
if vendor == GPU_VENDOR {
|
|
||||||
return Ok(base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn find_hwmon() -> Result<PathBuf> {
|
async fn find_hwmon() -> Result<PathBuf> {
|
||||||
let mut dir = fs::read_dir(path(GPU_HWMON_PREFIX)).await?;
|
let mut dir = fs::read_dir(path(GPU_HWMON_PREFIX)).await?;
|
||||||
loop {
|
loop {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue