forked from NG-SD-Plugins/PowerTools
Replace pt_oc functionality with cross-provider equivalent (& resultant refactor)
This commit is contained in:
parent
a8ad9a9e62
commit
a90932d813
47 changed files with 2727 additions and 934 deletions
2
backend/Cargo.lock
generated
2
backend/Cargo.lock
generated
|
@ -808,7 +808,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "limits_core"
|
||||
version = "2.0.1"
|
||||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -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
|
||||
|
|
2
backend/limits_core/Cargo.lock
generated
2
backend/limits_core/Cargo.lock
generated
|
@ -10,7 +10,7 @@ checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
|||
|
||||
[[package]]
|
||||
name = "limits_core"
|
||||
version = "2.0.1"
|
||||
version = "3.0.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -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
|
||||
|
|
267
backend/limits_core/src/json_v2/base.rs
Normal file
267
backend/limits_core/src/json_v2/base.rs
Normal file
|
@ -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<super::Config>,
|
||||
/// Server messages
|
||||
pub messages: Vec<super::DeveloperMessage>,
|
||||
/// URL from which to grab the next update
|
||||
pub refresh: Option<String>,
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
69
backend/limits_core/src/json_v2/battery_limit.rs
Normal file
69
backend/limits_core/src/json_v2/battery_limit.rs
Normal file
|
@ -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<RangeLimit<u64>>,
|
||||
pub charge_modes: Vec<String>,
|
||||
pub charge_limit: Option<RangeLimit<f64>>, // 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;
|
||||
}
|
||||
}
|
26
backend/limits_core/src/json_v2/conditions.rs
Normal file
26
backend/limits_core/src/json_v2/conditions.rs
Normal file
|
@ -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<String>,
|
||||
/// Regex pattern for /proc/cpuinfo reading
|
||||
pub cpuinfo: Option<String>,
|
||||
/// Regex pattern for /etc/os-release reading
|
||||
pub os: Option<String>,
|
||||
/// Custom command to run, where an exit code of 0 means a successful match
|
||||
pub command: Option<String>,
|
||||
/// Check if file exists
|
||||
pub file_exists: Option<String>,
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
8
backend/limits_core/src/json_v2/config.rs
Normal file
8
backend/limits_core/src/json_v2/config.rs
Normal file
|
@ -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,
|
||||
}
|
126
backend/limits_core/src/json_v2/cpu_limit.rs
Normal file
126
backend/limits_core/src/json_v2/cpu_limit.rs
Normal file
|
@ -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<GenericCpuLimit>,
|
||||
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<usize> {
|
||||
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::<usize>() {
|
||||
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<RangeLimit<u64>>,
|
||||
pub clock_max: Option<RangeLimit<u64>>,
|
||||
pub clock_step: Option<u64>,
|
||||
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;
|
||||
}
|
||||
}
|
14
backend/limits_core/src/json_v2/devel_message.rs
Normal file
14
backend/limits_core/src/json_v2/devel_message.rs
Normal file
|
@ -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<String>,
|
||||
}
|
132
backend/limits_core/src/json_v2/gpu_limit.rs
Normal file
132
backend/limits_core/src/json_v2/gpu_limit.rs
Normal file
|
@ -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<RangeLimit<u64>>,
|
||||
pub fast_ppt_default: Option<u64>,
|
||||
pub slow_ppt: Option<RangeLimit<u64>>,
|
||||
pub slow_ppt_default: Option<u64>,
|
||||
pub ppt_divisor: Option<u64>,
|
||||
pub ppt_step: Option<u64>,
|
||||
pub tdp: Option<RangeLimit<u64>>,
|
||||
pub tdp_boost: Option<RangeLimit<u64>>,
|
||||
pub tdp_step: Option<u64>,
|
||||
pub clock_min: Option<RangeLimit<u64>>,
|
||||
pub clock_max: Option<RangeLimit<u64>>,
|
||||
pub clock_step: Option<u64>,
|
||||
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;
|
||||
}
|
||||
}
|
28
backend/limits_core/src/json_v2/limits.rs
Normal file
28
backend/limits_core/src/json_v2/limits.rs
Normal file
|
@ -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<Self>) {
|
||||
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<P, L> {
|
||||
pub provider: P,
|
||||
pub limits: L,
|
||||
}
|
||||
|
||||
pub type CpuLimit = Limit<super::CpuLimitType, super::GenericCpusLimit>;
|
||||
pub type GpuLimit = Limit<super::GpuLimitType, super::GenericGpuLimit>;
|
||||
pub type BatteryLimit = Limit<super::BatteryLimitType, super::GenericBatteryLimit>;
|
21
backend/limits_core/src/json_v2/mod.rs
Normal file
21
backend/limits_core/src/json_v2/mod.rs
Normal file
|
@ -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;
|
8
backend/limits_core/src/json_v2/range.rs
Normal file
8
backend/limits_core/src/json_v2/range.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Base JSON limits information
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub struct RangeLimit<T> {
|
||||
pub min: Option<T>,
|
||||
pub max: Option<T>,
|
||||
}
|
9
backend/limits_core/src/json_v2/target.rs
Normal file
9
backend/limits_core/src/json_v2/target.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum Target {
|
||||
SteamDeck,
|
||||
SteamDeckAdvance,
|
||||
Generic,
|
||||
Unknown,
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
pub mod json;
|
||||
pub mod json_v2;
|
||||
|
|
4
backend/limits_srv/Cargo.lock
generated
4
backend/limits_srv/Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
1250
backend/limits_srv/pt_limits_v2.json
Normal file
1250
backend/limits_srv/pt_limits_v2.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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<RwLock<Base>>) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
|
||||
fn routes(base: Arc<RwLock<limits_core::json::Base>>, base2: Arc<RwLock<limits_core::json_v2::Base>>) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + 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<impl warp::Reply, warp:
|
|||
async fn main() {
|
||||
START_TIME.store(chrono::Utc::now().timestamp(), Ordering::Relaxed);
|
||||
let file = std::fs::File::open("./pt_limits.json").expect("Failed to read limits file");
|
||||
let limits: Base = serde_json::from_reader(file).expect("Failed to parse limits file");
|
||||
let limits: limits_core::json::Base = serde_json::from_reader(file).expect("Failed to parse limits file");
|
||||
assert!(limits.refresh.is_some(), "`refresh` cannot be null, since it will brick future refreshes");
|
||||
|
||||
warp::serve(routes(Arc::new(RwLock::new(limits))))
|
||||
let file = std::fs::File::open("./pt_limits_v2.json").expect("Failed to read limits file");
|
||||
let limits_v2: limits_core::json_v2::Base = serde_json::from_reader(file).expect("Failed to parse limits file");
|
||||
assert!(limits_v2.refresh.is_some(), "`refresh` cannot be null, since it will brick future refreshes");
|
||||
|
||||
warp::serve(routes(Arc::new(RwLock::new(limits)), Arc::new(RwLock::new(limits_v2))))
|
||||
.run(([0, 0, 0, 0], 8080))
|
||||
.await;
|
||||
}
|
||||
|
@ -75,4 +94,11 @@ mod test {
|
|||
let output_file = std::fs::File::create("./pt_limits.json").unwrap();
|
||||
serde_json::to_writer_pretty(output_file, &limits).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_default_pt_limits_v2() {
|
||||
let limits = limits_core::json_v2::Base::default();
|
||||
let output_file = std::fs::File::create("./pt_limits_v2.json").unwrap();
|
||||
serde_json::to_writer_pretty(output_file, &limits).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,5 +7,7 @@ pub const DEFAULT_SETTINGS_FILE: &str = "default_settings.json";
|
|||
pub const DEFAULT_SETTINGS_NAME: &str = "Main";
|
||||
|
||||
pub const LIMITS_FILE: &str = "limits_cache.json";
|
||||
pub const LIMITS_OVERRIDE_FILE: &str = "limits_override.json";
|
||||
|
||||
|
||||
pub const MESSAGE_SEEN_ID_FILE: &str = "seen_message.bin";
|
||||
|
|
|
@ -2,12 +2,12 @@ use std::fs::File;
|
|||
|
||||
use regex::RegexBuilder;
|
||||
|
||||
use limits_core::json::{BatteryLimit, CpuLimit, GpuLimit, Limits};
|
||||
use limits_core::json_v2::{BatteryLimitType, CpuLimitType, GpuLimitType, Limits};
|
||||
|
||||
use crate::persist::{DriverJson, SettingsJson};
|
||||
use crate::settings::{Driver, General, TBattery, TCpus, TGeneral, TGpu};
|
||||
use crate::settings::{Driver, General, TBattery, TCpus, TGeneral, TGpu, ProviderBuilder};
|
||||
|
||||
fn get_limits() -> 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<Limits> {
|
||||
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,14 +96,12 @@ 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)
|
||||
|
@ -107,226 +136,189 @@ pub fn auto_detect0(
|
|||
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<dyn TCpus> = match cpus {
|
||||
CpuLimit::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::from_json(
|
||||
*general_driver.persistent() = true;
|
||||
let cpu_driver: Box<dyn TCpus> = 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,
|
||||
))
|
||||
}
|
||||
CpuLimit::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::from_json(
|
||||
CpuLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::from_json_and_limits(
|
||||
settings.cpus.clone(),
|
||||
settings.version,
|
||||
relevant_limits.cpu.limits,
|
||||
))
|
||||
}
|
||||
CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::<
|
||||
CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::<
|
||||
crate::settings::generic::Cpu,
|
||||
>::from_json_and_limits(
|
||||
settings.cpus.clone(),
|
||||
settings.version,
|
||||
x,
|
||||
relevant_limits.cpu.limits,
|
||||
)),
|
||||
CpuLimit::GenericAMD(x) => Box::new(
|
||||
CpuLimitType::GenericAMD => Box::new(
|
||||
crate::settings::generic_amd::Cpus::from_json_and_limits(
|
||||
settings.cpus.clone(),
|
||||
settings.version,
|
||||
x,
|
||||
relevant_limits.cpu.limits,
|
||||
),
|
||||
),
|
||||
CpuLimit::Unknown => {
|
||||
Box::new(crate::settings::unknown::Cpus::from_json(
|
||||
CpuLimitType::Unknown => {
|
||||
Box::new(crate::settings::unknown::Cpus::from_json_and_limits(
|
||||
settings.cpus.clone(),
|
||||
settings.version,
|
||||
relevant_limits.cpu.limits,
|
||||
))
|
||||
}
|
||||
};
|
||||
builder.cpus = Some(cpu_driver);
|
||||
}
|
||||
Limits::Gpu(gpu) => {
|
||||
let driver: Box<dyn TGpu> = match gpu {
|
||||
GpuLimit::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_json(
|
||||
|
||||
let gpu_driver: Box<dyn TGpu> = 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,
|
||||
))
|
||||
}
|
||||
GpuLimit::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_json(
|
||||
GpuLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_json_and_limits(
|
||||
settings.gpu.clone(),
|
||||
settings.version,
|
||||
relevant_limits.gpu.limits,
|
||||
))
|
||||
}
|
||||
GpuLimit::Generic(x) => {
|
||||
GpuLimitType::Generic => {
|
||||
Box::new(crate::settings::generic::Gpu::from_json_and_limits(
|
||||
settings.gpu.clone(),
|
||||
settings.version,
|
||||
x,
|
||||
relevant_limits.gpu.limits,
|
||||
))
|
||||
}
|
||||
GpuLimit::GenericAMD(x) => Box::new(
|
||||
GpuLimitType::GenericAMD => Box::new(
|
||||
crate::settings::generic_amd::Gpu::from_json_and_limits(
|
||||
settings.gpu.clone(),
|
||||
settings.version,
|
||||
x,
|
||||
relevant_limits.gpu.limits,
|
||||
),
|
||||
),
|
||||
GpuLimit::Unknown => {
|
||||
Box::new(crate::settings::unknown::Gpu::from_json(
|
||||
GpuLimitType::Unknown => {
|
||||
Box::new(crate::settings::unknown::Gpu::from_json_and_limits(
|
||||
settings.gpu.clone(),
|
||||
settings.version,
|
||||
relevant_limits.gpu.limits,
|
||||
))
|
||||
}
|
||||
};
|
||||
builder.gpu = Some(driver);
|
||||
}
|
||||
Limits::Battery(batt) => {
|
||||
let driver: Box<dyn TBattery> = match batt {
|
||||
BatteryLimit::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Battery::from_json(
|
||||
let battery_driver: Box<dyn TBattery> = 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,
|
||||
))
|
||||
}
|
||||
BatteryLimit::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Battery::from_json(
|
||||
BatteryLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Battery::from_json_and_limits(
|
||||
settings.battery.clone(),
|
||||
settings.version,
|
||||
relevant_limits.battery.limits,
|
||||
))
|
||||
}
|
||||
BatteryLimit::Generic(x) => Box::new(
|
||||
BatteryLimitType::Generic => Box::new(
|
||||
crate::settings::generic::Battery::from_json_and_limits(
|
||||
settings.battery.clone(),
|
||||
settings.version,
|
||||
x,
|
||||
relevant_limits.battery.limits,
|
||||
),
|
||||
),
|
||||
BatteryLimit::Unknown => {
|
||||
Box::new(crate::settings::unknown::Battery)
|
||||
BatteryLimitType::Unknown => {
|
||||
Box::new(crate::settings::unknown::Battery::from_json_and_limits(
|
||||
settings.battery.clone(),
|
||||
settings.version,
|
||||
relevant_limits.battery.limits,
|
||||
))
|
||||
}
|
||||
};
|
||||
builder.battery = Some(driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<dyn TCpus> = match cpus {
|
||||
CpuLimit::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::system_default())
|
||||
let cpu_driver: Box<dyn TCpus> = match relevant_limits.cpu.provider {
|
||||
CpuLimitType::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits))
|
||||
}
|
||||
CpuLimit::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::system_default())
|
||||
CpuLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits))
|
||||
}
|
||||
CpuLimit::Generic(x) => {
|
||||
CpuLimitType::Generic => {
|
||||
Box::new(crate::settings::generic::Cpus::<
|
||||
crate::settings::generic::Cpu,
|
||||
>::from_limits(x))
|
||||
>::from_limits(relevant_limits.cpu.limits))
|
||||
}
|
||||
CpuLimit::GenericAMD(x) => {
|
||||
Box::new(crate::settings::generic_amd::Cpus::from_limits(x))
|
||||
CpuLimitType::GenericAMD => {
|
||||
Box::new(crate::settings::generic_amd::Cpus::from_limits(relevant_limits.cpu.limits))
|
||||
}
|
||||
CpuLimit::Unknown => {
|
||||
Box::new(crate::settings::unknown::Cpus::system_default())
|
||||
CpuLimitType::Unknown => {
|
||||
Box::new(crate::settings::unknown::Cpus::from_limits(relevant_limits.cpu.limits))
|
||||
}
|
||||
};
|
||||
builder.cpus = Some(cpu_driver);
|
||||
let gpu_driver: Box<dyn TGpu> = match relevant_limits.gpu.provider {
|
||||
GpuLimitType::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
Limits::Gpu(gpu) => {
|
||||
let driver: Box<dyn TGpu> = match gpu {
|
||||
GpuLimit::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::system_default())
|
||||
GpuLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
GpuLimit::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::system_default())
|
||||
GpuLimitType::Generic => {
|
||||
Box::new(crate::settings::generic::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
GpuLimit::Generic(x) => {
|
||||
Box::new(crate::settings::generic::Gpu::from_limits(x))
|
||||
GpuLimitType::GenericAMD => {
|
||||
Box::new(crate::settings::generic_amd::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
GpuLimit::GenericAMD(x) => {
|
||||
Box::new(crate::settings::generic_amd::Gpu::from_limits(x))
|
||||
}
|
||||
GpuLimit::Unknown => {
|
||||
Box::new(crate::settings::unknown::Gpu::system_default())
|
||||
GpuLimitType::Unknown => {
|
||||
Box::new(crate::settings::unknown::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
};
|
||||
builder.gpu = Some(driver);
|
||||
let battery_driver: Box<dyn TBattery> = match relevant_limits.battery.provider {
|
||||
BatteryLimitType::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Battery::from_limits(relevant_limits.battery.limits))
|
||||
}
|
||||
Limits::Battery(batt) => {
|
||||
let driver: Box<dyn TBattery> = match batt {
|
||||
BatteryLimit::SteamDeck => {
|
||||
Box::new(crate::settings::steam_deck::Battery::system_default())
|
||||
BatteryLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Battery::from_limits(relevant_limits.battery.limits))
|
||||
}
|
||||
BatteryLimit::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Battery::system_default())
|
||||
BatteryLimitType::Generic => {
|
||||
Box::new(crate::settings::generic::Battery::from_limits(relevant_limits.battery.limits))
|
||||
}
|
||||
BatteryLimit::Generic(x) => {
|
||||
Box::new(crate::settings::generic::Battery::from_limits(x))
|
||||
}
|
||||
BatteryLimit::Unknown => {
|
||||
Box::new(crate::settings::unknown::Battery)
|
||||
BatteryLimitType::Unknown => {
|
||||
Box::new(crate::settings::unknown::Battery::from_limits(relevant_limits.battery.limits))
|
||||
}
|
||||
};
|
||||
builder.battery = Some(driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Driver {
|
||||
general: general_driver,
|
||||
cpus: cpu_driver,
|
||||
gpu: gpu_driver,
|
||||
battery: battery_driver,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
|
||||
struct DriverBuilder {
|
||||
general: Box<dyn TGeneral>,
|
||||
cpus: Option<Box<dyn TCpus>>,
|
||||
gpu: Option<Box<dyn TGpu>>,
|
||||
battery: Option<Box<dyn TBattery>>,
|
||||
}
|
||||
|
||||
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)),
|
||||
}
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<()> {
|
||||
|
|
|
@ -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<DeveloperMessage> {
|
||||
let limits_path = limits_path();
|
||||
|
|
|
@ -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<Self, SettingError> {
|
||||
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<Self, SettingError> {
|
||||
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 {
|
||||
|
|
|
@ -156,9 +156,7 @@ 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) => {
|
||||
let x = super::Driver::init(other, json_path.clone());
|
||||
log::info!(
|
||||
"Loaded settings with drivers general:{:?},cpus:{:?},gpu:{:?},battery:{:?}",
|
||||
x.general.provider(),
|
||||
|
@ -173,12 +171,6 @@ impl Settings {
|
|||
battery: x.battery,
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Driver init error: {}", e);
|
||||
Self::system_default(json_path, name_bup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn system_default(json_path: PathBuf, name: String) -> Self {
|
||||
let driver = super::Driver::system_default(json_path, name);
|
||||
|
@ -219,23 +211,13 @@ impl Settings {
|
|||
*self.general.persistent() = false;
|
||||
self.general.name(name);
|
||||
} else {
|
||||
match super::Driver::init(settings_json, json_path.clone()) {
|
||||
Ok(x) => {
|
||||
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;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Driver init error: {}", e);
|
||||
self.general.name(name);
|
||||
*self.general.persistent() = false;
|
||||
self.general.path(json_path);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if system_defaults {
|
||||
self.load_system_default(name);
|
||||
|
|
|
@ -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<BatteryJson, GenericBatteryLimit> 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>),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> Cpus<C> {
|
|||
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<CpuJson>,
|
||||
version: u64,
|
||||
limits: limits_core::json::GenericCpuLimit,
|
||||
) -> Self {
|
||||
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus<C> {
|
||||
fn from_json_and_limits(mut other: Vec<CpuJson>, 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<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> Cpus<C> {
|
|||
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<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> Cpus<C> {
|
|||
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<C: AsMut<Cpu> + AsRef<Cpu> + 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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<GpuJson, GenericGpuLimit> 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<GpuJson> for Gpu {
|
||||
|
|
|
@ -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<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
|
||||
|
||||
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>();
|
||||
impl_provider_builder::<Cpus<Cpu>, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
|
||||
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::persist::CpuJson;
|
||||
use limits_core::json::GenericCpuLimit;
|
||||
use limits_core::json_v2::GenericCpuLimit;
|
||||
|
||||
// similar to crate::settings::ProviderBuilder<CpuJson, GenericCpuLimit>
|
||||
pub trait FromGenericCpuInfo {
|
||||
fn from_limits(cpu_index: usize, limits: GenericCpuLimit) -> Self;
|
||||
|
||||
|
|
|
@ -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<Cpu>,
|
||||
}
|
||||
|
||||
impl Cpus {
|
||||
pub fn from_limits(limits: limits_core::json::GenericCpuLimit) -> Self {
|
||||
impl ProviderBuilder<Vec<CpuJson>, 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<CpuJson>,
|
||||
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 }
|
||||
|
|
|
@ -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<Mutex<RyzenAdj>> {
|
||||
|
@ -35,8 +35,8 @@ impl std::fmt::Debug for Gpu {
|
|||
}
|
||||
}
|
||||
|
||||
impl Gpu {
|
||||
pub fn from_limits(limits: limits_core::json::GenericGpuLimit) -> Self {
|
||||
impl ProviderBuilder<GpuJson, limits_core::json_v2::GenericGpuLimit> 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<SettingError>> {
|
||||
let mutex = match &self.implementor {
|
||||
|
|
|
@ -3,3 +3,10 @@ mod gpu;
|
|||
|
||||
pub use cpu::{Cpu, Cpus};
|
||||
pub use gpu::Gpu;
|
||||
|
||||
fn _impl_checker() {
|
||||
fn impl_provider_builder<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
|
||||
|
||||
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
|
||||
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<u64>,
|
||||
pub charge_mode: Option<ChargeMode>,
|
||||
events: Vec<EventInstruction>,
|
||||
limits: BatteryLimits,
|
||||
limits: GenericBatteryLimit,
|
||||
state: crate::state::steam_deck::Battery,
|
||||
driver_mode: crate::persist::DriverJson,
|
||||
sysfs_bat: PowerSupplyPath,
|
||||
sysfs_hwmon: Arc<HwMonPath>,
|
||||
}
|
||||
|
@ -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<impl AsRef<std::path::Path>>) -> 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<usize> {
|
||||
for (i, event) in self.events.iter().enumerate() {
|
||||
match event.trigger {
|
||||
|
@ -550,6 +485,58 @@ impl Into<BatteryJson> for Battery {
|
|||
}
|
||||
}
|
||||
|
||||
impl ProviderBuilder<BatteryJson, GenericBatteryLimit> 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<SettingError>> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Cpu>,
|
||||
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 {
|
||||
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<CpuJson>, version: u64) -> Self {
|
||||
impl ProviderBuilder<Vec<CpuJson>, GenericCpusLimit> for Cpus {
|
||||
fn from_json_and_limits(mut persistent: Vec<CpuJson>, 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
|
||||
};
|
||||
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(
|
||||
let new_cpu = if let Some(cpu_limit) = limits.cpus.get(i) {
|
||||
Cpu::from_json_and_limits(
|
||||
cpu,
|
||||
version,
|
||||
i,
|
||||
oc_limits
|
||||
.cpus
|
||||
.get(i)
|
||||
.map(|x| x.to_owned())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
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<MinMax<u64>>,
|
||||
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<impl AsRef<std::path::Path>>) -> 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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<u64>,
|
||||
pub clock_limits: Option<MinMax<u64>>,
|
||||
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<impl AsRef<std::path::Path>>) -> 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<GpuJson> for Gpu {
|
||||
|
@ -354,6 +310,46 @@ impl Into<GpuJson> for Gpu {
|
|||
}
|
||||
}
|
||||
|
||||
impl ProviderBuilder<GpuJson, GenericGpuLimit> 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<SettingError>> {
|
||||
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<u64>, slow: Option<u64>) {
|
||||
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<u64>, Option<u64>) {
|
||||
(
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
|
||||
|
||||
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>();
|
||||
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
|
||||
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
|
||||
}
|
||||
|
|
|
@ -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<u64>,
|
||||
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<CpuLimits>,
|
||||
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<u64>,
|
||||
pub clock_max: MinMax<u64>,
|
||||
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<u64>,
|
||||
pub fast_ppt_default: u64,
|
||||
pub slow_ppt: MinMax<u64>,
|
||||
pub slow_ppt_default: u64,
|
||||
pub ppt_divisor: u64,
|
||||
pub ppt_step: u64,
|
||||
pub clock_min: MinMax<u64>,
|
||||
pub clock_max: MinMax<u64>,
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -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<I: Copy>(range: &Option<limits_core::json_v2::RangeLimit<I>>, fallback: I) -> I {
|
||||
range.and_then(|lim| lim.min).unwrap_or(fallback)
|
||||
}
|
||||
|
||||
pub fn range_max_or_fallback<I: Copy>(range: &Option<limits_core::json_v2::RangeLimit<I>>, 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())
|
||||
|
|
|
@ -40,6 +40,12 @@ pub trait OnPowerEvent {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait ProviderBuilder<J, L> {
|
||||
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;
|
||||
|
||||
|
|
|
@ -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<BatteryJson> for Battery {
|
||||
#[inline]
|
||||
fn into(self) -> BatteryJson {
|
||||
|
@ -19,6 +28,16 @@ impl Into<BatteryJson> for Battery {
|
|||
}
|
||||
}
|
||||
|
||||
impl ProviderBuilder<BatteryJson, GenericBatteryLimit> 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<SettingError>> {
|
||||
Ok(())
|
||||
|
|
|
@ -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<CpuJson>, 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<Vec<CpuJson>, GenericCpusLimit> for Cpus {
|
||||
fn from_json_and_limits(mut persistent: Vec<CpuJson>, 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<crate::persist::CpuJson> {
|
||||
fn json(&self) -> Vec<CpuJson> {
|
||||
self.cpus.iter().map(|x| x.to_owned().into()).collect()
|
||||
}
|
||||
|
||||
|
|
|
@ -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<GpuJson, GenericGpuLimit> 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<GpuJson> for Gpu {
|
||||
#[inline]
|
||||
fn into(self) -> GpuJson {
|
||||
|
|
|
@ -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<T: crate::settings::ProviderBuilder<J, L>, J, L>() {}
|
||||
|
||||
impl_provider_builder::<Battery, crate::persist::BatteryJson, limits_core::json_v2::GenericBatteryLimit>();
|
||||
impl_provider_builder::<Cpus, Vec<crate::persist::CpuJson>, limits_core::json_v2::GenericCpusLimit>();
|
||||
impl_provider_builder::<Gpu, crate::persist::GpuJson, limits_core::json_v2::GenericGpuLimit>();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue