mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-05 06:00:30 -04:00
power: Simplify GPU power profiles parsing with regex
This commit is contained in:
parent
f939767867
commit
fd6d9cbfe0
3 changed files with 31 additions and 27 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1014,8 +1014,10 @@ dependencies = [
|
||||||
"config",
|
"config",
|
||||||
"inotify",
|
"inotify",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"nix",
|
"nix",
|
||||||
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"strum",
|
"strum",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
|
@ -16,9 +16,11 @@ async-trait = "0.1"
|
||||||
clap = { version = "4.5", default-features = false, features = ["derive", "help", "std", "usage"] }
|
clap = { version = "4.5", default-features = false, features = ["derive", "help", "std", "usage"] }
|
||||||
config = { version = "0.14", default-features = false, features = ["async", "toml"] }
|
config = { version = "0.14", default-features = false, features = ["async", "toml"] }
|
||||||
inotify = { version = "0.10", default-features = false, features = ["stream"] }
|
inotify = { version = "0.10", default-features = false, features = ["stream"] }
|
||||||
|
lazy_static = "1"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
nix = { version = "0.29", default-features = false, features = ["fs", "poll", "signal"] }
|
nix = { version = "0.29", default-features = false, features = ["fs", "poll", "signal"] }
|
||||||
|
regex = "1"
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||||
tokio = { version = "1", default-features = false, features = ["fs", "io-std", "io-util", "macros", "process", "rt-multi-thread", "signal", "sync"] }
|
tokio = { version = "1", default-features = false, features = ["fs", "io-std", "io-util", "macros", "process", "rt-multi-thread", "signal", "sync"] }
|
||||||
tokio-stream = { version = "0.1", default-features = false }
|
tokio-stream = { version = "0.1", default-features = false }
|
||||||
|
|
54
src/power.rs
54
src/power.rs
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Result};
|
use anyhow::{anyhow, bail, ensure, Result};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -33,9 +35,13 @@ const CPU_SCALING_AVAILABLE_GOVERNORS_SUFFIX: &str = "scaling_available_governor
|
||||||
const TDP_LIMIT1: &str = "power1_cap";
|
const TDP_LIMIT1: &str = "power1_cap";
|
||||||
const TDP_LIMIT2: &str = "power2_cap";
|
const TDP_LIMIT2: &str = "power2_cap";
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref GPU_POWER_PROFILE_REGEX: Regex =
|
||||||
|
Regex::new(r"^\s*(?<value>[0-9]+)\s+(?<name>[0-9A-Za-z_]+)(?<active>\*)?").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Display, EnumString, PartialEq, Debug, Copy, Clone)]
|
#[derive(Display, EnumString, PartialEq, Debug, Copy, Clone)]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
#[repr(u32)]
|
|
||||||
pub enum GPUPowerProfile {
|
pub enum GPUPowerProfile {
|
||||||
// Currently firmware exposes these values, though
|
// Currently firmware exposes these values, though
|
||||||
// deck doesn't support them yet
|
// deck doesn't support them yet
|
||||||
|
@ -167,27 +173,23 @@ pub(crate) async fn get_gpu_power_profile() -> Result<GPUPowerProfile> {
|
||||||
// firmware support setting the value to no-op values.
|
// firmware support setting the value to no-op values.
|
||||||
let lines = contents.lines();
|
let lines = contents.lines();
|
||||||
for line in lines {
|
for line in lines {
|
||||||
let mut words = line.split_whitespace();
|
let caps = GPU_POWER_PROFILE_REGEX.captures(line);
|
||||||
let value: u32 = match words.next() {
|
let caps = match caps {
|
||||||
Some(v) => v
|
Some(caps) => caps,
|
||||||
.parse()
|
None => continue,
|
||||||
.map_err(|message| anyhow!("Unable to parse value from sysfs {message}"))?,
|
|
||||||
None => bail!("Unable to get value from sysfs"),
|
|
||||||
};
|
};
|
||||||
let name = match words.next() {
|
|
||||||
Some(v) => v.to_string(),
|
let name = &caps["name"].to_lowercase();
|
||||||
None => bail!("Unable to get name from sysfs"),
|
if caps.name("active").is_some() {
|
||||||
};
|
match GPUPowerProfile::from_str(name.as_str()) {
|
||||||
if name.ends_with('*') {
|
|
||||||
match GPUPowerProfile::try_from(value) {
|
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
return Ok(v);
|
return Ok(v);
|
||||||
}
|
}
|
||||||
Err(e) => bail!("Unable to parse value for gpu power profile {e}"),
|
Err(e) => bail!("Unable to parse value for GPU power profile: {e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bail!("Unable to determine current gpu power profile");
|
bail!("Unable to determine current GPU power profile");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_gpu_power_profiles() -> Result<HashMap<u32, String>> {
|
pub(crate) async fn get_gpu_power_profiles() -> Result<HashMap<u32, String>> {
|
||||||
|
@ -197,29 +199,27 @@ pub(crate) async fn get_gpu_power_profiles() -> Result<HashMap<u32, String>> {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
let lines = contents.lines();
|
let lines = contents.lines();
|
||||||
for line in lines {
|
for line in lines {
|
||||||
let mut words = line.split_whitespace();
|
let caps = GPU_POWER_PROFILE_REGEX.captures(line);
|
||||||
let value: u32 = match words.next() {
|
let caps = match caps {
|
||||||
Some(v) => v
|
Some(caps) => caps,
|
||||||
.parse()
|
None => continue,
|
||||||
.map_err(|message| anyhow!("Unable to parse value from sysfs {message}"))?,
|
|
||||||
None => bail!("Unable to get value from sysfs"),
|
|
||||||
};
|
|
||||||
let name = match words.next() {
|
|
||||||
Some(v) => v.to_string().replace('*', ""),
|
|
||||||
None => bail!("Unable to get name from sysfs"),
|
|
||||||
};
|
};
|
||||||
|
let value: u32 = caps["value"]
|
||||||
|
.parse()
|
||||||
|
.map_err(|message| anyhow!("Unable to parse value for GPU power profile: {message}"))?;
|
||||||
|
let name = &caps["name"];
|
||||||
if deck {
|
if deck {
|
||||||
// Deck is designed to operate in one of the CAPPED or UNCAPPED power profiles,
|
// Deck is designed to operate in one of the CAPPED or UNCAPPED power profiles,
|
||||||
// the other profiles aren't correctly tuned for the hardware.
|
// the other profiles aren't correctly tuned for the hardware.
|
||||||
if value == GPUPowerProfile::Capped as u32 || value == GPUPowerProfile::Uncapped as u32
|
if value == GPUPowerProfile::Capped as u32 || value == GPUPowerProfile::Uncapped as u32
|
||||||
{
|
{
|
||||||
map.insert(value, name);
|
map.insert(value, name.to_string());
|
||||||
} else {
|
} else {
|
||||||
// Got unsupported value, so don't include it
|
// Got unsupported value, so don't include it
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Do basic validation to ensure our enum is up to date?
|
// Do basic validation to ensure our enum is up to date?
|
||||||
map.insert(value, name);
|
map.insert(value, name.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(map)
|
Ok(map)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue