diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 4da9134..04fb53e 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -808,7 +808,7 @@ dependencies = [ [[package]] name = "limits_core" -version = "2.0.1" +version = "3.0.0" dependencies = [ "serde", "serde_json", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 2f48805..382f3de 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -26,7 +26,7 @@ log = "0.4" simplelog = "0.12" # limits & driver functionality -limits_core = { version = "2", path = "./limits_core" } +limits_core = { version = "3", path = "./limits_core" } regex = "1" libryzenadj = { version = "0.12" } # ureq's tls feature does not like musl targets diff --git a/backend/limits_core/Cargo.lock b/backend/limits_core/Cargo.lock index a3d5955..1fa968e 100644 --- a/backend/limits_core/Cargo.lock +++ b/backend/limits_core/Cargo.lock @@ -10,7 +10,7 @@ checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "limits_core" -version = "2.0.1" +version = "3.0.0" dependencies = [ "serde", "serde_json", diff --git a/backend/limits_core/Cargo.toml b/backend/limits_core/Cargo.toml index 7d2f721..8f6db2c 100644 --- a/backend/limits_core/Cargo.toml +++ b/backend/limits_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "limits_core" -version = "2.0.1" +version = "3.0.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/backend/limits_core/src/json_v2/base.rs b/backend/limits_core/src/json_v2/base.rs new file mode 100644 index 0000000..81643d9 --- /dev/null +++ b/backend/limits_core/src/json_v2/base.rs @@ -0,0 +1,267 @@ +use std::default::Default; +use serde::{Deserialize, Serialize}; + +/// Base JSON limits information +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Base { + /// System-specific configurations + pub configs: Vec, + /// Server messages + pub messages: Vec, + /// URL from which to grab the next update + pub refresh: Option, +} + +impl Default for Base { + fn default() -> Self { + Base { + configs: vec![ + super::Config { + name: "Steam Deck Custom".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t: AMD Custom APU 0405\n".to_owned()), + os: None, + command: None, + file_exists: Some("./limits_override.json".into()), + }, + limits: super::Limits { + cpu: super::Limit { + provider: super::CpuLimitType::SteamDeckAdvance, + limits: super::GenericCpusLimit::default_for(super::CpuLimitType::SteamDeckAdvance), + }, + gpu: super::Limit { + provider: super::GpuLimitType::SteamDeckAdvance, + limits: super::GenericGpuLimit::default_for(super::GpuLimitType::SteamDeckAdvance), + }, + battery: super::Limit { + provider: super::BatteryLimitType::SteamDeckAdvance, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::SteamDeckAdvance), + }, + } + }, + super::Config { + name: "Steam Deck".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t: AMD Custom APU 0405\n".to_owned()), + os: None, + command: None, + file_exists: None, + }, + limits: super::Limits { + cpu: super::Limit { + provider: super::CpuLimitType::SteamDeck, + limits: super::GenericCpusLimit::default_for(super::CpuLimitType::SteamDeck), + }, + gpu: super::Limit { + provider: super::GpuLimitType::SteamDeck, + limits: super::GenericGpuLimit::default_for(super::GpuLimitType::SteamDeck), + }, + battery: super::Limit { + provider: super::BatteryLimitType::SteamDeck, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::SteamDeck), + }, + } + }, + super::Config { + name: "AMD R3 2300U".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t+: AMD Ryzen 3 2300U\n".to_owned()), + os: None, + command: None, + file_exists: None, + }, + limits: super::Limits { + cpu: super::CpuLimit { + provider: super::CpuLimitType::GenericAMD, + limits: super::GenericCpusLimit { + cpus: vec![ + super::GenericCpuLimit { + clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(3700) }), + clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(3700) }), + clock_step: Some(100), + skip_resume_reclock: false, + }; 4], + global_governors: true, + } + }, + gpu: super::GpuLimit { + provider: super::GpuLimitType::GenericAMD, + limits: super::GenericGpuLimit { + 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: Some(400), max: Some(1100) }), + clock_max: Some(super::RangeLimit { min: Some(400), max: Some(1100) }), + clock_step: Some(100), + ..Default::default() + } + }, + battery: super::Limit { + provider: super::BatteryLimitType::Generic, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::Generic), + } + }, + }, + super::Config { + name: "AMD R5 5560U".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t+: AMD Ryzen 5 5560U\n".to_owned()), + os: None, + command: None, + file_exists: None, + }, + limits: super::Limits { + cpu: super::CpuLimit { + provider: super::CpuLimitType::GenericAMD, + limits: super::GenericCpusLimit { + cpus: vec![ + super::GenericCpuLimit { + clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(4000) }), + clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(4000) }), + clock_step: Some(100), + skip_resume_reclock: false, + }; 12], // 6 cores with SMTx2 + global_governors: true, + } + }, + gpu: super::GpuLimit { + provider: super::GpuLimitType::GenericAMD, + limits: super::GenericGpuLimit { + 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: Some(400), max: Some(1600) }), + clock_max: Some(super::RangeLimit { min: Some(400), max: Some(1600) }), + clock_step: Some(100), + ..Default::default() + } + }, + battery: super::Limit { + provider: super::BatteryLimitType::Generic, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::Generic), + } + } + }, + super::Config { + name: "AMD R7 5825U".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t+: AMD Ryzen 7 5825U\n".to_owned()), + os: None, + command: None, + file_exists: None, + }, + limits: super::Limits { + cpu: super::CpuLimit { + provider: super::CpuLimitType::GenericAMD, + limits: super::GenericCpusLimit { + cpus: vec![ + super::GenericCpuLimit { + clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(4500) }), + clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(4500) }), + clock_step: Some(100), + skip_resume_reclock: false, + }; 16], // 8 cores with SMTx2 + global_governors: true, + } + }, + gpu: super::GpuLimit { + provider: super::GpuLimitType::GenericAMD, + limits: super::GenericGpuLimit { + 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: Some(400), max: Some(2200) }), + clock_max: Some(super::RangeLimit { min: Some(400), max: Some(2200) }), + clock_step: Some(100), + ..Default::default() + } + }, + battery: super::Limit { + provider: super::BatteryLimitType::Generic, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::Generic), + } + } + }, + super::Config { + name: "AMD R7 6800U".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: Some("model name\t+: AMD Ryzen 7 6800U\n".to_owned()), + os: None, + command: None, + file_exists: None, + }, + limits: super::Limits { + cpu: super::CpuLimit { + provider: super::CpuLimitType::GenericAMD, + limits: super::GenericCpusLimit { + cpus: vec![ + super::GenericCpuLimit { + clock_min: Some(super::RangeLimit { min: Some(1000), max: Some(4700) }), + clock_max: Some(super::RangeLimit { min: Some(1000), max: Some(4700) }), + clock_step: Some(100), + skip_resume_reclock: false, + }; 16], // 8 cores with SMTx2 + global_governors: true, + } + }, + gpu: super::GpuLimit { + provider: super::GpuLimitType::GenericAMD, + limits: super::GenericGpuLimit { + 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: Some(400), max: Some(2200) }), + clock_max: Some(super::RangeLimit { min: Some(400), max: Some(2200) }), + clock_step: Some(100), + ..Default::default() + } + }, + battery: super::Limit { + provider: super::BatteryLimitType::Generic, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::Generic), + } + } + }, + super::Config { + name: "Fallback".to_owned(), + conditions: super::Conditions { + dmi: None, + cpuinfo: None, + os: None, + command: None, + file_exists: None, + }, + limits: super::Limits { + cpu: super::Limit { + provider: super::CpuLimitType::Unknown, + limits: super::GenericCpusLimit::default_for(super::CpuLimitType::Unknown), + }, + gpu: super::Limit { + provider: super::GpuLimitType::Unknown, + limits: super::GenericGpuLimit::default_for(super::GpuLimitType::Unknown), + }, + battery: super::Limit { + provider: super::BatteryLimitType::Unknown, + limits: super::GenericBatteryLimit::default_for(super::BatteryLimitType::Unknown), + } + } + } + ], + messages: vec![ + super::DeveloperMessage { + id: 1, + title: "Welcome".to_owned(), + body: "Thanks for installing PowerTools! For more information, please check the wiki. For bugs and requests, please create an issue.".to_owned(), + url: Some("https://git.ngni.us/NG-SD-Plugins/PowerTools/wiki".to_owned()), + } + ], + refresh: Some("http://limits.ngni.us:45000/powertools/v2".to_owned()) + } + } +} diff --git a/backend/limits_core/src/json_v2/battery_limit.rs b/backend/limits_core/src/json_v2/battery_limit.rs new file mode 100644 index 0000000..f064fd9 --- /dev/null +++ b/backend/limits_core/src/json_v2/battery_limit.rs @@ -0,0 +1,69 @@ +use serde::{Deserialize, Serialize}; +use super::RangeLimit; + +#[derive(Serialize, Deserialize, Debug, Clone)] +//#[serde(tag = "target")] +pub enum BatteryLimitType { + SteamDeck, + SteamDeckAdvance, + Generic, + Unknown, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct GenericBatteryLimit { + pub charge_rate: Option>, + pub charge_modes: Vec, + pub charge_limit: Option>, // battery charge % + pub extra_readouts: bool, +} + +impl GenericBatteryLimit { + pub fn default_for(t: BatteryLimitType) -> Self { + match t { + BatteryLimitType::SteamDeck | BatteryLimitType::SteamDeckAdvance => Self::default_steam_deck(), + _t => Self::default(), + } + } + + fn default_steam_deck() -> Self { + Self { + charge_rate: Some(RangeLimit { + min: Some(250), + max: Some(2500), + }), + charge_modes: vec![ + "normal".to_owned(), + "discharge".to_owned(), + "idle".to_owned(), + ], + charge_limit: Some(RangeLimit { + min: Some(10.0), + max: Some(90.0), + }), + extra_readouts: false, + } + } + + pub fn apply_override(&mut self, limit_override: Self) { + if let Some(range) = limit_override.charge_rate { + if range.min.is_none() && range.max.is_none() { + self.charge_rate = None; + } else { + self.charge_rate = Some(range); + } + } + if self.charge_modes.len() != limit_override.charge_modes.len() && !limit_override.charge_modes.is_empty() { + // assume limit_override.cpus wants to override even the cpu count + self.charge_modes = limit_override.charge_modes; + } + if let Some(range) = limit_override.charge_limit { + if range.min.is_none() && range.max.is_none() { + self.charge_limit = None; + } else { + self.charge_limit = Some(range); + } + } + self.extra_readouts = limit_override.extra_readouts; + } +} diff --git a/backend/limits_core/src/json_v2/conditions.rs b/backend/limits_core/src/json_v2/conditions.rs new file mode 100644 index 0000000..be08a1c --- /dev/null +++ b/backend/limits_core/src/json_v2/conditions.rs @@ -0,0 +1,26 @@ +use serde::{Deserialize, Serialize}; + +/// Conditions under which a config applies (ANDed together) +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Conditions { + /// Regex pattern for dmidecode output + pub dmi: Option, + /// Regex pattern for /proc/cpuinfo reading + pub cpuinfo: Option, + /// Regex pattern for /etc/os-release reading + pub os: Option, + /// Custom command to run, where an exit code of 0 means a successful match + pub command: Option, + /// Check if file exists + pub file_exists: Option, +} + +impl Conditions { + pub fn is_empty(&self) -> bool { + self.dmi.is_none() + && self.cpuinfo.is_none() + && self.os.is_none() + && self.command.is_none() + && self.file_exists.is_none() + } +} diff --git a/backend/limits_core/src/json_v2/config.rs b/backend/limits_core/src/json_v2/config.rs new file mode 100644 index 0000000..cf1e8e1 --- /dev/null +++ b/backend/limits_core/src/json_v2/config.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Config { + pub name: String, + pub conditions: super::Conditions, + pub limits: super::Limits, +} diff --git a/backend/limits_core/src/json_v2/cpu_limit.rs b/backend/limits_core/src/json_v2/cpu_limit.rs new file mode 100644 index 0000000..84f7ea0 --- /dev/null +++ b/backend/limits_core/src/json_v2/cpu_limit.rs @@ -0,0 +1,126 @@ +use serde::{Deserialize, Serialize}; + +use super::RangeLimit; + +#[derive(Serialize, Deserialize, Debug, Clone)] +//#[serde(tag = "target")] +pub enum CpuLimitType { + SteamDeck, + SteamDeckAdvance, + Generic, + GenericAMD, + Unknown, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct GenericCpusLimit { + pub cpus: Vec, + pub global_governors: bool, +} + +impl GenericCpusLimit { + pub fn default_for(t: CpuLimitType) -> Self { + match t { + CpuLimitType::SteamDeck | CpuLimitType::SteamDeckAdvance => { + Self { + cpus: [(); 8].iter().enumerate().map(|(i, _)| GenericCpuLimit::default_for(&t, i)).collect(), + global_governors: true, + } + }, + t => { + let cpu_count = Self::cpu_count().unwrap_or(8); + let mut cpus = Vec::with_capacity(cpu_count); + for i in 0..cpu_count { + cpus.push(GenericCpuLimit::default_for(&t, i)); + } + Self { + cpus, + global_governors: true, + } + } + } + } + + fn cpu_count() -> Option { + let mut data: String = std::fs::read_to_string("/sys/devices/system/cpu/present") + .unwrap_or_else(|_| "0-7".to_string() /* Steam Deck's default */); + if let Some(dash_index) = data.find('-') { + let data = data.split_off(dash_index + 1); + if let Ok(max_cpu) = data.parse::() { + return Some(max_cpu + 1); + } + } + None + } + + pub fn apply_override(&mut self, limit_override: Self) { + if self.cpus.len() != limit_override.cpus.len() && !limit_override.cpus.is_empty() { + // assume limit_override.cpus wants to override even the cpu count + self.cpus = limit_override.cpus; + } else { + self.cpus.iter_mut() + .zip(limit_override.cpus.into_iter()) + .for_each(|(cpu, limit_override)| cpu.apply_override(limit_override)); + } + self.global_governors = limit_override.global_governors; + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct GenericCpuLimit { + pub clock_min: Option>, + pub clock_max: Option>, + pub clock_step: Option, + pub skip_resume_reclock: bool, +} + +impl GenericCpuLimit { + pub fn default_for(t: &CpuLimitType, _index: usize) -> Self { + match t { + CpuLimitType::SteamDeck | CpuLimitType::SteamDeckAdvance => Self::default_steam_deck(), + _ => Self { + clock_min: None, + clock_max: None, + clock_step: Some(100), + skip_resume_reclock: false, + }, + } + } + + fn default_steam_deck() -> Self { + Self { + clock_min: Some(RangeLimit { + min: Some(1400), + max: Some(3500), + }), + clock_max: Some(RangeLimit { + min: Some(400), + max: Some(3500), + }), + clock_step: Some(100), + skip_resume_reclock: false, + } + } + + pub fn apply_override(&mut self, limit_override: Self) { + if let Some(range) = limit_override.clock_min { + if range.min.is_none() && range.max.is_none() { + self.clock_min = None; + } else { + self.clock_min = Some(range); + } + } + if let Some(range) = limit_override.clock_max { + if range.min.is_none() && range.max.is_none() { + self.clock_max = None; + } else { + self.clock_max = Some(range); + } + } + if let Some(val) = limit_override.clock_step { + self.clock_step = Some(val); + } + self.clock_step = limit_override.clock_step; + self.skip_resume_reclock = limit_override.skip_resume_reclock; + } +} diff --git a/backend/limits_core/src/json_v2/devel_message.rs b/backend/limits_core/src/json_v2/devel_message.rs new file mode 100644 index 0000000..904968d --- /dev/null +++ b/backend/limits_core/src/json_v2/devel_message.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +/// Message from the developers +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct DeveloperMessage { + /// Message identifier + pub id: u64, + /// Message title + pub title: String, + /// Message content + pub body: String, + /// Link for further information + pub url: Option, +} diff --git a/backend/limits_core/src/json_v2/gpu_limit.rs b/backend/limits_core/src/json_v2/gpu_limit.rs new file mode 100644 index 0000000..39e09c1 --- /dev/null +++ b/backend/limits_core/src/json_v2/gpu_limit.rs @@ -0,0 +1,132 @@ +use serde::{Deserialize, Serialize}; +use super::RangeLimit; + +#[derive(Serialize, Deserialize, Debug, Clone)] +//#[serde(tag = "target")] +pub enum GpuLimitType { + SteamDeck, + SteamDeckAdvance, + Generic, + GenericAMD, + Unknown, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct GenericGpuLimit { + pub fast_ppt: Option>, + pub fast_ppt_default: Option, + pub slow_ppt: Option>, + pub slow_ppt_default: Option, + pub ppt_divisor: Option, + pub ppt_step: Option, + pub tdp: Option>, + pub tdp_boost: Option>, + pub tdp_step: Option, + pub clock_min: Option>, + pub clock_max: Option>, + pub clock_step: Option, + pub skip_resume_reclock: bool, +} + +impl GenericGpuLimit { + pub fn default_for(t: GpuLimitType) -> Self { + match t { + GpuLimitType::SteamDeck | GpuLimitType::SteamDeckAdvance => Self::default_steam_deck(), + _t => Self::default(), + } + } + + fn default_steam_deck() -> Self { + Self { + fast_ppt: Some(RangeLimit { + min: Some(1000000), + max: Some(30_000_000), + }), + fast_ppt_default: Some(15_000_000), + slow_ppt: Some(RangeLimit { + min: Some(1000000), + max: Some(29_000_000), + }), + slow_ppt_default: Some(15_000_000), + ppt_divisor: Some(1_000_000), + ppt_step: Some(1), + tdp: None, + tdp_boost: None, + tdp_step: None, + clock_min: Some(RangeLimit { + min: Some(400), + max: Some(1600), + }), + clock_max: Some(RangeLimit { + min: Some(400), + max: Some(1600), + }), + clock_step: Some(100), + skip_resume_reclock: false, + } + } + + pub fn apply_override(&mut self, limit_override: Self) { + if let Some(range) = limit_override.fast_ppt { + if range.min.is_none() && range.max.is_none() { + self.fast_ppt = None; + } else { + self.fast_ppt = Some(range); + } + } + if let Some(def) = limit_override.fast_ppt_default { + self.fast_ppt_default = Some(def); + } + if let Some(range) = limit_override.slow_ppt { + if range.min.is_none() && range.max.is_none() { + self.slow_ppt = None; + } else { + self.slow_ppt = Some(range); + } + } + if let Some(def) = limit_override.slow_ppt_default { + self.slow_ppt_default = Some(def); + } + if let Some(val) = limit_override.ppt_divisor { + self.ppt_divisor = Some(val); + } + if let Some(val) = limit_override.ppt_step { + self.ppt_step = Some(val); + } + if let Some(range) = limit_override.tdp { + if range.min.is_none() && range.max.is_none() { + self.tdp = None; + } else { + self.tdp = Some(range); + } + } + if let Some(range) = limit_override.tdp_boost { + if range.min.is_none() && range.max.is_none() { + self.tdp_boost = None; + } else { + self.tdp_boost = Some(range); + } + } + if let Some(val) = limit_override.tdp_step { + self.tdp_step = Some(val); + } + if let Some(range) = limit_override.clock_min { + if range.min.is_none() && range.max.is_none() { + self.clock_min = None; + } else { + self.clock_min = Some(range); + } + } + if let Some(range) = limit_override.clock_max { + if range.min.is_none() && range.max.is_none() { + self.clock_max = None; + } else { + self.clock_max = Some(range); + } + } + if let Some(val) = limit_override.clock_step { + self.clock_step = Some(val); + } + self.skip_resume_reclock = limit_override.skip_resume_reclock; + } +} diff --git a/backend/limits_core/src/json_v2/limits.rs b/backend/limits_core/src/json_v2/limits.rs new file mode 100644 index 0000000..b983603 --- /dev/null +++ b/backend/limits_core/src/json_v2/limits.rs @@ -0,0 +1,28 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Limits { + pub cpu: CpuLimit, + pub gpu: GpuLimit, + pub battery: BatteryLimit, +} + +impl Limits { + pub fn apply_override(&mut self, limit_override: Option) { + if let Some(limit_override) = limit_override { + self.cpu.limits.apply_override(limit_override.cpu.limits); + self.gpu.limits.apply_override(limit_override.gpu.limits); + self.battery.limits.apply_override(limit_override.battery.limits); + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Limit { + pub provider: P, + pub limits: L, +} + +pub type CpuLimit = Limit; +pub type GpuLimit = Limit; +pub type BatteryLimit = Limit; diff --git a/backend/limits_core/src/json_v2/mod.rs b/backend/limits_core/src/json_v2/mod.rs new file mode 100644 index 0000000..c5bfeb6 --- /dev/null +++ b/backend/limits_core/src/json_v2/mod.rs @@ -0,0 +1,21 @@ +mod base; +mod battery_limit; +mod conditions; +mod config; +mod cpu_limit; +mod devel_message; +mod gpu_limit; +mod limits; +mod range; +mod target; + +pub use base::Base; +pub use battery_limit::{BatteryLimitType, GenericBatteryLimit}; +pub use conditions::Conditions; +pub use cpu_limit::{CpuLimitType, GenericCpusLimit, GenericCpuLimit}; +pub use devel_message::DeveloperMessage; +pub use gpu_limit::{GpuLimitType, GenericGpuLimit}; +pub use config::Config; +pub use limits::{Limits, Limit, CpuLimit, GpuLimit, BatteryLimit}; +pub use range::RangeLimit; +pub use target::Target; diff --git a/backend/limits_core/src/json_v2/range.rs b/backend/limits_core/src/json_v2/range.rs new file mode 100644 index 0000000..62de907 --- /dev/null +++ b/backend/limits_core/src/json_v2/range.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +/// Base JSON limits information +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub struct RangeLimit { + pub min: Option, + pub max: Option, +} diff --git a/backend/limits_core/src/json_v2/target.rs b/backend/limits_core/src/json_v2/target.rs new file mode 100644 index 0000000..768df6f --- /dev/null +++ b/backend/limits_core/src/json_v2/target.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum Target { + SteamDeck, + SteamDeckAdvance, + Generic, + Unknown, +} diff --git a/backend/limits_core/src/lib.rs b/backend/limits_core/src/lib.rs index 22fdbb3..11adaf7 100644 --- a/backend/limits_core/src/lib.rs +++ b/backend/limits_core/src/lib.rs @@ -1 +1,2 @@ pub mod json; +pub mod json_v2; diff --git a/backend/limits_srv/Cargo.lock b/backend/limits_srv/Cargo.lock index 1b8b3ee..9c3cf2d 100644 --- a/backend/limits_srv/Cargo.lock +++ b/backend/limits_srv/Cargo.lock @@ -433,7 +433,7 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "limits_core" -version = "2.0.1" +version = "3.0.0" dependencies = [ "serde", "serde_json", @@ -441,7 +441,7 @@ dependencies = [ [[package]] name = "limits_srv" -version = "2.0.1" +version = "3.0.0" dependencies = [ "chrono", "limits_core", diff --git a/backend/limits_srv/Cargo.toml b/backend/limits_srv/Cargo.toml index 2d529a8..18f52a6 100644 --- a/backend/limits_srv/Cargo.toml +++ b/backend/limits_srv/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "limits_srv" -version = "2.0.1" +version = "3.0.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -limits_core = { version = "2.0.1", path = "../limits_core" } +limits_core = { version = "3.0.0", path = "../limits_core" } chrono = { version = "0.4" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/backend/limits_srv/pt_limits.json b/backend/limits_srv/pt_limits.json index 2b34975..eea7711 100644 --- a/backend/limits_srv/pt_limits.json +++ b/backend/limits_srv/pt_limits.json @@ -293,8 +293,8 @@ { "id": 1, "title": "Welcome", - "body": "Thanks for installing PowerTools! For more information, please check the wiki. For bugs and requests, please create an issue on GitHub.", - "url": "https://github.com/NGnius/PowerTools/wiki" + "body": "Thanks for installing PowerTools! For more information, please check the wiki. For bugs and requests, please create an issue.", + "url": "https://git.ngni.us/NG-SD-Plugins/PowerTools/wiki" } ], "refresh": "http://limits.ngni.us:45000/powertools/v1" diff --git a/backend/limits_srv/pt_limits_v2.json b/backend/limits_srv/pt_limits_v2.json new file mode 100644 index 0000000..fc515c6 --- /dev/null +++ b/backend/limits_srv/pt_limits_v2.json @@ -0,0 +1,1250 @@ +{ + "configs": [ + { + "name": "Steam Deck Custom", + "conditions": { + "dmi": null, + "cpuinfo": "model name\t: AMD Custom APU 0405\n", + "os": null, + "command": null, + "file_exists": "./limits_override.json" + }, + "limits": { + "cpu": { + "provider": "SteamDeckAdvance", + "limits": { + "cpus": [ + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "SteamDeckAdvance", + "limits": { + "fast_ppt": { + "min": 1000000, + "max": 30000000 + }, + "fast_ppt_default": 15000000, + "slow_ppt": { + "min": 1000000, + "max": 29000000 + }, + "slow_ppt_default": 15000000, + "ppt_divisor": 1000000, + "ppt_step": 1, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": { + "min": 400, + "max": 1600 + }, + "clock_max": { + "min": 400, + "max": 1600 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "SteamDeckAdvance", + "limits": { + "charge_rate": { + "min": 250, + "max": 2500 + }, + "charge_modes": [ + "normal", + "discharge", + "idle" + ], + "charge_limit": { + "min": 10.0, + "max": 90.0 + }, + "extra_readouts": false + } + } + } + }, + { + "name": "Steam Deck", + "conditions": { + "dmi": null, + "cpuinfo": "model name\t: AMD Custom APU 0405\n", + "os": null, + "command": null, + "file_exists": null + }, + "limits": { + "cpu": { + "provider": "SteamDeck", + "limits": { + "cpus": [ + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1400, + "max": 3500 + }, + "clock_max": { + "min": 400, + "max": 3500 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "SteamDeck", + "limits": { + "fast_ppt": { + "min": 1000000, + "max": 30000000 + }, + "fast_ppt_default": 15000000, + "slow_ppt": { + "min": 1000000, + "max": 29000000 + }, + "slow_ppt_default": 15000000, + "ppt_divisor": 1000000, + "ppt_step": 1, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": { + "min": 400, + "max": 1600 + }, + "clock_max": { + "min": 400, + "max": 1600 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "SteamDeck", + "limits": { + "charge_rate": { + "min": 250, + "max": 2500 + }, + "charge_modes": [ + "normal", + "discharge", + "idle" + ], + "charge_limit": { + "min": 10.0, + "max": 90.0 + }, + "extra_readouts": false + } + } + } + }, + { + "name": "AMD R3 2300U", + "conditions": { + "dmi": null, + "cpuinfo": "model name\t+: AMD Ryzen 3 2300U\n", + "os": null, + "command": null, + "file_exists": null + }, + "limits": { + "cpu": { + "provider": "GenericAMD", + "limits": { + "cpus": [ + { + "clock_min": { + "min": 1000, + "max": 3700 + }, + "clock_max": { + "min": 1000, + "max": 3700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 3700 + }, + "clock_max": { + "min": 1000, + "max": 3700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 3700 + }, + "clock_max": { + "min": 1000, + "max": 3700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 3700 + }, + "clock_max": { + "min": 1000, + "max": 3700 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "GenericAMD", + "limits": { + "fast_ppt": { + "min": 1000000, + "max": 25000000 + }, + "fast_ppt_default": null, + "slow_ppt": { + "min": 1000000, + "max": 25000000 + }, + "slow_ppt_default": null, + "ppt_divisor": null, + "ppt_step": 1000000, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": { + "min": 400, + "max": 1100 + }, + "clock_max": { + "min": 400, + "max": 1100 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "Generic", + "limits": { + "charge_rate": null, + "charge_modes": [], + "charge_limit": null, + "extra_readouts": false + } + } + } + }, + { + "name": "AMD R5 5560U", + "conditions": { + "dmi": null, + "cpuinfo": "model name\t+: AMD Ryzen 5 5560U\n", + "os": null, + "command": null, + "file_exists": null + }, + "limits": { + "cpu": { + "provider": "GenericAMD", + "limits": { + "cpus": [ + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4000 + }, + "clock_max": { + "min": 1000, + "max": 4000 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "GenericAMD", + "limits": { + "fast_ppt": { + "min": 1000000, + "max": 25000000 + }, + "fast_ppt_default": null, + "slow_ppt": { + "min": 1000000, + "max": 25000000 + }, + "slow_ppt_default": null, + "ppt_divisor": null, + "ppt_step": 1000000, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": { + "min": 400, + "max": 1600 + }, + "clock_max": { + "min": 400, + "max": 1600 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "Generic", + "limits": { + "charge_rate": null, + "charge_modes": [], + "charge_limit": null, + "extra_readouts": false + } + } + } + }, + { + "name": "AMD R7 5825U", + "conditions": { + "dmi": null, + "cpuinfo": "model name\t+: AMD Ryzen 7 5825U\n", + "os": null, + "command": null, + "file_exists": null + }, + "limits": { + "cpu": { + "provider": "GenericAMD", + "limits": { + "cpus": [ + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4500 + }, + "clock_max": { + "min": 1000, + "max": 4500 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "GenericAMD", + "limits": { + "fast_ppt": { + "min": 1000000, + "max": 28000000 + }, + "fast_ppt_default": null, + "slow_ppt": { + "min": 1000000, + "max": 28000000 + }, + "slow_ppt_default": null, + "ppt_divisor": null, + "ppt_step": 1000000, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": { + "min": 400, + "max": 2200 + }, + "clock_max": { + "min": 400, + "max": 2200 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "Generic", + "limits": { + "charge_rate": null, + "charge_modes": [], + "charge_limit": null, + "extra_readouts": false + } + } + } + }, + { + "name": "AMD R7 6800U", + "conditions": { + "dmi": null, + "cpuinfo": "model name\t+: AMD Ryzen 7 6800U\n", + "os": null, + "command": null, + "file_exists": null + }, + "limits": { + "cpu": { + "provider": "GenericAMD", + "limits": { + "cpus": [ + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": { + "min": 1000, + "max": 4700 + }, + "clock_max": { + "min": 1000, + "max": 4700 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "GenericAMD", + "limits": { + "fast_ppt": { + "min": 1000000, + "max": 28000000 + }, + "fast_ppt_default": null, + "slow_ppt": { + "min": 1000000, + "max": 28000000 + }, + "slow_ppt_default": null, + "ppt_divisor": null, + "ppt_step": 1000000, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": { + "min": 400, + "max": 2200 + }, + "clock_max": { + "min": 400, + "max": 2200 + }, + "clock_step": 100, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "Generic", + "limits": { + "charge_rate": null, + "charge_modes": [], + "charge_limit": null, + "extra_readouts": false + } + } + } + }, + { + "name": "Fallback", + "conditions": { + "dmi": null, + "cpuinfo": null, + "os": null, + "command": null, + "file_exists": null + }, + "limits": { + "cpu": { + "provider": "Unknown", + "limits": { + "cpus": [ + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + }, + { + "clock_min": null, + "clock_max": null, + "clock_step": 100, + "skip_resume_reclock": false + } + ], + "global_governors": true + } + }, + "gpu": { + "provider": "Unknown", + "limits": { + "fast_ppt": null, + "fast_ppt_default": null, + "slow_ppt": null, + "slow_ppt_default": null, + "ppt_divisor": null, + "ppt_step": null, + "tdp": null, + "tdp_boost": null, + "tdp_step": null, + "clock_min": null, + "clock_max": null, + "clock_step": null, + "skip_resume_reclock": false + } + }, + "battery": { + "provider": "Unknown", + "limits": { + "charge_rate": null, + "charge_modes": [], + "charge_limit": null, + "extra_readouts": false + } + } + } + } + ], + "messages": [ + { + "id": 1, + "title": "Welcome", + "body": "Thanks for installing PowerTools! For more information, please check the wiki. For bugs and requests, please create an issue.", + "url": "https://git.ngni.us/NG-SD-Plugins/PowerTools/wiki" + } + ], + "refresh": "http://limits.ngni.us:45000/powertools/v2" +} \ No newline at end of file diff --git a/backend/limits_srv/src/main.rs b/backend/limits_srv/src/main.rs index 10a03af..6e33b45 100644 --- a/backend/limits_srv/src/main.rs +++ b/backend/limits_srv/src/main.rs @@ -4,46 +4,61 @@ use std::sync::{RwLock, Arc}; use serde::Serialize; use warp::Filter; -use limits_core::json::Base; - -static VISIT_COUNT: AtomicU64 = AtomicU64::new(0); +static VISIT_V1_COUNT: AtomicU64 = AtomicU64::new(0); +static VISIT_V2_COUNT: AtomicU64 = AtomicU64::new(0); static START_TIME: AtomicI64 = AtomicI64::new(0); -fn get_limits(base: Base) -> impl warp::Reply { - VISIT_COUNT.fetch_add(1, Ordering::AcqRel); +fn get_limits_v1(base: &limits_core::json::Base) -> impl warp::Reply { + VISIT_V1_COUNT.fetch_add(1, Ordering::AcqRel); //println!("Limits got"); - warp::reply::json(&base) + warp::reply::json(base) +} + +fn get_limits_v2(base: &limits_core::json_v2::Base) -> impl warp::Reply { + VISIT_V2_COUNT.fetch_add(1, Ordering::AcqRel); + //println!("Limits got"); + warp::reply::json(base) } #[derive(Serialize)] struct Visits { - visits: u64, + visits_v1: u64, + visits_v2: u64, since: i64, // Unix time (since epoch) } fn get_visits() -> impl warp::Reply { - let count = VISIT_COUNT.load(Ordering::Relaxed); + let count_v1 = VISIT_V1_COUNT.load(Ordering::Relaxed); + let count_v2 = VISIT_V2_COUNT.load(Ordering::Relaxed); let start = START_TIME.load(Ordering::Relaxed); //println!("Count got"); warp::reply::json(&Visits { - visits: count, + visits_v1: count_v1, + visits_v2: count_v2, since: start, }) } #[allow(opaque_hidden_inferred_bound)] -fn routes(base: Arc>) -> impl Filter + Clone { +fn routes(base: Arc>, base2: Arc>) -> impl Filter + Clone { warp::get().and( warp::path!("powertools" / "v1") .map(move || { - let base = base.read().expect("Failed to acquire base limits read lock").clone(); - get_limits(base) + let base = base.read().expect("Failed to acquire base limits read lock"); + get_limits_v1(&base) }) .or( warp::path!("powertools" / "count") .map(get_visits) ) + .or( + warp::path!("powertools" / "v2") + .map(move || { + let base2 = base2.read().expect("Failed to acquire base limits read lock"); + get_limits_v2(&base2) + }) + ) ).recover(recovery) } @@ -59,10 +74,14 @@ pub async fn recovery(reject: warp::Rejection) -> Result limits_core::json::Base { +fn get_limits() -> limits_core::json_v2::Base { let limits_path = super::utility::limits_path(); match File::open(&limits_path) { Ok(f) => match serde_json::from_reader(f) { @@ -18,7 +18,7 @@ fn get_limits() -> limits_core::json::Base { limits_path.display(), e ); - limits_core::json::Base::default() + limits_core::json_v2::Base::default() } }, Err(e) => { @@ -32,6 +32,31 @@ fn get_limits() -> limits_core::json::Base { } } +fn get_limits_overrides() -> Option { + let limits_override_path = super::utility::limits_override_path(); + match File::open(&limits_override_path) { + Ok(f) => match serde_json::from_reader(f) { + Ok(lim) => Some(lim), + Err(e) => { + log::warn!( + "Failed to parse limits override file `{}`, cannot use for auto_detect: {}", + limits_override_path.display(), + e + ); + None + } + }, + Err(e) => { + log::info!( + "Failed to open limits override file `{}`: {}", + limits_override_path.display(), + e + ); + None + } + } +} + #[inline] pub fn auto_detect_provider() -> DriverJson { let provider = auto_detect0( @@ -51,7 +76,13 @@ pub fn auto_detect0( json_path: std::path::PathBuf, name: String, ) -> Driver { - let mut builder = DriverBuilder::new(json_path, name); + let mut general_driver = Box::new(General { + persistent: false, + path: json_path, + name, + driver: DriverJson::AutoDetect, + events: Default::default(), + }); let cpu_info: String = usdpl_back::api::files::read_single("/proc/cpuinfo").unwrap_or_default(); log::debug!("Read from /proc/cpuinfo:\n{}", cpu_info); @@ -65,268 +96,229 @@ pub fn auto_detect0( log::debug!("Read dmidecode:\n{}", dmi_info); let limits = get_limits(); + let limits_override = get_limits_overrides(); // build driver based on limits conditions for conf in limits.configs { let conditions = conf.conditions; let mut matches = true; - if conditions.is_empty() { - matches = !builder.is_complete(); - } else { - if let Some(dmi) = &conditions.dmi { - let pattern = RegexBuilder::new(dmi) - .multi_line(true) - .build() - .expect("Invalid DMI regex"); - matches &= pattern.is_match(&dmi_info); - } - if let Some(cpuinfo) = &conditions.cpuinfo { - let pattern = RegexBuilder::new(cpuinfo) - .multi_line(true) - .build() - .expect("Invalid CPU regex"); - matches &= pattern.is_match(&cpu_info); - } - if let Some(os) = &conditions.os { - let pattern = RegexBuilder::new(os) - .multi_line(true) - .build() - .expect("Invalid OS regex"); - matches &= pattern.is_match(&os_info); - } - if let Some(cmd) = &conditions.command { - match std::process::Command::new("bash") - .args(["-c", cmd]) - .status() - { - Ok(status) => matches &= status.code().map(|c| c == 0).unwrap_or(false), - Err(e) => log::warn!("Ignoring bash limits error: {}", e), - } - } - if let Some(file_exists) = &conditions.file_exists { - let exists = std::path::Path::new(file_exists).exists(); - matches &= exists; + if let Some(dmi) = &conditions.dmi { + let pattern = RegexBuilder::new(dmi) + .multi_line(true) + .build() + .expect("Invalid DMI regex"); + matches &= pattern.is_match(&dmi_info); + } + if let Some(cpuinfo) = &conditions.cpuinfo { + let pattern = RegexBuilder::new(cpuinfo) + .multi_line(true) + .build() + .expect("Invalid CPU regex"); + matches &= pattern.is_match(&cpu_info); + } + if let Some(os) = &conditions.os { + let pattern = RegexBuilder::new(os) + .multi_line(true) + .build() + .expect("Invalid OS regex"); + matches &= pattern.is_match(&os_info); + } + if let Some(cmd) = &conditions.command { + match std::process::Command::new("bash") + .args(["-c", cmd]) + .status() + { + Ok(status) => matches &= status.code().map(|c| c == 0).unwrap_or(false), + Err(e) => log::warn!("Ignoring bash limits error: {}", e), } } + if let Some(file_exists) = &conditions.file_exists { + let exists = std::path::Path::new(file_exists).exists(); + matches &= exists; + } + if matches { + let mut relevant_limits = conf.limits.clone(); + relevant_limits.apply_override(limits_override); if let Some(settings) = &settings_opt { - *builder.general.persistent() = true; - builder.general.name(settings.name.clone()); - for limit in conf.limits { - match limit { - Limits::Cpu(cpus) => { - let cpu_driver: Box = match cpus { - CpuLimit::SteamDeck => { - Box::new(crate::settings::steam_deck::Cpus::from_json( - settings.cpus.clone(), - settings.version, - )) - } - CpuLimit::SteamDeckAdvance => { - Box::new(crate::settings::steam_deck::Cpus::from_json( - settings.cpus.clone(), - settings.version, - )) - } - CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::< - crate::settings::generic::Cpu, - >::from_json_and_limits( - settings.cpus.clone(), - settings.version, - x, - )), - CpuLimit::GenericAMD(x) => Box::new( - crate::settings::generic_amd::Cpus::from_json_and_limits( - settings.cpus.clone(), - settings.version, - x, - ), - ), - CpuLimit::Unknown => { - Box::new(crate::settings::unknown::Cpus::from_json( - settings.cpus.clone(), - settings.version, - )) - } - }; - builder.cpus = Some(cpu_driver); - } - Limits::Gpu(gpu) => { - let driver: Box = match gpu { - GpuLimit::SteamDeck => { - Box::new(crate::settings::steam_deck::Gpu::from_json( - settings.gpu.clone(), - settings.version, - )) - } - GpuLimit::SteamDeckAdvance => { - Box::new(crate::settings::steam_deck::Gpu::from_json( - settings.gpu.clone(), - settings.version, - )) - } - GpuLimit::Generic(x) => { - Box::new(crate::settings::generic::Gpu::from_json_and_limits( - settings.gpu.clone(), - settings.version, - x, - )) - } - GpuLimit::GenericAMD(x) => Box::new( - crate::settings::generic_amd::Gpu::from_json_and_limits( - settings.gpu.clone(), - settings.version, - x, - ), - ), - GpuLimit::Unknown => { - Box::new(crate::settings::unknown::Gpu::from_json( - settings.gpu.clone(), - settings.version, - )) - } - }; - builder.gpu = Some(driver); - } - Limits::Battery(batt) => { - let driver: Box = match batt { - BatteryLimit::SteamDeck => { - Box::new(crate::settings::steam_deck::Battery::from_json( - settings.battery.clone(), - settings.version, - )) - } - BatteryLimit::SteamDeckAdvance => { - Box::new(crate::settings::steam_deck::Battery::from_json( - settings.battery.clone(), - settings.version, - )) - } - BatteryLimit::Generic(x) => Box::new( - crate::settings::generic::Battery::from_json_and_limits( - settings.battery.clone(), - settings.version, - x, - ), - ), - BatteryLimit::Unknown => { - Box::new(crate::settings::unknown::Battery) - } - }; - builder.battery = Some(driver); - } + *general_driver.persistent() = true; + let cpu_driver: Box = match relevant_limits.cpu.provider { + CpuLimitType::SteamDeck => { + Box::new(crate::settings::steam_deck::Cpus::from_json_and_limits( + settings.cpus.clone(), + settings.version, + relevant_limits.cpu.limits, + )) } - } + CpuLimitType::SteamDeckAdvance => { + Box::new(crate::settings::steam_deck::Cpus::from_json_and_limits( + settings.cpus.clone(), + settings.version, + relevant_limits.cpu.limits, + )) + } + CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::< + crate::settings::generic::Cpu, + >::from_json_and_limits( + settings.cpus.clone(), + settings.version, + relevant_limits.cpu.limits, + )), + CpuLimitType::GenericAMD => Box::new( + crate::settings::generic_amd::Cpus::from_json_and_limits( + settings.cpus.clone(), + settings.version, + relevant_limits.cpu.limits, + ), + ), + CpuLimitType::Unknown => { + Box::new(crate::settings::unknown::Cpus::from_json_and_limits( + settings.cpus.clone(), + settings.version, + relevant_limits.cpu.limits, + )) + } + }; + + let gpu_driver: Box = match relevant_limits.gpu.provider { + GpuLimitType::SteamDeck => { + Box::new(crate::settings::steam_deck::Gpu::from_json_and_limits( + settings.gpu.clone(), + settings.version, + relevant_limits.gpu.limits, + )) + } + GpuLimitType::SteamDeckAdvance => { + Box::new(crate::settings::steam_deck::Gpu::from_json_and_limits( + settings.gpu.clone(), + settings.version, + relevant_limits.gpu.limits, + )) + } + GpuLimitType::Generic => { + Box::new(crate::settings::generic::Gpu::from_json_and_limits( + settings.gpu.clone(), + settings.version, + relevant_limits.gpu.limits, + )) + } + GpuLimitType::GenericAMD => Box::new( + crate::settings::generic_amd::Gpu::from_json_and_limits( + settings.gpu.clone(), + settings.version, + relevant_limits.gpu.limits, + ), + ), + GpuLimitType::Unknown => { + Box::new(crate::settings::unknown::Gpu::from_json_and_limits( + settings.gpu.clone(), + settings.version, + relevant_limits.gpu.limits, + )) + } + }; + let battery_driver: Box = match relevant_limits.battery.provider { + BatteryLimitType::SteamDeck => { + Box::new(crate::settings::steam_deck::Battery::from_json_and_limits( + settings.battery.clone(), + settings.version, + relevant_limits.battery.limits, + )) + } + BatteryLimitType::SteamDeckAdvance => { + Box::new(crate::settings::steam_deck::Battery::from_json_and_limits( + settings.battery.clone(), + settings.version, + relevant_limits.battery.limits, + )) + } + BatteryLimitType::Generic => Box::new( + crate::settings::generic::Battery::from_json_and_limits( + settings.battery.clone(), + settings.version, + relevant_limits.battery.limits, + ), + ), + BatteryLimitType::Unknown => { + Box::new(crate::settings::unknown::Battery::from_json_and_limits( + settings.battery.clone(), + settings.version, + relevant_limits.battery.limits, + )) + } + }; + + return Driver { + general: general_driver, + cpus: cpu_driver, + gpu: gpu_driver, + battery: battery_driver, + }; } else { - for limit in conf.limits { - match limit { - Limits::Cpu(cpus) => { - let cpu_driver: Box = match cpus { - CpuLimit::SteamDeck => { - Box::new(crate::settings::steam_deck::Cpus::system_default()) - } - CpuLimit::SteamDeckAdvance => { - Box::new(crate::settings::steam_deck::Cpus::system_default()) - } - CpuLimit::Generic(x) => { - Box::new(crate::settings::generic::Cpus::< - crate::settings::generic::Cpu, - >::from_limits(x)) - } - CpuLimit::GenericAMD(x) => { - Box::new(crate::settings::generic_amd::Cpus::from_limits(x)) - } - CpuLimit::Unknown => { - Box::new(crate::settings::unknown::Cpus::system_default()) - } - }; - builder.cpus = Some(cpu_driver); - } - Limits::Gpu(gpu) => { - let driver: Box = match gpu { - GpuLimit::SteamDeck => { - Box::new(crate::settings::steam_deck::Gpu::system_default()) - } - GpuLimit::SteamDeckAdvance => { - Box::new(crate::settings::steam_deck::Gpu::system_default()) - } - GpuLimit::Generic(x) => { - Box::new(crate::settings::generic::Gpu::from_limits(x)) - } - GpuLimit::GenericAMD(x) => { - Box::new(crate::settings::generic_amd::Gpu::from_limits(x)) - } - GpuLimit::Unknown => { - Box::new(crate::settings::unknown::Gpu::system_default()) - } - }; - builder.gpu = Some(driver); - } - Limits::Battery(batt) => { - let driver: Box = match batt { - BatteryLimit::SteamDeck => { - Box::new(crate::settings::steam_deck::Battery::system_default()) - } - BatteryLimit::SteamDeckAdvance => { - Box::new(crate::settings::steam_deck::Battery::system_default()) - } - BatteryLimit::Generic(x) => { - Box::new(crate::settings::generic::Battery::from_limits(x)) - } - BatteryLimit::Unknown => { - Box::new(crate::settings::unknown::Battery) - } - }; - builder.battery = Some(driver); - } + let cpu_driver: Box = match relevant_limits.cpu.provider { + CpuLimitType::SteamDeck => { + Box::new(crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits)) } - } + CpuLimitType::SteamDeckAdvance => { + Box::new(crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits)) + } + CpuLimitType::Generic => { + Box::new(crate::settings::generic::Cpus::< + crate::settings::generic::Cpu, + >::from_limits(relevant_limits.cpu.limits)) + } + CpuLimitType::GenericAMD => { + Box::new(crate::settings::generic_amd::Cpus::from_limits(relevant_limits.cpu.limits)) + } + CpuLimitType::Unknown => { + Box::new(crate::settings::unknown::Cpus::from_limits(relevant_limits.cpu.limits)) + } + }; + let gpu_driver: Box = match relevant_limits.gpu.provider { + GpuLimitType::SteamDeck => { + Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits)) + } + GpuLimitType::SteamDeckAdvance => { + Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits)) + } + GpuLimitType::Generic => { + Box::new(crate::settings::generic::Gpu::from_limits(relevant_limits.gpu.limits)) + } + GpuLimitType::GenericAMD => { + Box::new(crate::settings::generic_amd::Gpu::from_limits(relevant_limits.gpu.limits)) + } + GpuLimitType::Unknown => { + Box::new(crate::settings::unknown::Gpu::from_limits(relevant_limits.gpu.limits)) + } + }; + let battery_driver: Box = match relevant_limits.battery.provider { + BatteryLimitType::SteamDeck => { + Box::new(crate::settings::steam_deck::Battery::from_limits(relevant_limits.battery.limits)) + } + BatteryLimitType::SteamDeckAdvance => { + Box::new(crate::settings::steam_deck::Battery::from_limits(relevant_limits.battery.limits)) + } + BatteryLimitType::Generic => { + Box::new(crate::settings::generic::Battery::from_limits(relevant_limits.battery.limits)) + } + BatteryLimitType::Unknown => { + Box::new(crate::settings::unknown::Battery::from_limits(relevant_limits.battery.limits)) + } + }; + return Driver { + general: general_driver, + cpus: cpu_driver, + gpu: gpu_driver, + battery: battery_driver, + }; } } } - builder.build() -} - -struct DriverBuilder { - general: Box, - cpus: Option>, - gpu: Option>, - battery: Option>, -} - -impl DriverBuilder { - fn new(json_path: std::path::PathBuf, profile_name: String) -> Self { - Self { - general: Box::new(General { - persistent: false, - path: json_path, - name: profile_name, - driver: DriverJson::AutoDetect, - events: Default::default(), - }), - cpus: None, - gpu: None, - battery: None, - } - } - - fn is_complete(&self) -> bool { - self.cpus.is_some() && self.gpu.is_some() && self.battery.is_some() - } - - fn build(self) -> Driver { - Driver { - general: self.general, - cpus: self - .cpus - .unwrap_or_else(|| Box::new(crate::settings::unknown::Cpus::system_default())), - gpu: self - .gpu - .unwrap_or_else(|| Box::new(crate::settings::unknown::Gpu::system_default())), - battery: self - .battery - .unwrap_or_else(|| Box::new(crate::settings::unknown::Battery)), - } + Driver { + general: general_driver, + cpus: Box::new(crate::settings::unknown::Cpus::system_default()), + gpu: Box::new(crate::settings::unknown::Gpu::system_default()), + battery: Box::new(crate::settings::unknown::Battery), } } diff --git a/backend/src/settings/detect/limits_worker.rs b/backend/src/settings/detect/limits_worker.rs index 8a52b96..c3dbd0e 100644 --- a/backend/src/settings/detect/limits_worker.rs +++ b/backend/src/settings/detect/limits_worker.rs @@ -2,7 +2,7 @@ use std::thread::{self, JoinHandle}; #[cfg(feature = "online")] use std::time::Duration; -use limits_core::json::Base; +use limits_core::json_v2::Base; #[cfg(feature = "online")] pub fn spawn() -> JoinHandle<()> { diff --git a/backend/src/settings/detect/utility.rs b/backend/src/settings/detect/utility.rs index c278e66..7d42be0 100644 --- a/backend/src/settings/detect/utility.rs +++ b/backend/src/settings/detect/utility.rs @@ -4,6 +4,10 @@ pub fn limits_path() -> std::path::PathBuf { crate::utility::settings_dir().join(crate::consts::LIMITS_FILE) } +pub fn limits_override_path() -> std::path::PathBuf { + crate::utility::settings_dir().join(crate::consts::LIMITS_OVERRIDE_FILE) +} + // NOTE: eats errors pub fn get_dev_messages() -> Vec { let limits_path = limits_path(); diff --git a/backend/src/settings/driver.rs b/backend/src/settings/driver.rs index 4192f6f..90a3b7f 100644 --- a/backend/src/settings/driver.rs +++ b/backend/src/settings/driver.rs @@ -1,4 +1,4 @@ -use super::{auto_detect0, General, SettingError, TBattery, TCpus, TGeneral, TGpu}; +use super::{auto_detect0, TBattery, TCpus, TGeneral, TGpu}; use crate::persist::{DriverJson, SettingsJson}; pub struct Driver { @@ -12,96 +12,9 @@ impl Driver { pub fn init( settings: SettingsJson, json_path: std::path::PathBuf, - ) -> Result { - Ok(match settings.version { - 0 => Self::version0(settings, json_path)?, - _ => Self { - general: Box::new(General { - persistent: settings.persistent, - path: json_path, - name: settings.name, - driver: DriverJson::SteamDeck, - events: settings.events.unwrap_or_default(), - }), - cpus: Box::new(super::steam_deck::Cpus::from_json( - settings.cpus, - settings.version, - )), - gpu: Box::new(super::steam_deck::Gpu::from_json( - settings.gpu, - settings.version, - )), - battery: Box::new(super::steam_deck::Battery::from_json( - settings.battery, - settings.version, - )), - }, - }) - } - - fn version0( - settings: SettingsJson, - json_path: std::path::PathBuf, - ) -> Result { - let name = settings.name.clone(); - if let Some(provider) = &settings.provider { - match provider { - DriverJson::SteamDeck => Ok(Self { - general: Box::new(General { - persistent: settings.persistent, - path: json_path, - name: settings.name, - driver: DriverJson::SteamDeck, - events: settings.events.unwrap_or_default(), - }), - cpus: Box::new(super::steam_deck::Cpus::from_json( - settings.cpus, - settings.version, - )), - gpu: Box::new(super::steam_deck::Gpu::from_json( - settings.gpu, - settings.version, - )), - battery: Box::new(super::steam_deck::Battery::from_json( - settings.battery, - settings.version, - )), - }), - // There's nothing special about SteamDeckAdvance, it just appears different - DriverJson::SteamDeckAdvance => Ok(Self { - general: Box::new(General { - persistent: settings.persistent, - path: json_path, - name: settings.name, - driver: DriverJson::SteamDeckAdvance, - events: settings.events.unwrap_or_default(), - }), - cpus: Box::new(super::steam_deck::Cpus::from_json( - settings.cpus, - settings.version, - )), - gpu: Box::new(super::steam_deck::Gpu::from_json( - settings.gpu, - settings.version, - )), - battery: Box::new(super::steam_deck::Battery::from_json( - settings.battery, - settings.version, - )), - }), - DriverJson::Generic | DriverJson::GenericAMD => { - Ok(super::detect::auto_detect0(Some(settings), json_path, name)) - } - DriverJson::Unknown => { - Ok(super::detect::auto_detect0(Some(settings), json_path, name)) - } - DriverJson::AutoDetect => { - Ok(super::detect::auto_detect0(Some(settings), json_path, name)) - } - } - } else { - Ok(super::detect::auto_detect0(Some(settings), json_path, name)) - } + ) -> Self { + let name_bup = settings.name.clone(); + auto_detect0(Some(settings), json_path, name_bup) } pub fn system_default(json_path: std::path::PathBuf, name: String) -> Self { diff --git a/backend/src/settings/general.rs b/backend/src/settings/general.rs index 1f47bc2..a4b7844 100644 --- a/backend/src/settings/general.rs +++ b/backend/src/settings/general.rs @@ -156,27 +156,19 @@ impl OnSet for Settings { impl Settings { #[inline] pub fn from_json(other: SettingsJson, json_path: PathBuf) -> Self { - let name_bup = other.name.clone(); - match super::Driver::init(other, json_path.clone()) { - Ok(x) => { - log::info!( - "Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", - x.general.provider(), - x.cpus.provider(), - x.gpu.provider(), - x.battery.provider() - ); - Self { - general: x.general, - cpus: x.cpus, - gpu: x.gpu, - battery: x.battery, - } - } - Err(e) => { - log::error!("Driver init error: {}", e); - Self::system_default(json_path, name_bup) - } + let x = super::Driver::init(other, json_path.clone()); + log::info!( + "Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", + x.general.provider(), + x.cpus.provider(), + x.gpu.provider(), + x.battery.provider() + ); + Self { + general: x.general, + cpus: x.cpus, + gpu: x.gpu, + battery: x.battery, } } @@ -219,22 +211,12 @@ impl Settings { *self.general.persistent() = false; self.general.name(name); } else { - match super::Driver::init(settings_json, json_path.clone()) { - Ok(x) => { - log::info!("Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", x.general.provider(), x.cpus.provider(), x.gpu.provider(), x.battery.provider()); - self.general = x.general; - self.cpus = x.cpus; - self.gpu = x.gpu; - self.battery = x.battery; - } - Err(e) => { - log::error!("Driver init error: {}", e); - self.general.name(name); - *self.general.persistent() = false; - self.general.path(json_path); - return Err(e); - } - }; + let x = super::Driver::init(settings_json, json_path.clone()); + log::info!("Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}", x.general.provider(), x.cpus.provider(), x.gpu.provider(), x.battery.provider()); + self.general = x.general; + self.cpus = x.cpus; + self.gpu = x.gpu; + self.battery = x.battery; } } else { if system_defaults { diff --git a/backend/src/settings/generic/battery.rs b/backend/src/settings/generic/battery.rs index 81464dd..2c64075 100644 --- a/backend/src/settings/generic/battery.rs +++ b/backend/src/settings/generic/battery.rs @@ -1,10 +1,10 @@ use std::convert::Into; -use limits_core::json::GenericBatteryLimit; +use limits_core::json_v2::GenericBatteryLimit; use sysfuss::SysEntity; use crate::persist::BatteryJson; -use crate::settings::TBattery; +use crate::settings::{TBattery, ProviderBuilder}; use crate::settings::{OnResume, OnSet, SettingError}; #[derive(Debug, Clone)] @@ -56,24 +56,26 @@ impl Battery { } } } +} - pub fn from_limits(limits: limits_core::json::GenericBatteryLimit) -> Self { - // TODO - Self { - limits, - sysfs: Self::find_psu_sysfs(None::<&'static str>), - } - } - - pub fn from_json_and_limits( - other: BatteryJson, +impl ProviderBuilder for Battery { + fn from_json_and_limits( + persistent: BatteryJson, _version: u64, - limits: limits_core::json::GenericBatteryLimit, + limits: GenericBatteryLimit, ) -> Self { // TODO Self { limits, - sysfs: Self::find_psu_sysfs(other.root) + sysfs: Self::find_psu_sysfs(persistent.root) + } + } + + fn from_limits(limits: GenericBatteryLimit) -> Self { + // TODO + Self { + limits, + sysfs: Self::find_psu_sysfs(None::<&'static str>), } } } diff --git a/backend/src/settings/generic/cpu.rs b/backend/src/settings/generic/cpu.rs index 00f7dbe..40d2056 100644 --- a/backend/src/settings/generic/cpu.rs +++ b/backend/src/settings/generic/cpu.rs @@ -1,13 +1,13 @@ use std::convert::{AsMut, AsRef, Into}; -use limits_core::json::GenericCpuLimit; +use limits_core::json_v2::{GenericCpusLimit, 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}; -use crate::settings::{TCpu, TCpus}; +use crate::settings::{TCpu, TCpus, ProviderBuilder}; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; @@ -87,31 +87,15 @@ impl + AsRef + TCpu + FromGenericCpuInfo> Cpus { Err(_) => (false, false), } } +} - pub fn from_limits(limits: limits_core::json::GenericCpuLimit) -> Self { - let cpu_count = Self::cpu_count().unwrap_or(8); - let (_, can_smt) = Self::system_smt_capabilities(); - let mut new_cpus = Vec::with_capacity(cpu_count); - for i in 0..cpu_count { - let new_cpu = C::from_limits(i, limits.clone()); - new_cpus.push(new_cpu); - } - Self { - cpus: new_cpus, - smt: true, - smt_capable: can_smt, - } - } - - pub fn from_json_and_limits( - mut other: Vec, - version: u64, - limits: limits_core::json::GenericCpuLimit, - ) -> Self { +impl + AsRef + TCpu + FromGenericCpuInfo> ProviderBuilder, GenericCpusLimit> for Cpus { + fn from_json_and_limits(mut other: Vec, version: u64, limits: GenericCpusLimit) -> Self { let (_, can_smt) = Self::system_smt_capabilities(); let mut result = Vec::with_capacity(other.len()); let max_cpus = Self::cpu_count(); let smt_guess = crate::settings::util::guess_smt(&other) && can_smt; + let fallback_cpu_limit = GenericCpuLimit::default(); for (i, cpu) in other.drain(..).enumerate() { // prevent having more CPUs than available if let Some(max_cpus) = max_cpus { @@ -119,7 +103,10 @@ impl + AsRef + TCpu + FromGenericCpuInfo> Cpus { break; } } - let new_cpu = C::from_json_and_limits(cpu, version, i, limits.clone()); + let cpu_limit = limits.cpus.get(i) + .or_else(|| limits.cpus.get(0)) + .unwrap_or_else(|| &fallback_cpu_limit).clone(); + let new_cpu = C::from_json_and_limits(cpu, version, i, cpu_limit); result.push(new_cpu); } if let Some(max_cpus) = max_cpus { @@ -136,6 +123,25 @@ impl + AsRef + TCpu + FromGenericCpuInfo> Cpus { smt_capable: can_smt, } } + + fn from_limits(limits: GenericCpusLimit) -> Self { + let cpu_count = Self::cpu_count().unwrap_or(8); + let (_, can_smt) = Self::system_smt_capabilities(); + let mut new_cpus = Vec::with_capacity(cpu_count); + let fallback_cpu_limit = GenericCpuLimit::default(); + for i in 0..cpu_count { + let cpu_limit = limits.cpus.get(i) + .or_else(|| limits.cpus.get(0)) + .unwrap_or_else(|| &fallback_cpu_limit).clone(); + let new_cpu = C::from_limits(i, cpu_limit); + new_cpus.push(new_cpu); + } + Self { + cpus: new_cpus, + smt: true, + smt_capable: can_smt, + } + } } impl + AsRef + TCpu + crate::settings::OnPowerEvent> @@ -345,7 +351,7 @@ impl Cpu { .clock_max .clone() .map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(5_000))), - clock_step: self.limits.clock_step, + clock_step: self.limits.clock_step.unwrap_or(100), governors: self.governors(), } } diff --git a/backend/src/settings/generic/gpu.rs b/backend/src/settings/generic/gpu.rs index b8fcb6c..0bee174 100644 --- a/backend/src/settings/generic/gpu.rs +++ b/backend/src/settings/generic/gpu.rs @@ -1,11 +1,11 @@ use std::convert::Into; -use limits_core::json::GenericGpuLimit; +use limits_core::json_v2::GenericGpuLimit; use sysfuss::{BasicEntityPath, SysEntity}; use crate::api::RangeLimit; use crate::persist::GpuJson; -use crate::settings::TGpu; +use crate::settings::{TGpu, ProviderBuilder}; use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{OnResume, OnSet, SettingError}; @@ -49,8 +49,34 @@ impl Gpu { } } } +} - pub fn from_limits(limits: limits_core::json::GenericGpuLimit) -> Self { +impl ProviderBuilder for Gpu { + fn from_json_and_limits(persistent: GpuJson, version: u64, limits: GenericGpuLimit) -> Self { + let clock_lims = if limits.clock_min.is_some() && limits.clock_max.is_some() { + persistent.clock_limits.map(|x| min_max_from_json(x, version)) + } else { + None + }; + Self { + slow_memory: false, + fast_ppt: if limits.fast_ppt.is_some() { + persistent.fast_ppt + } else { + None + }, + slow_ppt: if limits.slow_ppt.is_some() { + persistent.slow_ppt + } else { + None + }, + clock_limits: clock_lims, + limits, + sysfs: Self::find_card_sysfs(persistent.root) + } + } + + fn from_limits(limits: GenericGpuLimit) -> Self { Self { slow_memory: false, fast_ppt: None, @@ -60,34 +86,6 @@ impl Gpu { sysfs: Self::find_card_sysfs(None::<&'static str>), } } - - pub fn from_json_and_limits( - other: GpuJson, - version: u64, - limits: limits_core::json::GenericGpuLimit, - ) -> Self { - let clock_lims = if limits.clock_min.is_some() && limits.clock_max.is_some() { - other.clock_limits.map(|x| min_max_from_json(x, version)) - } else { - None - }; - Self { - slow_memory: false, - fast_ppt: if limits.fast_ppt.is_some() { - other.fast_ppt - } else { - None - }, - slow_ppt: if limits.slow_ppt.is_some() { - other.slow_ppt - } else { - None - }, - clock_limits: clock_lims, - limits, - sysfs: Self::find_card_sysfs(other.root) - } - } } impl Into for Gpu { diff --git a/backend/src/settings/generic/mod.rs b/backend/src/settings/generic/mod.rs index 6989a23..9a99d47 100644 --- a/backend/src/settings/generic/mod.rs +++ b/backend/src/settings/generic/mod.rs @@ -7,3 +7,11 @@ pub use battery::Battery; pub use cpu::{Cpu, Cpus}; pub use gpu::Gpu; pub use traits::FromGenericCpuInfo; + +fn _impl_checker() { + fn impl_provider_builder, J, L>() {} + + impl_provider_builder::(); + impl_provider_builder::, Vec, limits_core::json_v2::GenericCpusLimit>(); + impl_provider_builder::(); +} diff --git a/backend/src/settings/generic/traits.rs b/backend/src/settings/generic/traits.rs index a8674bb..58d91ad 100644 --- a/backend/src/settings/generic/traits.rs +++ b/backend/src/settings/generic/traits.rs @@ -1,6 +1,7 @@ use crate::persist::CpuJson; -use limits_core::json::GenericCpuLimit; +use limits_core::json_v2::GenericCpuLimit; +// similar to crate::settings::ProviderBuilder pub trait FromGenericCpuInfo { fn from_limits(cpu_index: usize, limits: GenericCpuLimit) -> Self; diff --git a/backend/src/settings/generic_amd/cpu.rs b/backend/src/settings/generic_amd/cpu.rs index 48e119c..07aef41 100644 --- a/backend/src/settings/generic_amd/cpu.rs +++ b/backend/src/settings/generic_amd/cpu.rs @@ -2,24 +2,24 @@ use crate::persist::CpuJson; use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus, FromGenericCpuInfo}; use crate::settings::MinMax; use crate::settings::{OnResume, OnSet, SettingError}; -use crate::settings::{TCpu, TCpus}; +use crate::settings::{TCpu, TCpus, ProviderBuilder}; #[derive(Debug)] pub struct Cpus { generic: GenericCpus, } -impl Cpus { - pub fn from_limits(limits: limits_core::json::GenericCpuLimit) -> Self { +impl ProviderBuilder, limits_core::json_v2::GenericCpusLimit> for Cpus { + fn from_limits(limits: limits_core::json_v2::GenericCpusLimit) -> Self { Self { generic: GenericCpus::from_limits(limits), } } - pub fn from_json_and_limits( + fn from_json_and_limits( other: Vec, version: u64, - limits: limits_core::json::GenericCpuLimit, + limits: limits_core::json_v2::GenericCpusLimit, ) -> Self { Self { generic: GenericCpus::from_json_and_limits(other, version, limits), @@ -75,7 +75,7 @@ pub struct Cpu { } impl FromGenericCpuInfo for Cpu { - fn from_limits(cpu_index: usize, limits: limits_core::json::GenericCpuLimit) -> Self { + fn from_limits(cpu_index: usize, limits: limits_core::json_v2::GenericCpuLimit) -> Self { let gen = GenericCpu::from_limits(cpu_index, limits.clone()); Self { generic: gen } } @@ -84,7 +84,7 @@ impl FromGenericCpuInfo for Cpu { other: CpuJson, version: u64, cpu_index: usize, - limits: limits_core::json::GenericCpuLimit, + limits: limits_core::json_v2::GenericCpuLimit, ) -> Self { let gen = GenericCpu::from_json_and_limits(other, version, cpu_index, limits); Self { generic: gen } diff --git a/backend/src/settings/generic_amd/gpu.rs b/backend/src/settings/generic_amd/gpu.rs index 9af3bc2..9d0090b 100644 --- a/backend/src/settings/generic_amd/gpu.rs +++ b/backend/src/settings/generic_amd/gpu.rs @@ -4,7 +4,7 @@ use std::sync::Mutex; use crate::persist::GpuJson; use crate::settings::generic::Gpu as GenericGpu; use crate::settings::MinMax; -use crate::settings::TGpu; +use crate::settings::{TGpu, ProviderBuilder}; use crate::settings::{OnResume, OnSet, SettingError, SettingVariant}; fn ryzen_adj_or_log() -> Option> { @@ -35,8 +35,8 @@ impl std::fmt::Debug for Gpu { } } -impl Gpu { - pub fn from_limits(limits: limits_core::json::GenericGpuLimit) -> Self { +impl ProviderBuilder for Gpu { + fn from_limits(limits: limits_core::json_v2::GenericGpuLimit) -> Self { Self { generic: GenericGpu::from_limits(limits), implementor: ryzen_adj_or_log(), @@ -44,10 +44,10 @@ impl Gpu { } } - pub fn from_json_and_limits( + fn from_json_and_limits( other: GpuJson, version: u64, - limits: limits_core::json::GenericGpuLimit, + limits: limits_core::json_v2::GenericGpuLimit, ) -> Self { Self { generic: GenericGpu::from_json_and_limits(other, version, limits), @@ -55,6 +55,9 @@ impl Gpu { state: Default::default(), } } +} + +impl Gpu { fn set_all(&mut self) -> Result<(), Vec> { let mutex = match &self.implementor { diff --git a/backend/src/settings/generic_amd/mod.rs b/backend/src/settings/generic_amd/mod.rs index 6a8e412..0f443a9 100644 --- a/backend/src/settings/generic_amd/mod.rs +++ b/backend/src/settings/generic_amd/mod.rs @@ -3,3 +3,10 @@ mod gpu; pub use cpu::{Cpu, Cpus}; pub use gpu::Gpu; + +fn _impl_checker() { + fn impl_provider_builder, J, L>() {} + + impl_provider_builder::, limits_core::json_v2::GenericCpusLimit>(); + impl_provider_builder::(); +} diff --git a/backend/src/settings/mod.rs b/backend/src/settings/mod.rs index c3a0044..5aa3483 100644 --- a/backend/src/settings/mod.rs +++ b/backend/src/settings/mod.rs @@ -17,7 +17,7 @@ pub use general::{General, SettingVariant, Settings}; pub use min_max::{min_max_from_json, MinMax}; pub use error::SettingError; -pub use traits::{OnPowerEvent, OnResume, OnSet, PowerMode, TBattery, TCpu, TCpus, TGeneral, TGpu}; +pub use traits::{OnPowerEvent, OnResume, OnSet, PowerMode, TBattery, TCpu, TCpus, TGeneral, TGpu, ProviderBuilder}; #[cfg(test)] mod tests { diff --git a/backend/src/settings/steam_deck/battery.rs b/backend/src/settings/steam_deck/battery.rs index d5b800e..07ac1a9 100644 --- a/backend/src/settings/steam_deck/battery.rs +++ b/backend/src/settings/steam_deck/battery.rs @@ -4,11 +4,12 @@ use std::sync::Arc; use sysfuss::{PowerSupplyAttribute, PowerSupplyPath, HwMonAttribute, HwMonAttributeItem, HwMonAttributeType, HwMonPath, SysEntity, SysEntityAttributesExt, SysAttribute}; use sysfuss::capability::attributes; -use super::oc_limits::{BatteryLimits, OverclockLimits}; +use limits_core::json_v2::GenericBatteryLimit; + use super::util::ChargeMode; use crate::api::RangeLimit; use crate::persist::{BatteryEventJson, BatteryJson}; -use crate::settings::TBattery; +use crate::settings::{TBattery, ProviderBuilder}; use crate::settings::{OnPowerEvent, OnResume, OnSet, PowerMode, SettingError}; #[derive(Debug, Clone)] @@ -16,9 +17,8 @@ pub struct Battery { pub charge_rate: Option, pub charge_mode: Option, events: Vec, - limits: BatteryLimits, + limits: GenericBatteryLimit, state: crate::state::steam_deck::Battery, - driver_mode: crate::persist::DriverJson, sysfs_bat: PowerSupplyPath, sysfs_hwmon: Arc, } @@ -217,55 +217,10 @@ const MAXIMUM_BATTERY_CHARGE_RATE_ATTR: HwMonAttribute = HwMonAttribute::custom( const MAX_BATTERY_CHARGE_RATE_ATTR: HwMonAttribute = HwMonAttribute::custom("maximum_battery_charge_rate"); const MAX_BATTERY_CHARGE_LEVEL_ATTR: HwMonAttribute = HwMonAttribute::custom("max_battery_charge_level"); -impl Battery { - #[inline] - pub fn from_json(other: BatteryJson, version: u64) -> Self { - let (oc_limits, is_default) = OverclockLimits::load_or_default(); - let oc_limits = oc_limits.battery; - let driver = if is_default { - crate::persist::DriverJson::SteamDeck - } else { - crate::persist::DriverJson::SteamDeckAdvance - }; - let hwmon_sys = Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)); - match version { - 0 => Self { - charge_rate: other.charge_rate, - charge_mode: other - .charge_mode - .map(|x| Self::str_to_charge_mode(&x)) - .flatten(), - events: other - .events - .into_iter() - .map(|x| EventInstruction::from_json(x, version, hwmon_sys.clone())) - .collect(), - limits: oc_limits, - state: crate::state::steam_deck::Battery::default(), - driver_mode: driver, - sysfs_bat: Self::find_battery_sysfs(None::<&'static str>), - sysfs_hwmon: hwmon_sys, - }, - _ => Self { - charge_rate: other.charge_rate, - charge_mode: other - .charge_mode - .map(|x| Self::str_to_charge_mode(&x)) - .flatten(), - events: other - .events - .into_iter() - .map(|x| EventInstruction::from_json(x, version, hwmon_sys.clone())) - .collect(), - limits: oc_limits, - state: crate::state::steam_deck::Battery::default(), - driver_mode: driver, - sysfs_bat: Self::find_battery_sysfs(None::<&'static str>), - sysfs_hwmon: hwmon_sys, - }, - } - } +const MAX_CHARGE_RATE: u64 = 2500; +const MIN_CHARGE_RATE: u64 = 250; +impl Battery { fn find_battery_sysfs(root: Option>) -> PowerSupplyPath { let root = crate::settings::util::root_or_default_sysfs(root); match root.power_supply(attributes(BATTERY_NEEDS.into_iter().copied())) { @@ -360,7 +315,7 @@ impl Battery { MAXIMUM_BATTERY_CHARGE_RATE_ATTR }; let path = attr.path(&*self.sysfs_hwmon); - self.sysfs_hwmon.set(attr, self.limits.charge_rate.max,).map_err( + self.sysfs_hwmon.set(attr, self.limits.charge_rate.and_then(|lim| lim.max).unwrap_or(2500)).map_err( |e| SettingError { msg: format!("Failed to write to `{}`: {}", path.display(), e), setting: crate::settings::SettingVariant::Battery, @@ -407,7 +362,7 @@ impl Battery { fn clamp_all(&mut self) { if let Some(charge_rate) = &mut self.charge_rate { *charge_rate = - (*charge_rate).clamp(self.limits.charge_rate.min, self.limits.charge_rate.max); + (*charge_rate).clamp(self.limits.charge_rate.and_then(|lim| lim.min).unwrap_or(MIN_CHARGE_RATE), self.limits.charge_rate.and_then(|lim| lim.max).unwrap_or(MAX_CHARGE_RATE)); } } @@ -489,26 +444,6 @@ impl Battery { } } - pub fn system_default() -> Self { - let (oc_limits, is_default) = OverclockLimits::load_or_default(); - let oc_limits = oc_limits.battery; - let driver = if is_default { - crate::persist::DriverJson::SteamDeck - } else { - crate::persist::DriverJson::SteamDeckAdvance - }; - Self { - charge_rate: None, - charge_mode: None, - events: Vec::new(), - limits: oc_limits, - state: crate::state::steam_deck::Battery::default(), - driver_mode: driver, - sysfs_bat: Self::find_battery_sysfs(None::<&'static str>), - sysfs_hwmon: Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)), - } - } - fn find_limit_event(&self) -> Option { for (i, event) in self.events.iter().enumerate() { match event.trigger { @@ -550,6 +485,58 @@ impl Into for Battery { } } +impl ProviderBuilder for Battery { + fn from_json_and_limits(persistent: BatteryJson, version: u64, limits: GenericBatteryLimit) -> Self { + let hwmon_sys = Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)); + match version { + 0 => Self { + charge_rate: persistent.charge_rate, + charge_mode: persistent + .charge_mode + .map(|x| Self::str_to_charge_mode(&x)) + .flatten(), + events: persistent + .events + .into_iter() + .map(|x| EventInstruction::from_json(x, version, hwmon_sys.clone())) + .collect(), + limits: limits, + state: crate::state::steam_deck::Battery::default(), + sysfs_bat: Self::find_battery_sysfs(None::<&'static str>), + sysfs_hwmon: hwmon_sys, + }, + _ => Self { + charge_rate: persistent.charge_rate, + charge_mode: persistent + .charge_mode + .map(|x| Self::str_to_charge_mode(&x)) + .flatten(), + events: persistent + .events + .into_iter() + .map(|x| EventInstruction::from_json(x, version, hwmon_sys.clone())) + .collect(), + limits: limits, + state: crate::state::steam_deck::Battery::default(), + sysfs_bat: Self::find_battery_sysfs(None::<&'static str>), + sysfs_hwmon: hwmon_sys, + }, + } + } + + fn from_limits(limits: GenericBatteryLimit) -> Self { + Self { + charge_rate: None, + charge_mode: None, + events: Vec::new(), + limits: limits, + state: crate::state::steam_deck::Battery::default(), + sysfs_bat: Self::find_battery_sysfs(None::<&'static str>), + sysfs_hwmon: Arc::new(Self::find_hwmon_sysfs(None::<&'static str>)), + } + } +} + impl OnSet for Battery { fn on_set(&mut self) -> Result<(), Vec> { self.clamp_all(); @@ -631,8 +618,8 @@ impl TBattery for Battery { fn limits(&self) -> crate::api::BatteryLimits { crate::api::BatteryLimits { charge_current: Some(RangeLimit { - min: self.limits.charge_rate.min, - max: self.limits.charge_rate.max, + min: self.limits.charge_rate.and_then(|lim| lim.min).unwrap_or(MIN_CHARGE_RATE), + max: self.limits.charge_rate.and_then(|lim| lim.max).unwrap_or(MAX_CHARGE_RATE), }), charge_current_step: 50, charge_modes: vec![ @@ -844,6 +831,6 @@ impl TBattery for Battery { } fn provider(&self) -> crate::persist::DriverJson { - self.driver_mode.clone() + crate::persist::DriverJson::SteamDeck } } diff --git a/backend/src/settings/steam_deck/cpu.rs b/backend/src/settings/steam_deck/cpu.rs index c6ac04e..3a5cc56 100644 --- a/backend/src/settings/steam_deck/cpu.rs +++ b/backend/src/settings/steam_deck/cpu.rs @@ -2,13 +2,15 @@ use std::convert::Into; use sysfuss::{BasicEntityPath, SysEntity, SysEntityAttributesExt}; -use super::oc_limits::{CpuLimits, CpusLimits, OverclockLimits}; +use limits_core::json_v2::{GenericCpusLimit, GenericCpuLimit}; + use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT; +use super::util::{range_max_or_fallback, range_min_or_fallback}; use crate::api::RangeLimit; use crate::persist::CpuJson; use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{OnResume, OnSet, SettingError}; -use crate::settings::{TCpu, TCpus}; +use crate::settings::{TCpu, TCpus, ProviderBuilder}; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; @@ -17,13 +19,17 @@ const CARD_EXTENSIONS: &[&'static str] = &[ super::DPM_FORCE_LIMITS_ATTRIBUTE ]; +const MAX_CLOCK: u64 = 3500; +const MIN_MAX_CLOCK: u64 = 200; // minimum value allowed for maximum CPU clock, MHz +const MIN_MIN_CLOCK: u64 = 1400; // minimum value allowed for minimum CPU clock, MHz +const CLOCK_STEP: u64 = 100; + #[derive(Debug, Clone)] pub struct Cpus { pub cpus: Vec, pub smt: bool, pub smt_capable: bool, - pub(super) limits: CpusLimits, - driver_mode: crate::persist::DriverJson, + pub(super) limits: GenericCpusLimit, } impl OnSet for Cpus { @@ -94,85 +100,42 @@ impl Cpus { Err(_) => (false, false), } } +} - pub fn system_default() -> Self { +impl ProviderBuilder, GenericCpusLimit> for Cpus { + fn from_json_and_limits(mut persistent: Vec, version: u64, limits: GenericCpusLimit) -> Self { POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset(); - let (oc_limits, is_default) = OverclockLimits::load_or_default(); - let oc_limits = oc_limits.cpus; - let driver = if is_default { - crate::persist::DriverJson::SteamDeck - } else { - crate::persist::DriverJson::SteamDeckAdvance - }; - if let Some(max_cpu) = Self::cpu_count() { - let mut sys_cpus = Vec::with_capacity(max_cpu); - for i in 0..max_cpu { - sys_cpus.push(Cpu::system_default( - i, - oc_limits - .cpus - .get(i) - .map(|x| x.to_owned()) - .unwrap_or_default(), - )); - } - let (_, can_smt) = Self::system_smt_capabilities(); - Self { - cpus: sys_cpus, - smt: true, - smt_capable: can_smt, - limits: oc_limits, - driver_mode: driver, - } - } else { - Self { - cpus: vec![], - smt: false, - smt_capable: false, - limits: oc_limits, - driver_mode: driver, - } - } - } - - #[inline] - pub fn from_json(mut other: Vec, version: u64) -> Self { - POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset(); - let (oc_limits, is_default) = OverclockLimits::load_or_default(); - let oc_limits = oc_limits.cpus; - let driver = if is_default { - crate::persist::DriverJson::SteamDeck - } else { - crate::persist::DriverJson::SteamDeckAdvance - }; let (_, can_smt) = Self::system_smt_capabilities(); - let mut result = Vec::with_capacity(other.len()); + let mut result = Vec::with_capacity(persistent.len()); let max_cpus = Self::cpu_count(); - let smt_guess = crate::settings::util::guess_smt(&other) && can_smt; - for (i, cpu) in other.drain(..).enumerate() { + let smt_guess = crate::settings::util::guess_smt(&persistent) && can_smt; + for (i, cpu) in persistent.drain(..).enumerate() { // prevent having more CPUs than available if let Some(max_cpus) = max_cpus { if i == max_cpus { break; } } - let new_cpu = Cpu::from_json( - cpu, - version, - i, - oc_limits - .cpus - .get(i) - .map(|x| x.to_owned()) - .unwrap_or_default(), - ); + let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) { + Cpu::from_json_and_limits( + cpu, + version, + i, + cpu_limit.to_owned() + ) + } else { + Cpu::from_json( + cpu, + version, + i, + ) + }; result.push(new_cpu); } if let Some(max_cpus) = max_cpus { if result.len() != max_cpus { - let mut sys_cpus = Cpus::system_default(); - for i in result.len()..sys_cpus.cpus.len() { - result.push(sys_cpus.cpus.remove(i)); + for i in result.len()..max_cpus { + result.push(Cpu::system_default(i)); } } } @@ -180,8 +143,39 @@ impl Cpus { cpus: result, smt: smt_guess, smt_capable: can_smt, - limits: oc_limits, - driver_mode: driver, + limits: limits, + } + } + + fn from_limits(limits: GenericCpusLimit) -> Self { + POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.reset(); + if let Some(max_cpu) = Self::cpu_count() { + let mut sys_cpus = Vec::with_capacity(max_cpu); + for i in 0..max_cpu { + let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) { + Cpu::from_limits( + i, + cpu_limit.to_owned() + ) + } else { + Cpu::system_default(i) + }; + sys_cpus.push(new_cpu); + } + let (_, can_smt) = Self::system_smt_capabilities(); + Self { + cpus: sys_cpus, + smt: true, + smt_capable: can_smt, + limits: limits, + } + } else { + Self { + cpus: vec![], + smt: false, + smt_capable: false, + limits: limits, + } } } } @@ -224,7 +218,7 @@ impl TCpus for Cpus { } fn provider(&self) -> crate::persist::DriverJson { - self.driver_mode.clone() + crate::persist::DriverJson::SteamDeck } } @@ -233,7 +227,7 @@ pub struct Cpu { pub online: bool, pub clock_limits: Option>, pub governor: String, - limits: CpuLimits, + limits: GenericCpuLimit, index: usize, state: crate::state::steam_deck::Cpu, sysfs: BasicEntityPath, @@ -249,7 +243,7 @@ enum ClockType { impl Cpu { #[inline] - fn from_json(other: CpuJson, version: u64, i: usize, oc_limits: CpuLimits) -> Self { + fn from_json_and_limits(other: CpuJson, version: u64, i: usize, oc_limits: GenericCpuLimit) -> Self { match version { 0 => Self { online: other.online, @@ -272,6 +266,12 @@ impl Cpu { } } + #[inline] + fn from_json(other: CpuJson, version: u64, i: usize) -> Self { + let oc_limits = GenericCpuLimit::default_for(&limits_core::json_v2::CpuLimitType::SteamDeck, i); + Self::from_json_and_limits(other, version, i, oc_limits) + } + fn find_card_sysfs(root: Option>) -> BasicEntityPath { let root = crate::settings::util::root_or_default_sysfs(root); match root.class("drm", sysfuss::capability::attributes(crate::settings::util::CARD_NEEDS.into_iter().map(|s| s.to_string()))) { @@ -338,8 +338,8 @@ impl Cpu { } // min clock if let Some(min) = clock_limits.min { - let valid_min = if min < self.limits.clock_min.min { - self.limits.clock_min.min + let valid_min = if min < range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) { + range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK) } else { min }; @@ -367,10 +367,10 @@ impl Cpu { // disable manual clock limits log::debug!("Setting CPU {} to default clockspeed", self.index); // max clock - self.set_clock_limit(self.index, self.limits.clock_max.max, ClockType::Max) + self.set_clock_limit(self.index, range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), ClockType::Max) .unwrap_or_else(|e| errors.push(e)); // min clock - self.set_clock_limit(self.index, self.limits.clock_min.min, ClockType::Min) + self.set_clock_limit(self.index, range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK), ClockType::Min) .unwrap_or_else(|e| errors.push(e)); } // TODO remove this when it's no longer needed @@ -395,10 +395,10 @@ impl Cpu { // disable manual clock limits log::debug!("Setting CPU {} to default clockspeed", self.index); // max clock - self.set_clock_limit(self.index, self.limits.clock_max.max, ClockType::Max) + self.set_clock_limit(self.index, range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), ClockType::Max) .unwrap_or_else(|e| errors.push(e)); // min clock - self.set_clock_limit(self.index, self.limits.clock_min.min, ClockType::Min) + self.set_clock_limit(self.index, range_min_or_fallback(&self.limits.clock_min, MIN_MIN_CLOCK), ClockType::Min) .unwrap_or_else(|e| errors.push(e)); self.set_confirm().unwrap_or_else(|e| errors.push(e)); @@ -493,11 +493,11 @@ impl Cpu { if let Some(clock_limits) = &mut self.clock_limits { if let Some(min) = clock_limits.min { clock_limits.min = - Some(min.clamp(self.limits.clock_max.min, self.limits.clock_min.max)); + Some(min.clamp(range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK))); } if let Some(max) = clock_limits.max { clock_limits.max = - Some(max.clamp(self.limits.clock_max.min, self.limits.clock_max.max)); + Some(max.clamp(range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK))); } } } @@ -514,7 +514,7 @@ impl Cpu { } }*/ - fn system_default(cpu_index: usize, oc_limits: CpuLimits) -> Self { + fn from_limits(cpu_index: usize, oc_limits: GenericCpuLimit) -> Self { Self { online: true, clock_limits: None, @@ -526,17 +526,21 @@ impl Cpu { } } + fn system_default(cpu_index: usize) -> Self { + Self::from_limits(cpu_index, GenericCpuLimit::default_for(&limits_core::json_v2::CpuLimitType::SteamDeck, cpu_index)) + } + fn limits(&self) -> crate::api::CpuLimits { crate::api::CpuLimits { clock_min_limits: Some(RangeLimit { - min: self.limits.clock_max.min, // allows min to be set by max (it's weird, blame the kernel) - max: self.limits.clock_min.max, + min: range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), // allows min to be set by max (it's weird, blame the kernel) + max: range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK), }), clock_max_limits: Some(RangeLimit { - min: self.limits.clock_max.min, - max: self.limits.clock_max.max, + min: range_min_or_fallback(&self.limits.clock_max, MIN_MAX_CLOCK), + max: range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), }), - clock_step: self.limits.clock_step, + clock_step: self.limits.clock_step.unwrap_or(CLOCK_STEP), governors: self.governors(), } } diff --git a/backend/src/settings/steam_deck/gpu.rs b/backend/src/settings/steam_deck/gpu.rs index f1f428b..96316f0 100644 --- a/backend/src/settings/steam_deck/gpu.rs +++ b/backend/src/settings/steam_deck/gpu.rs @@ -2,11 +2,12 @@ use std::convert::Into; use sysfuss::{BasicEntityPath, HwMonPath, SysEntity, capability::attributes, SysEntityAttributesExt, SysAttribute}; -use super::oc_limits::{GpuLimits, OverclockLimits}; +use limits_core::json_v2::GenericGpuLimit; + use super::POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT; use crate::api::RangeLimit; use crate::persist::GpuJson; -use crate::settings::TGpu; +use crate::settings::{TGpu, ProviderBuilder}; use crate::settings::{min_max_from_json, MinMax}; use crate::settings::{OnResume, OnSet, SettingError}; @@ -20,9 +21,8 @@ pub struct Gpu { pub slow_ppt: Option, pub clock_limits: Option>, pub slow_memory: bool, - limits: GpuLimits, + limits: GenericGpuLimit, state: crate::state::steam_deck::Gpu, - driver_mode: crate::persist::DriverJson, sysfs_card: BasicEntityPath, sysfs_hwmon: HwMonPath } @@ -45,41 +45,16 @@ enum ClockType { Max = 1, } -impl Gpu { - #[inline] - pub fn from_json(other: GpuJson, version: u64) -> Self { - let (oc_limits, is_default) = OverclockLimits::load_or_default(); - let driver = if is_default { - crate::persist::DriverJson::SteamDeck - } else { - crate::persist::DriverJson::SteamDeckAdvance - }; - match version { - 0 => Self { - fast_ppt: other.fast_ppt, - slow_ppt: other.slow_ppt, - clock_limits: other.clock_limits.map(|x| min_max_from_json(x, version)), - slow_memory: other.slow_memory, - limits: oc_limits.gpu, - state: crate::state::steam_deck::Gpu::default(), - driver_mode: driver, - sysfs_card: Self::find_card_sysfs(other.root.clone()), - sysfs_hwmon: Self::find_hwmon_sysfs(other.root), - }, - _ => Self { - fast_ppt: other.fast_ppt, - slow_ppt: other.slow_ppt, - clock_limits: other.clock_limits.map(|x| min_max_from_json(x, version)), - slow_memory: other.slow_memory, - limits: oc_limits.gpu, - state: crate::state::steam_deck::Gpu::default(), - driver_mode: driver, - sysfs_card: Self::find_card_sysfs(other.root.clone()), - sysfs_hwmon: Self::find_hwmon_sysfs(other.root), - }, - } - } +const MAX_CLOCK: u64 = 1600; +const MIN_CLOCK: u64 = 200; +const MAX_FAST_PPT: u64 = 30_000_000; +const MIN_FAST_PPT: u64 = 1_000_000; +const MAX_SLOW_PPT: u64 = 29_000_000; +const MIN_SLOW_PPT: u64 = 1_000_000; +const MIDDLE_PPT: u64 = 15_000_000; +const PPT_DIVISOR: u64 = 1_000; +impl Gpu { fn find_card_sysfs(root: Option>) -> BasicEntityPath { let root = crate::settings::util::root_or_default_sysfs(root); match root.class("drm", attributes(crate::settings::util::CARD_NEEDS.into_iter().map(|s| s.to_string()))) { @@ -160,10 +135,10 @@ impl Gpu { POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs_card)?; // disable manual clock limits // max clock - self.set_clock_limit(self.limits.clock_max.max, ClockType::Max) + self.set_clock_limit(self.limits.clock_max.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK), ClockType::Max) .unwrap_or_else(|e| errors.push(e)); // min clock - self.set_clock_limit(self.limits.clock_min.min, ClockType::Min) + self.set_clock_limit(self.limits.clock_min.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), ClockType::Min) .unwrap_or_else(|e| errors.push(e)); self.set_confirm().unwrap_or_else(|e| errors.push(e)); @@ -251,7 +226,7 @@ impl Gpu { }); } else if self.state.fast_ppt_set { self.state.fast_ppt_set = false; - let fast_ppt = self.limits.fast_ppt_default; + let fast_ppt = self.limits.fast_ppt_default.unwrap_or(MIDDLE_PPT); self.sysfs_hwmon.set(FAST_PPT_ATTRIBUTE, fast_ppt) .map_err(|e| SettingError { msg: format!( @@ -280,7 +255,7 @@ impl Gpu { }); } else if self.state.slow_ppt_set { self.state.slow_ppt_set = false; - let slow_ppt = self.limits.slow_ppt_default; + let slow_ppt = self.limits.slow_ppt_default.unwrap_or(MIDDLE_PPT); self.sysfs_hwmon.set(SLOW_PPT_ATTRIBUTE, slow_ppt) .map_err(|e| SettingError { msg: format!( @@ -304,41 +279,22 @@ impl Gpu { fn clamp_all(&mut self) { if let Some(fast_ppt) = &mut self.fast_ppt { - *fast_ppt = (*fast_ppt).clamp(self.limits.fast_ppt.min, self.limits.fast_ppt.max); + *fast_ppt = (*fast_ppt).clamp(self.limits.fast_ppt.and_then(|lim| lim.min).unwrap_or(MIN_FAST_PPT), self.limits.fast_ppt.and_then(|lim| lim.max).unwrap_or(MAX_FAST_PPT)); } if let Some(slow_ppt) = &mut self.slow_ppt { - *slow_ppt = (*slow_ppt).clamp(self.limits.slow_ppt.min, self.limits.slow_ppt.max); + *slow_ppt = (*slow_ppt).clamp(self.limits.slow_ppt.and_then(|lim| lim.min).unwrap_or(MIN_SLOW_PPT), self.limits.slow_ppt.and_then(|lim| lim.max).unwrap_or(MAX_SLOW_PPT)); } if let Some(clock_limits) = &mut self.clock_limits { if let Some(min) = clock_limits.min { clock_limits.min = - Some(min.clamp(self.limits.clock_min.min, self.limits.clock_min.max)); + Some(min.clamp(self.limits.clock_min.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), self.limits.clock_min.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK))); } if let Some(max) = clock_limits.max { clock_limits.max = - Some(max.clamp(self.limits.clock_max.min, self.limits.clock_max.max)); + Some(max.clamp(self.limits.clock_max.and_then(|lim| lim.min).unwrap_or(MIN_CLOCK), self.limits.clock_max.and_then(|lim| lim.max).unwrap_or(MAX_CLOCK))); } } } - - pub fn system_default() -> Self { - let (oc_limits, is_default) = OverclockLimits::load_or_default(); - Self { - fast_ppt: None, - slow_ppt: None, - clock_limits: None, - slow_memory: false, - limits: oc_limits.gpu, - state: crate::state::steam_deck::Gpu::default(), - driver_mode: if is_default { - crate::persist::DriverJson::SteamDeck - } else { - crate::persist::DriverJson::SteamDeckAdvance - }, - sysfs_card: Self::find_card_sysfs(None::<&'static str>), - sysfs_hwmon: Self::find_hwmon_sysfs(None::<&'static str>), - } - } } impl Into for Gpu { @@ -354,6 +310,46 @@ impl Into for Gpu { } } +impl ProviderBuilder for Gpu { + fn from_json_and_limits(persistent: GpuJson, version: u64, limits: GenericGpuLimit) -> Self { + match version { + 0 => Self { + fast_ppt: persistent.fast_ppt, + slow_ppt: persistent.slow_ppt, + clock_limits: persistent.clock_limits.map(|x| min_max_from_json(x, version)), + slow_memory: persistent.slow_memory, + limits: limits, + state: crate::state::steam_deck::Gpu::default(), + sysfs_card: Self::find_card_sysfs(persistent.root.clone()), + sysfs_hwmon: Self::find_hwmon_sysfs(persistent.root), + }, + _ => Self { + fast_ppt: persistent.fast_ppt, + slow_ppt: persistent.slow_ppt, + clock_limits: persistent.clock_limits.map(|x| min_max_from_json(x, version)), + slow_memory: persistent.slow_memory, + limits: limits, + state: crate::state::steam_deck::Gpu::default(), + sysfs_card: Self::find_card_sysfs(persistent.root.clone()), + sysfs_hwmon: Self::find_hwmon_sysfs(persistent.root), + }, + } + } + + fn from_limits(limits: GenericGpuLimit) -> Self { + Self { + fast_ppt: None, + slow_ppt: None, + clock_limits: None, + slow_memory: false, + limits: limits, + state: crate::state::steam_deck::Gpu::default(), + sysfs_card: Self::find_card_sysfs(None::<&'static str>), + sysfs_hwmon: Self::find_hwmon_sysfs(None::<&'static str>), + } + } +} + impl OnSet for Gpu { fn on_set(&mut self) -> Result<(), Vec> { self.clamp_all(); @@ -375,26 +371,26 @@ impl TGpu for Gpu { fn limits(&self) -> crate::api::GpuLimits { crate::api::GpuLimits { fast_ppt_limits: Some(RangeLimit { - min: self.limits.fast_ppt.min / self.limits.ppt_divisor, - max: self.limits.fast_ppt.max / self.limits.ppt_divisor, + min: super::util::range_min_or_fallback(&self.limits.fast_ppt, MIN_FAST_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), + max: super::util::range_max_or_fallback(&self.limits.fast_ppt, MAX_FAST_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), }), slow_ppt_limits: Some(RangeLimit { - min: self.limits.slow_ppt.min / self.limits.ppt_divisor, - max: self.limits.slow_ppt.max / self.limits.ppt_divisor, + min: super::util::range_min_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), + max: super::util::range_max_or_fallback(&self.limits.slow_ppt, MIN_SLOW_PPT) / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR), }), - ppt_step: self.limits.ppt_step, + ppt_step: self.limits.ppt_step.unwrap_or(1), tdp_limits: None, tdp_boost_limits: None, tdp_step: 42, clock_min_limits: Some(RangeLimit { - min: self.limits.clock_min.min, - max: self.limits.clock_min.max, + min: super::util::range_min_or_fallback(&self.limits.clock_min, MIN_CLOCK), + max: super::util::range_max_or_fallback(&self.limits.clock_min, MAX_CLOCK), }), clock_max_limits: Some(RangeLimit { - min: self.limits.clock_max.min, - max: self.limits.clock_max.max, + min: super::util::range_min_or_fallback(&self.limits.clock_max, MIN_CLOCK), + max: super::util::range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK), }), - clock_step: self.limits.clock_step, + clock_step: self.limits.clock_step.unwrap_or(100), memory_control_capable: true, } } @@ -404,14 +400,14 @@ impl TGpu for Gpu { } fn ppt(&mut self, fast: Option, slow: Option) { - self.fast_ppt = fast.map(|x| x * self.limits.ppt_divisor); - self.slow_ppt = slow.map(|x| x * self.limits.ppt_divisor); + self.fast_ppt = fast.map(|x| x * self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)); + self.slow_ppt = slow.map(|x| x * self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)); } fn get_ppt(&self) -> (Option, Option) { ( - self.fast_ppt.map(|x| x / self.limits.ppt_divisor), - self.slow_ppt.map(|x| x / self.limits.ppt_divisor), + self.fast_ppt.map(|x| x / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)), + self.slow_ppt.map(|x| x / self.limits.ppt_divisor.unwrap_or(PPT_DIVISOR)), ) } @@ -428,6 +424,6 @@ impl TGpu for Gpu { } fn provider(&self) -> crate::persist::DriverJson { - self.driver_mode.clone() + crate::persist::DriverJson::SteamDeck } } diff --git a/backend/src/settings/steam_deck/mod.rs b/backend/src/settings/steam_deck/mod.rs index 268fa90..676d7fe 100644 --- a/backend/src/settings/steam_deck/mod.rs +++ b/backend/src/settings/steam_deck/mod.rs @@ -1,7 +1,6 @@ mod battery; mod cpu; mod gpu; -mod oc_limits; mod power_dpm_force; mod util; @@ -11,3 +10,11 @@ pub use gpu::Gpu; pub(self) use power_dpm_force::{POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT, DPM_FORCE_LIMITS_ATTRIBUTE}; pub use util::flash_led; + +fn _impl_checker() { + fn impl_provider_builder, J, L>() {} + + impl_provider_builder::(); + impl_provider_builder::, limits_core::json_v2::GenericCpusLimit>(); + impl_provider_builder::(); +} diff --git a/backend/src/settings/steam_deck/oc_limits.rs b/backend/src/settings/steam_deck/oc_limits.rs deleted file mode 100644 index f229a0c..0000000 --- a/backend/src/settings/steam_deck/oc_limits.rs +++ /dev/null @@ -1,190 +0,0 @@ -use crate::api::RangeLimit as MinMax; -use serde::{Deserialize, Serialize}; - -const OC_LIMITS_FILEPATH: &str = "pt_oc.json"; - -#[derive(Serialize, Deserialize, Debug)] -pub(super) struct OverclockLimits { - pub battery: BatteryLimits, - pub cpus: CpusLimits, - pub gpu: GpuLimits, -} - -impl Default for OverclockLimits { - fn default() -> Self { - Self { - battery: BatteryLimits::default(), - cpus: CpusLimits::default(), - gpu: GpuLimits::default(), - } - } -} - -impl OverclockLimits { - /// (Self, is_default) - pub fn load_or_default() -> (Self, bool) { - let path = oc_limits_filepath(); - if path.exists() { - log::info!("Steam Deck limits file {} found", path.display()); - let mut file = match std::fs::File::open(&path) { - Ok(f) => f, - Err(e) => { - log::warn!( - "Steam Deck limits file {} err: {} (using default fallback)", - path.display(), - e - ); - return (Self::default(), true); - } - }; - match serde_json::from_reader(&mut file) { - Ok(result) => { - log::debug!( - "Steam Deck limits file {} successfully loaded", - path.display() - ); - (result, false) - } - Err(e) => { - log::warn!( - "Steam Deck limits file {} json err: {} (using default fallback)", - path.display(), - e - ); - (Self::default(), true) - } - } - } else { - log::info!( - "Steam Deck limits file {} not found (using default fallback)", - path.display() - ); - (Self::default(), true) - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub(super) struct BatteryLimits { - pub charge_rate: MinMax, - pub extra_readouts: bool, -} - -impl Default for BatteryLimits { - fn default() -> Self { - Self { - charge_rate: MinMax { - min: 250, - max: 2500, - }, - extra_readouts: false, - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub(super) struct CpusLimits { - pub cpus: Vec, - pub global_governors: bool, -} - -impl Default for CpusLimits { - fn default() -> Self { - Self { - cpus: [(); 8].iter().map(|_| CpuLimits::default()).collect(), - global_governors: true, - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub(super) struct CpuLimits { - pub clock_min: MinMax, - pub clock_max: MinMax, - pub clock_step: u64, - pub skip_resume_reclock: bool, -} - -impl Default for CpuLimits { - fn default() -> Self { - Self { - clock_min: MinMax { - min: 1400, - max: 3500, - }, - clock_max: MinMax { - min: 400, - max: 3500, - }, - clock_step: 100, - skip_resume_reclock: false, - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub(super) struct GpuLimits { - pub fast_ppt: MinMax, - pub fast_ppt_default: u64, - pub slow_ppt: MinMax, - pub slow_ppt_default: u64, - pub ppt_divisor: u64, - pub ppt_step: u64, - pub clock_min: MinMax, - pub clock_max: MinMax, - pub clock_step: u64, - pub skip_resume_reclock: bool, -} - -impl Default for GpuLimits { - fn default() -> Self { - Self { - fast_ppt: MinMax { - min: 1000000, - max: 30_000_000, - }, - fast_ppt_default: 15_000_000, - slow_ppt: MinMax { - min: 1000000, - max: 29_000_000, - }, - slow_ppt_default: 15_000_000, - ppt_divisor: 1_000_000, - ppt_step: 1, - clock_min: MinMax { - min: 400, - max: 1600, - }, - clock_max: MinMax { - min: 400, - max: 1600, - }, - clock_step: 100, - skip_resume_reclock: false, - } - } -} - -fn oc_limits_filepath() -> std::path::PathBuf { - crate::utility::settings_dir().join(OC_LIMITS_FILEPATH) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(not(feature = "dev_stuff"))] // this can fail due to reading from incompletely-written file otherwise - #[test] - fn load_pt_oc() { - let mut file = std::fs::File::open("../pt_oc.json").unwrap(); - let settings: OverclockLimits = serde_json::from_reader(&mut file).unwrap(); - assert!(settings.cpus.cpus.len() == 8); - } - - #[cfg(feature = "dev_stuff")] - #[test] - fn emit_default_pt_oc() { - let mut file = std::fs::File::create("../pt_oc.json").unwrap(); - serde_json::to_writer_pretty(&mut file, &OverclockLimits::default()).unwrap(); - } -} diff --git a/backend/src/settings/steam_deck/util.rs b/backend/src/settings/steam_deck/util.rs index 52eb3e9..029e2f3 100644 --- a/backend/src/settings/steam_deck/util.rs +++ b/backend/src/settings/steam_deck/util.rs @@ -12,6 +12,14 @@ pub const JUPITER_HWMON_NAME: &'static str = "jupiter"; pub const STEAMDECK_HWMON_NAME: &'static str = "steamdeck_hwmon"; pub const GPU_HWMON_NAME: &'static str = "amdgpu"; +pub fn range_min_or_fallback(range: &Option>, fallback: I) -> I { + range.and_then(|lim| lim.min).unwrap_or(fallback) +} + +pub fn range_max_or_fallback(range: &Option>, fallback: I) -> I { + range.and_then(|lim| lim.max).unwrap_or(fallback) +} + pub fn card_also_has(card: &dyn sysfuss::SysEntity, extensions: &'static [&'static str]) -> bool { extensions.iter() .all(|ext| card.as_ref().join(ext).exists()) diff --git a/backend/src/settings/traits.rs b/backend/src/settings/traits.rs index 4e96882..990984d 100644 --- a/backend/src/settings/traits.rs +++ b/backend/src/settings/traits.rs @@ -40,6 +40,12 @@ pub trait OnPowerEvent { } } +pub trait ProviderBuilder { + fn from_json_and_limits(persistent: J, version: u64, limits: L) -> Self; + + fn from_limits(limits: L) -> Self; +} + pub trait TGpu: OnSet + OnResume + OnPowerEvent + Debug + Send { fn limits(&self) -> crate::api::GpuLimits; diff --git a/backend/src/settings/unknown/battery.rs b/backend/src/settings/unknown/battery.rs index ab76959..6c1a2e3 100644 --- a/backend/src/settings/unknown/battery.rs +++ b/backend/src/settings/unknown/battery.rs @@ -1,12 +1,21 @@ use std::convert::Into; +use limits_core::json_v2::GenericBatteryLimit; + use crate::persist::BatteryJson; -use crate::settings::TBattery; +use crate::settings::{TBattery, ProviderBuilder}; use crate::settings::{OnResume, OnSet, SettingError}; #[derive(Debug, Clone)] pub struct Battery; +impl Battery { + #[inline] + fn system_default() -> Self { + Battery + } +} + impl Into for Battery { #[inline] fn into(self) -> BatteryJson { @@ -19,6 +28,16 @@ impl Into for Battery { } } +impl ProviderBuilder for Battery { + fn from_json_and_limits(_persistent: BatteryJson, _version: u64, _limits: GenericBatteryLimit) -> Self { + Battery::system_default() + } + + fn from_limits(_limits: GenericBatteryLimit) -> Self { + Battery::system_default() + } +} + impl OnSet for Battery { fn on_set(&mut self) -> Result<(), Vec> { Ok(()) diff --git a/backend/src/settings/unknown/cpu.rs b/backend/src/settings/unknown/cpu.rs index c3985cf..25130ca 100644 --- a/backend/src/settings/unknown/cpu.rs +++ b/backend/src/settings/unknown/cpu.rs @@ -1,9 +1,11 @@ use std::convert::Into; +use limits_core::json_v2::GenericCpusLimit; + use crate::persist::CpuJson; use crate::settings::MinMax; use crate::settings::{OnResume, OnSet, SettingError}; -use crate::settings::{TCpu, TCpus}; +use crate::settings::{TCpu, TCpus, ProviderBuilder}; const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present"; const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control"; @@ -111,7 +113,7 @@ impl Cpus { } } - #[inline] + /*#[inline] pub fn from_json(mut other: Vec, version: u64) -> Self { let (_, can_smt) = Self::system_smt_capabilities(); let mut result = Vec::with_capacity(other.len()); @@ -140,6 +142,42 @@ impl Cpus { smt: smt_guess, smt_capable: can_smt, } + }*/ +} + +impl ProviderBuilder, GenericCpusLimit> for Cpus { + fn from_json_and_limits(mut persistent: Vec, version: u64, _limits: GenericCpusLimit) -> Self { + let (_, can_smt) = Self::system_smt_capabilities(); + let mut result = Vec::with_capacity(persistent.len()); + let max_cpus = Self::cpu_count(); + let smt_guess = crate::settings::util::guess_smt(&persistent) && can_smt; + for (i, cpu) in persistent.drain(..).enumerate() { + // prevent having more CPUs than available + if let Some(max_cpus) = max_cpus { + if i == max_cpus { + break; + } + } + let new_cpu = Cpu::from_json(cpu, version, i); + result.push(new_cpu); + } + if let Some(max_cpus) = max_cpus { + if result.len() != max_cpus { + let mut sys_cpus = Cpus::system_default(); + for i in result.len()..sys_cpus.cpus.len() { + result.push(sys_cpus.cpus.remove(i)); + } + } + } + Self { + cpus: result, + smt: smt_guess, + smt_capable: can_smt, + } + } + + fn from_limits(_limits: GenericCpusLimit) -> Self { + Self::system_default() } } @@ -153,7 +191,7 @@ impl TCpus for Cpus { } } - fn json(&self) -> Vec { + fn json(&self) -> Vec { self.cpus.iter().map(|x| x.to_owned().into()).collect() } diff --git a/backend/src/settings/unknown/gpu.rs b/backend/src/settings/unknown/gpu.rs index 0b4b73e..4e911d4 100644 --- a/backend/src/settings/unknown/gpu.rs +++ b/backend/src/settings/unknown/gpu.rs @@ -1,8 +1,10 @@ use std::convert::Into; +use limits_core::json_v2::GenericGpuLimit; + use crate::persist::GpuJson; use crate::settings::MinMax; -use crate::settings::TGpu; +use crate::settings::{TGpu, ProviderBuilder}; use crate::settings::{OnResume, OnSet, SettingError}; #[derive(Debug, Clone)] @@ -11,16 +13,21 @@ pub struct Gpu { } impl Gpu { - #[inline] - pub fn from_json(_other: GpuJson, _version: u64) -> Self { - Self { slow_memory: false } - } - pub fn system_default() -> Self { Self { slow_memory: false } } } +impl ProviderBuilder for Gpu { + fn from_json_and_limits(_persistent: GpuJson, _version: u64, _limits: GenericGpuLimit) -> Self { + Self::system_default() + } + + fn from_limits(_limits: GenericGpuLimit) -> Self { + Self::system_default() + } +} + impl Into for Gpu { #[inline] fn into(self) -> GpuJson { diff --git a/backend/src/settings/unknown/mod.rs b/backend/src/settings/unknown/mod.rs index 2039cae..bd0f419 100644 --- a/backend/src/settings/unknown/mod.rs +++ b/backend/src/settings/unknown/mod.rs @@ -5,3 +5,11 @@ mod gpu; pub use battery::Battery; pub use cpu::{Cpu, Cpus}; pub use gpu::Gpu; + +fn _impl_checker() { + fn impl_provider_builder, J, L>() {} + + impl_provider_builder::(); + impl_provider_builder::, limits_core::json_v2::GenericCpusLimit>(); + impl_provider_builder::(); +}