Refactor steam_deck to modularize system interactions

This commit is contained in:
NGnius (Graham) 2023-05-25 21:03:13 -04:00
parent 23d6e49491
commit f8ea999604
21 changed files with 329 additions and 280 deletions

2
backend/Cargo.lock generated
View file

@ -799,7 +799,7 @@ dependencies = [
[[package]]
name = "limits_core"
version = "1.0.0"
version = "2.0.0"
dependencies = [
"serde",
"serde_json",

View file

@ -25,7 +25,7 @@ log = "0.4"
simplelog = "0.12"
# limits & driver functionality
limits_core = { version = "1.0.0", path = "./limits_core" }
limits_core = { version = "2", path = "./limits_core" }
regex = "1"
libryzenadj = { version = "0.12" }
# ureq's tls feature does not like musl targets

View file

@ -10,7 +10,7 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "limits_core"
version = "1.0.0"
version = "2.0.0"
dependencies = [
"serde",
"serde_json",

View file

@ -1,6 +1,6 @@
[package]
name = "limits_core"
version = "1.0.0"
version = "2.0.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -57,16 +57,16 @@ impl Default for Base {
},
limits: vec![
super::Limits::Cpu(super::CpuLimit::GenericAMD(super::GenericCpuLimit {
clock_min: Some(super::RangeLimit { min: 1000, max: 3700 }),
clock_max: Some(super::RangeLimit { min: 1000, max: 3700 }),
clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(3700) }),
clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(3700) }),
clock_step: 100,
})),
super::Limits::Gpu(super::GpuLimit::GenericAMD(super::GenericGpuLimit {
fast_ppt: Some(super::RangeLimit { min: 1_000_000, max: 25_000_000 }),
slow_ppt: Some(super::RangeLimit { min: 1_000_000, max: 25_000_000 }),
fast_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(25_000_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(25_000_000) }),
ppt_step: Some(1_000_000),
clock_min: Some(super::RangeLimit { min: 400, max: 1100 }),
clock_max: Some(super::RangeLimit { min: 400, max: 1100 }),
clock_min: Some(super::RangeLimit { min: Some(400), max: Some(1100) }),
clock_max: Some(super::RangeLimit { min: Some(400), max: Some(1100) }),
clock_step: Some(100),
..Default::default()
})),
@ -84,16 +84,16 @@ impl Default for Base {
},
limits: vec![
super::Limits::Cpu(super::CpuLimit::GenericAMD(super::GenericCpuLimit {
clock_min: Some(super::RangeLimit { min: 1000, max: 4000 }),
clock_max: Some(super::RangeLimit { min: 1000, max: 4000 }),
clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(4000) }),
clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(4000) }),
clock_step: 100,
})),
super::Limits::Gpu(super::GpuLimit::GenericAMD(super::GenericGpuLimit {
fast_ppt: Some(super::RangeLimit { min: 1_000_000, max: 25_000_000 }),
slow_ppt: Some(super::RangeLimit { min: 1_000_000, max: 25_000_000 }),
fast_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(25_000_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(25_000_000) }),
ppt_step: Some(1_000_000),
clock_min: Some(super::RangeLimit { min: 400, max: 1600 }),
clock_max: Some(super::RangeLimit { min: 400, max: 1600 }),
clock_min: Some(super::RangeLimit { min: Some(400), max: Some(1600) }),
clock_max: Some(super::RangeLimit { min: Some(400), max: Some(1600) }),
clock_step: Some(100),
..Default::default()
})),
@ -111,16 +111,16 @@ impl Default for Base {
},
limits: vec![
super::Limits::Cpu(super::CpuLimit::GenericAMD(super::GenericCpuLimit {
clock_min: Some(super::RangeLimit { min: 1000, max: 4500 }),
clock_max: Some(super::RangeLimit { min: 1000, max: 4500 }),
clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(4500) }),
clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(4500) }),
clock_step: 100,
})),
super::Limits::Gpu(super::GpuLimit::GenericAMD(super::GenericGpuLimit {
fast_ppt: Some(super::RangeLimit { min: 1_000_000, max: 25_000_000 }),
slow_ppt: Some(super::RangeLimit { min: 1_000_000, max: 25_000_000 }),
fast_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(25_000_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(25_000_000) }),
ppt_step: Some(1_000_000),
clock_min: Some(super::RangeLimit { min: 400, max: 2000 }),
clock_max: Some(super::RangeLimit { min: 400, max: 2000 }),
clock_min: Some(super::RangeLimit { min: Some(400), max: Some(2000) }),
clock_max: Some(super::RangeLimit { min: Some(400), max: Some(2000) }),
clock_step: Some(100),
..Default::default()
})),
@ -138,16 +138,16 @@ impl Default for Base {
},
limits: vec![
super::Limits::Cpu(super::CpuLimit::Generic(super::GenericCpuLimit {
clock_min: Some(super::RangeLimit { min: 1000, max: 4700 }),
clock_max: Some(super::RangeLimit { min: 1000, max: 4700 }),
clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(4700) }),
clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(4700) }),
clock_step: 100,
})),
super::Limits::Gpu(super::GpuLimit::Generic(super::GenericGpuLimit {
fast_ppt: Some(super::RangeLimit { min: 1_000_000, max: 28_000_000 }),
slow_ppt: Some(super::RangeLimit { min: 1_000_000, max: 28_000_000 }),
fast_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(28_000_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000_000), max: Some(28_000_000) }),
ppt_step: Some(1_000_000),
clock_min: Some(super::RangeLimit { min: 400, max: 2200 }),
clock_max: Some(super::RangeLimit { min: 400, max: 2200 }),
clock_min: Some(super::RangeLimit { min: Some(400), max: Some(2200) }),
clock_max: Some(super::RangeLimit { min: Some(400), max: Some(2200) }),
clock_step: Some(100),
..Default::default()
})),

View file

@ -3,6 +3,6 @@ use serde::{Deserialize, Serialize};
/// Base JSON limits information
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RangeLimit<T> {
pub min: T,
pub max: T,
pub min: Option<T>,
pub max: Option<T>,
}

View file

@ -1,12 +1,12 @@
[package]
name = "limits_srv"
version = "1.0.0"
version = "2.0.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
limits_core = { version = "1.0.0", path = "../limits_core" }
limits_core = { version = "2.0.0", path = "../limits_core" }
chrono = { version = "0.4" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View file

@ -1,18 +1,14 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RangeLimit<T> {
pub min: T,
pub max: T,
}
impl<T> From<limits_core::json::RangeLimit<T>> for RangeLimit<T> {
#[inline]
fn from(other: limits_core::json::RangeLimit<T>) -> Self {
RangeLimit {
min: other.min,
max: other.max,
}
impl<T> RangeLimit<T> {
pub fn new(min: T, max: T) -> Self {
Self { min, max }
}
}

View file

@ -6,6 +6,7 @@ use usdpl_back::AsyncCallable;
use crate::settings::{MinMax, SettingError, SettingVariant};
//use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use super::handler::{ApiMessage, CpuMessage};
use super::utility::map_optional;
/// Available CPUs web method
pub fn max_cpus(_: super::ApiParameterType) -> super::ApiParameterType {
@ -205,8 +206,8 @@ pub fn set_clock_limits(
setter(
index as usize,
MinMax {
min: safe_min as u64,
max: safe_max as u64,
min: Some(safe_min as u64),
max: Some(safe_max as u64),
},
);
vec![safe_min.into(), safe_max.into()]
@ -220,6 +221,7 @@ pub fn set_clock_limits(
vec!["set_clock_limits missing parameter 0".into()]
}
}
// TODO allow param 0 and/or 1 to be Primitive::Empty
}
pub fn get_clock_limits(
@ -245,7 +247,7 @@ pub fn get_clock_limits(
move |params_in: super::ApiParameterType| {
if let Some(&Primitive::F64(index)) = params_in.get(0) {
if let Some(min_max) = getter(index as usize) {
vec![min_max.min.into(), min_max.max.into()]
vec![map_optional(min_max.min), map_optional(min_max.max)]
} else {
vec![Primitive::Empty, Primitive::Empty]
}

View file

@ -3,6 +3,7 @@ use std::sync::{Arc, Mutex};
use usdpl_back::core::serdes::Primitive;
use usdpl_back::AsyncCallable;
use super::utility::map_optional;
use crate::settings::MinMax;
//use crate::utility::{unwrap_lock, unwrap_maybe_fatal};
use super::handler::{ApiMessage, GpuMessage};
@ -94,8 +95,8 @@ pub fn set_clock_limits(
let safe_max = if max < min { min } else { max };
let safe_min = if min > max { max } else { min };
setter(MinMax {
min: safe_min as _,
max: safe_max as _,
min: Some(safe_min as _),
max: Some(safe_max as _),
});
vec![(safe_min as u64).into(), (safe_max as u64).into()]
} else {
@ -105,6 +106,7 @@ pub fn set_clock_limits(
vec!["set_clock_limits missing parameter 0".into()]
}
}
// TODO allow param 0 and/or 1 to be Primitive::Empty
}
pub fn get_clock_limits(sender: Sender<ApiMessage>) -> impl AsyncCallable {
@ -131,7 +133,7 @@ pub fn get_clock_limits(sender: Sender<ApiMessage>) -> impl AsyncCallable {
set_get: getter,
trans_getter: |clocks: Option<MinMax<u64>>| {
clocks
.map(|x| vec![x.min.into(), x.max.into()])
.map(|x| vec![map_optional(x.min), map_optional(x.max)])
.unwrap_or_else(|| vec![Primitive::Empty, Primitive::Empty])
},
}

View file

@ -268,7 +268,9 @@ impl ApiMessageHandler {
while let Ok(msg) = self.intake.try_recv() {
dirty |= self.process(settings, msg);
}
if dirty /*|| dirty_echo */ {
if dirty
/*|| dirty_echo */
{
//dirty_echo = dirty; // echo only once
// run on_set

View file

@ -19,10 +19,7 @@ pub fn map_optional_result<T: Into<Primitive>>(
result: Result<Option<T>, SettingError>,
) -> super::ApiParameterType {
match result {
Ok(val) => match val {
Some(val) => vec![val.into()],
None => vec![Primitive::Empty],
},
Ok(val) => vec![map_optional(val)],
Err(e) => {
log::debug!("Mapping error to primitive: {}", e);
vec![e.msg.into()]
@ -30,6 +27,13 @@ pub fn map_optional_result<T: Into<Primitive>>(
}
}
pub fn map_optional<T: Into<Primitive>>(option: Option<T>) -> Primitive {
match option {
Some(val) => val.into(),
None => Primitive::Empty,
}
}
/*#[inline]
pub fn map_empty_result<T: Into<Primitive>>(
result: Result<(), SettingError>,

View file

@ -58,6 +58,6 @@ impl SettingsJson {
#[derive(Serialize, Deserialize, Clone)]
pub struct MinMaxJson<T> {
pub max: T,
pub min: T,
pub max: Option<T>,
pub min: Option<T>,
}

View file

@ -3,6 +3,7 @@ use std::convert::{AsMut, AsRef, Into};
use limits_core::json::GenericCpuLimit;
use super::FromGenericCpuInfo;
use crate::api::RangeLimit;
use crate::persist::CpuJson;
use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError};
@ -330,8 +331,16 @@ impl Cpu {
fn limits(&self) -> crate::api::CpuLimits {
crate::api::CpuLimits {
clock_min_limits: self.limits.clock_min.clone().map(|x| x.into()),
clock_max_limits: self.limits.clock_max.clone().map(|x| x.into()),
clock_min_limits: self
.limits
.clock_min
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(5_000))),
clock_max_limits: self
.limits
.clock_max
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(5_000))),
clock_step: self.limits.clock_step,
governors: self.governors(),
}

View file

@ -2,6 +2,7 @@ use std::convert::Into;
use limits_core::json::GenericGpuLimit;
use crate::api::RangeLimit;
use crate::persist::GpuJson;
use crate::settings::TGpu;
use crate::settings::{min_max_from_json, MinMax};
@ -97,14 +98,38 @@ impl crate::settings::OnPowerEvent for Gpu {}
impl TGpu for Gpu {
fn limits(&self) -> crate::api::GpuLimits {
crate::api::GpuLimits {
fast_ppt_limits: self.limits.fast_ppt.clone().map(|x| x.into()),
slow_ppt_limits: self.limits.slow_ppt.clone().map(|x| x.into()),
fast_ppt_limits: self
.limits
.fast_ppt
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
slow_ppt_limits: self
.limits
.slow_ppt
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
ppt_step: self.limits.ppt_step.unwrap_or(1_000_000),
tdp_limits: self.limits.tdp.clone().map(|x| x.into()),
tdp_boost_limits: self.limits.tdp_boost.clone().map(|x| x.into()),
tdp_limits: self
.limits
.tdp
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
tdp_boost_limits: self
.limits
.tdp_boost
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
tdp_step: self.limits.tdp_step.unwrap_or(42),
clock_min_limits: self.limits.clock_min.clone().map(|x| x.into()),
clock_max_limits: self.limits.clock_max.clone().map(|x| x.into()),
clock_min_limits: self
.limits
.clock_min
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))),
clock_max_limits: self
.limits
.clock_max
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))),
clock_step: self.limits.clock_step.unwrap_or(100),
memory_control_capable: false,
}
@ -116,10 +141,20 @@ impl TGpu for Gpu {
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
if let Some(fast_lims) = &self.limits.fast_ppt {
self.fast_ppt = fast.map(|x| x.clamp(fast_lims.min, fast_lims.max));
self.fast_ppt = fast.map(|x| {
x.clamp(
fast_lims.min.unwrap_or(0),
fast_lims.max.unwrap_or(u64::MAX),
)
});
}
if let Some(slow_lims) = &self.limits.slow_ppt {
self.slow_ppt = slow.map(|x| x.clamp(slow_lims.min, slow_lims.max));
self.slow_ppt = slow.map(|x| {
x.clamp(
slow_lims.min.unwrap_or(0),
slow_lims.max.unwrap_or(u64::MAX),
)
});
}
}

View file

@ -128,24 +128,22 @@ impl Gpu {
}
if let Some(clock_limits) = &self.generic.clock_limits {
self.state.clock_limits_set = true;
lock.set_max_gfxclk_freq(clock_limits.max as _)
.map_err(|e| SettingError {
msg: format!(
"RyzenAdj set_max_gfxclk_freq({}) err: {}",
clock_limits.max, e
),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
lock.set_min_gfxclk_freq(clock_limits.min as _)
.map_err(|e| SettingError {
msg: format!(
"RyzenAdj set_min_gfxclk_freq({}) err: {}",
clock_limits.min, e
),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
if let Some(max) = clock_limits.max {
lock.set_max_gfxclk_freq(max as _)
.map_err(|e| SettingError {
msg: format!("RyzenAdj set_max_gfxclk_freq({}) err: {}", max, e),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
}
if let Some(min) = clock_limits.min {
lock.set_min_gfxclk_freq(min as _)
.map_err(|e| SettingError {
msg: format!("RyzenAdj set_min_gfxclk_freq({}) err: {}", min, e),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
}
} else if self.state.clock_limits_set {
self.state.clock_limits_set = false;
let limits = self.generic.limits();
@ -218,24 +216,22 @@ impl Gpu {
.unwrap_or_else(|e| errors.push(e));
}
if let Some(clock_limits) = &self.generic.clock_limits {
lock.set_max_gfxclk_freq(clock_limits.max as _)
.map_err(|e| SettingError {
msg: format!(
"RyzenAdj set_max_gfxclk_freq({}) err: {}",
clock_limits.max, e
),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
lock.set_min_gfxclk_freq(clock_limits.min as _)
.map_err(|e| SettingError {
msg: format!(
"RyzenAdj set_min_gfxclk_freq({}) err: {}",
clock_limits.min, e
),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
if let Some(max) = clock_limits.max {
lock.set_max_gfxclk_freq(max as _)
.map_err(|e| SettingError {
msg: format!("RyzenAdj set_max_gfxclk_freq({}) err: {}", max, e),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
}
if let Some(min) = clock_limits.min {
lock.set_min_gfxclk_freq(min as _)
.map_err(|e| SettingError {
msg: format!("RyzenAdj set_min_gfxclk_freq({}) err: {}", min, e),
setting: SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
}
}
Ok(())
}

View file

@ -8,8 +8,8 @@ pub type MinMax<T> = RangeLimit<T>;
pub fn min_max_from_json<T, X: Into<T>>(other: MinMaxJson<X>, _version: u64) -> MinMax<T> {
MinMax {
max: other.max.into(),
min: other.min.into(),
max: other.max.map(|x| x.into()),
min: other.min.map(|x| x.into()),
}
}
@ -17,8 +17,8 @@ impl<X: Into<Y>, Y> Into<MinMaxJson<Y>> for RangeLimit<X> {
#[inline]
fn into(self) -> MinMaxJson<Y> {
MinMaxJson {
max: self.max.into(),
min: self.min.into(),
max: self.max.map(|x| x.into()),
min: self.min.map(|x| x.into()),
}
}
}

View file

@ -99,12 +99,12 @@ impl EventInstruction {
.trim_start_matches('>')
.parse::<f64>()
.ok()
.map(|x| EventTrigger::BatteryAbove(x/100.0)),
.map(|x| EventTrigger::BatteryAbove(x / 100.0)),
s if s.starts_with('<') => s
.trim_start_matches('<')
.parse::<f64>()
.ok()
.map(|x| EventTrigger::BatteryBelow(x/100.0)),
.map(|x| EventTrigger::BatteryBelow(x / 100.0)),
_ => None,
}
}
@ -244,6 +244,30 @@ impl Battery {
}
}
fn set_charge_rate(&mut self) -> Result<(), SettingError> {
if let Some(charge_rate) = self.charge_rate {
self.state.charge_rate_set = true;
usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, charge_rate).map_err(
|e| SettingError {
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
setting: crate::settings::SettingVariant::Battery,
},
)
} else if self.state.charge_rate_set {
self.state.charge_rate_set = false;
usdpl_back::api::files::write_single(
BATTERY_CHARGE_RATE_PATH,
self.limits.charge_rate.max,
)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
setting: crate::settings::SettingVariant::Battery,
})
} else {
Ok(())
}
}
fn set_charge_mode(&mut self) -> Result<(), SettingError> {
if let Some(charge_mode) = self.charge_mode {
self.state.charge_mode_set = true;
@ -268,26 +292,7 @@ impl Battery {
fn set_all(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
if let Some(charge_rate) = self.charge_rate {
self.state.charge_rate_set = true;
usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, charge_rate)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
setting: crate::settings::SettingVariant::Battery,
})
.unwrap_or_else(|e| errors.push(e));
} else if self.state.charge_rate_set {
self.state.charge_rate_set = false;
usdpl_back::api::files::write_single(
BATTERY_CHARGE_RATE_PATH,
self.limits.charge_rate.max,
)
.map_err(|e| SettingError {
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
setting: crate::settings::SettingVariant::Battery,
})
.unwrap_or_else(|e| errors.push(e));
}
self.set_charge_rate().unwrap_or_else(|e| errors.push(e));
self.set_charge_mode().unwrap_or_else(|e| errors.push(e));
if errors.is_empty() {
Ok(())

View file

@ -234,6 +234,11 @@ pub struct Cpu {
const CPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
enum ClockType {
Min = 0,
Max = 1,
}
impl Cpu {
#[inline]
fn from_json(other: CpuJson, version: u64, i: usize, oc_limits: CpuLimits) -> Self {
@ -257,86 +262,91 @@ impl Cpu {
}
}
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
fn set_clock_limit(index: usize, speed: u64, mode: ClockType) -> Result<(), SettingError> {
let payload = format!("p {} {} {}\n", index / 2, mode as u8, speed);
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload).map_err(|e| {
SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload, CPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Cpu,
}
})
}
// set clock limits
//log::debug!("Setting {} to manual", CPU_FORCE_LIMITS_PATH);
//let mode: String = usdpl_back::api::files::read_single(CPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
fn set_clock_limits(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
if let Some(clock_limits) = &self.clock_limits {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(true, self.index);
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
log::debug!(
"Setting CPU {} (min, max) clockspeed to ({}, {})",
"Setting CPU {} (min, max) clockspeed to ({:?}, {:?})",
self.index,
clock_limits.min,
clock_limits.max
);
self.state.clock_limits_set = true;
// max clock
let payload_max = format!("p {} 1 {}\n", self.index / 2, clock_limits.max);
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_max, CPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Cpu,
})
.unwrap_or_else(|e| errors.push(e));
if let Some(max) = clock_limits.max {
Self::set_clock_limit(self.index, max, ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
}
// min clock
let valid_min = if clock_limits.min < self.limits.clock_min.min {
self.limits.clock_min.min
if let Some(min) = clock_limits.min {
let valid_min = if min < self.limits.clock_min.min {
self.limits.clock_min.min
} else {
min
};
Self::set_clock_limit(self.index, valid_min, ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
}
if errors.is_empty() {
Ok(())
} else {
clock_limits.min
};
let payload_min = format!("p {} 0 {}\n", self.index / 2, valid_min);
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_min, CPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Cpu,
})
.unwrap_or_else(|e| errors.push(e));
Err(errors)
}
} else if self.state.clock_limits_set
|| (self.state.is_resuming && !self.limits.skip_resume_reclock)
|| POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual()
{
let mut errors = Vec::new();
self.state.clock_limits_set = false;
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(false, self.index);
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
// disable manual clock limits
log::debug!("Setting CPU {} to default clockspeed", self.index);
// max clock
let payload_max = format!("p {} 1 {}\n", self.index / 2, self.limits.clock_max.max);
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_max, CPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Cpu,
})
Self::set_clock_limit(self.index, self.limits.clock_max.max, ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
// min clock
let payload_min = format!("p {} 0 {}\n", self.index / 2, self.limits.clock_min.min);
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_min, CPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Cpu,
})
Self::set_clock_limit(self.index, self.limits.clock_min.min, ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
}
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_cpu(false, self.index);
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level()
.unwrap_or_else(|mut e| errors.append(&mut e));
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
} else {
Ok(())
}
}
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
// set clock limits
//log::debug!("Setting {} to manual", CPU_FORCE_LIMITS_PATH);
//let mode: String = usdpl_back::api::files::read_single(CPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
self.set_clock_limits()
.unwrap_or_else(|mut e| errors.append(&mut e));
// commit changes (if no errors have already occured)
if errors.is_empty() {
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
@ -354,6 +364,23 @@ impl Cpu {
}
}
fn set_governor(&self) -> Result<(), SettingError> {
if self.index == 0 || self.online {
let governor_path = cpu_governor_path(self.index);
usdpl_back::api::files::write_single(&governor_path, &self.governor).map_err(|e| {
SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&self.governor, &governor_path, e
),
setting: crate::settings::SettingVariant::Cpu,
}
})
} else {
Ok(())
}
}
fn set_all(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
// set cpu online/offline
@ -371,19 +398,8 @@ impl Cpu {
self.set_force_performance_related()
.unwrap_or_else(|mut e| errors.append(&mut e));
// set governor
if self.index == 0 || self.online {
let governor_path = cpu_governor_path(self.index);
usdpl_back::api::files::write_single(&governor_path, &self.governor)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&self.governor, &governor_path, e
),
setting: crate::settings::SettingVariant::Cpu,
})
.unwrap_or_else(|e| errors.push(e));
}
self.set_governor().unwrap_or_else(|e| errors.push(e));
if errors.is_empty() {
Ok(())
} else {
@ -393,12 +409,14 @@ impl Cpu {
fn clamp_all(&mut self) {
if let Some(clock_limits) = &mut self.clock_limits {
clock_limits.min = clock_limits
.min
.clamp(self.limits.clock_min.min, self.limits.clock_min.max);
clock_limits.max = clock_limits
.max
.clamp(self.limits.clock_max.min, self.limits.clock_max.max);
if let Some(min) = clock_limits.min {
clock_limits.min =
Some(min.clamp(self.limits.clock_min.min, self.limits.clock_min.max));
}
if let Some(max) = clock_limits.max {
clock_limits.max =
Some(max.clamp(self.limits.clock_max.min, self.limits.clock_max.max));
}
}
}

View file

@ -26,6 +26,11 @@ pub struct Gpu {
const GPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
const GPU_MEMORY_DOWNCLOCK_PATH: &str = "/sys/class/drm/card0/device/pp_dpm_fclk";
enum ClockType {
Min = 0,
Max = 1,
}
impl Gpu {
#[inline]
pub fn from_json(other: GpuJson, version: u64) -> Self {
@ -57,6 +62,28 @@ impl Gpu {
}
}
fn set_clock_limit(speed: u64, mode: ClockType) -> Result<(), SettingError> {
let payload = format!("s {} {}\n", mode as u8, speed);
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload).map_err(|e| {
SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload, GPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Gpu,
}
})
}
fn set_confirm() -> Result<(), SettingError> {
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| {
SettingError {
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
setting: crate::settings::SettingVariant::Gpu,
}
})
}
fn set_clocks(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
if let Some(clock_limits) = &self.clock_limits {
@ -65,81 +92,37 @@ impl Gpu {
// set clock limits
self.state.clock_limits_set = true;
// max clock
let payload_max = format!("s 1 {}\n", clock_limits.max);
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_max, GPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
if let Some(max) = clock_limits.max {
Self::set_clock_limit(max, ClockType::Max).unwrap_or_else(|e| errors.push(e));
}
// min clock
let payload_min = format!("s 0 {}\n", clock_limits.min);
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_min, GPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Gpu,
})
.unwrap_or_else(|e| errors.push(e));
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").unwrap_or_else(
|e| {
errors.push(SettingError {
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
setting: crate::settings::SettingVariant::Gpu,
})
},
);
if let Some(min) = clock_limits.min {
Self::set_clock_limit(min, ClockType::Min).unwrap_or_else(|e| errors.push(e));
}
Self::set_confirm().unwrap_or_else(|e| errors.push(e));
} else if self.state.clock_limits_set
|| (self.state.is_resuming && !self.limits.skip_resume_reclock)
|| POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual()
{
self.state.clock_limits_set = false;
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.slow_memory);
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level()?;
// disable manual clock limits
// max clock
let payload_max = format!("s 1 {}\n", self.limits.clock_max.max);
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_max, GPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Gpu,
})
Self::set_clock_limit(self.limits.clock_max.max, ClockType::Max)
.unwrap_or_else(|e| errors.push(e));
// min clock
let payload_min = format!("s 0 {}\n", self.limits.clock_min.min);
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min)
.map_err(|e| SettingError {
msg: format!(
"Failed to write `{}` to `{}`: {}",
&payload_min, GPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Gpu,
})
Self::set_clock_limit(self.limits.clock_min.min, ClockType::Min)
.unwrap_or_else(|e| errors.push(e));
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").unwrap_or_else(
|e| {
errors.push(SettingError {
msg: format!(
"Failed to write `c` to `{}`: {}",
GPU_CLOCK_LIMITS_PATH, e
),
setting: crate::settings::SettingVariant::Gpu,
})
},
);
Self::set_confirm().unwrap_or_else(|e| errors.push(e));
} else {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level()
.unwrap_or_else(|mut e| errors.append(&mut e));
}
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.slow_memory);
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level()
.unwrap_or_else(|mut e| errors.append(&mut e));
}
if errors.is_empty() {
Ok(())
@ -148,6 +131,15 @@ impl Gpu {
}
}
fn set_slow_memory(slow: bool) -> Result<(), SettingError> {
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, slow as u8).map_err(|e| {
SettingError {
msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e),
setting: crate::settings::SettingVariant::Gpu,
}
})
}
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
let mut errors = Vec::new();
// enable/disable downclock of GPU memory (to 400Mhz?)
@ -156,21 +148,9 @@ impl Gpu {
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level()
.unwrap_or_else(|mut e| errors.append(&mut e));
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8)
.unwrap_or_else(|e| {
errors.push(SettingError {
msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e),
setting: crate::settings::SettingVariant::Gpu,
});
});
Self::set_slow_memory(self.slow_memory).unwrap_or_else(|e| errors.push(e));
} else if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8)
.unwrap_or_else(|e| {
errors.push(SettingError {
msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e),
setting: crate::settings::SettingVariant::Gpu,
});
});
Self::set_slow_memory(self.slow_memory).unwrap_or_else(|e| errors.push(e));
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.clock_limits.is_some());
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
.enforce_level()
@ -181,11 +161,9 @@ impl Gpu {
// commit changes (if no errors have already occured)
if errors.is_empty() {
if self.slow_memory || self.clock_limits.is_some() {
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| {
vec![SettingError {
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
setting: crate::settings::SettingVariant::Gpu,
}]
Self::set_confirm().map_err(|e| {
errors.push(e);
errors
})
} else {
Ok(())
@ -276,12 +254,14 @@ impl Gpu {
*slow_ppt = (*slow_ppt).clamp(self.limits.slow_ppt.min, self.limits.slow_ppt.max);
}
if let Some(clock_limits) = &mut self.clock_limits {
clock_limits.min = clock_limits
.min
.clamp(self.limits.clock_min.min, self.limits.clock_min.max);
clock_limits.max = clock_limits
.max
.clamp(self.limits.clock_max.min, self.limits.clock_max.max);
if let Some(min) = clock_limits.min {
clock_limits.min =
Some(min.clamp(self.limits.clock_min.min, self.limits.clock_min.max));
}
if let Some(max) = clock_limits.max {
clock_limits.max =
Some(max.clamp(self.limits.clock_max.min, self.limits.clock_max.max));
}
}
}

View file

@ -1,4 +1,4 @@
use crate::settings::MinMax;
use crate::api::RangeLimit as MinMax;
use serde::{Deserialize, Serialize};
const OC_LIMITS_FILEPATH: &str = "pt_oc.json";