Implement full generic driver to simplify custom implementations

This commit is contained in:
NGnius (Graham) 2023-01-02 09:04:07 -05:00
parent 3031a1c9bf
commit 5614937012
9 changed files with 278 additions and 40 deletions

129
backend/Cargo.lock generated
View file

@ -102,6 +102,28 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bindgen"
version = "0.63.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
"which",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -149,6 +171,15 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -170,6 +201,17 @@ dependencies = [
"generic-array",
]
[[package]]
name = "clang-sys"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "cpufeatures"
version = "0.2.5"
@ -217,6 +259,12 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "encoding_rs"
version = "0.8.31"
@ -323,6 +371,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "h2"
version = "0.3.15"
@ -481,12 +535,34 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "limits_core"
version = "0.1.0"
@ -526,6 +602,12 @@ dependencies = [
"unicase",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.6.2"
@ -565,6 +647,16 @@ dependencies = [
"twoway",
]
[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num_cpus"
version = "1.14.0"
@ -602,6 +694,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "percent-encoding"
version = "2.2.0"
@ -660,6 +758,7 @@ dependencies = [
"limits_core",
"log",
"regex",
"ryzenadj-rs",
"serde",
"serde_json",
"simplelog",
@ -763,6 +862,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustls-pemfile"
version = "0.2.1"
@ -778,6 +883,13 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "ryzenadj-rs"
version = "0.1.0"
dependencies = [
"bindgen",
]
[[package]]
name = "safemem"
version = "0.3.3"
@ -855,6 +967,12 @@ dependencies = [
"digest",
]
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "simplelog"
version = "0.12.0"
@ -1265,6 +1383,17 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "which"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
dependencies = [
"either",
"libc",
"once_cell",
]
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -21,6 +21,7 @@ simplelog = "0.12"
# limits & driver functionality
limits_core = { version = "0.1.0", path = "./limits_core" }
regex = "1"
ryzenadj-rs = { version = "0.1", path = "../../ryzenadj-rs" }
# ureq's tls feature does not like musl targets
ureq = { version = "2.5", features = ["json", "gzip", "brotli", "charset"], default-features = false, optional = true }

View file

@ -97,7 +97,7 @@ pub fn auto_detect0(settings_opt: Option<SettingsJson>, json_path: std::path::Pa
let cpu_driver: Box<dyn TCpus> = match cpus {
CpuLimit::SteamDeck => Box::new(crate::settings::steam_deck::Cpus::from_json(settings.cpus.clone(), settings.version)),
CpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck::Cpus::from_json(settings.cpus.clone(), settings.version)),
CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::from_json_and_limits(settings.cpus.clone(), settings.version, x)),
CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::<crate::settings::generic::Cpu>::from_json_and_limits(settings.cpus.clone(), settings.version, x)),
CpuLimit::GenericAMD(x) => Box::new(crate::settings::generic_amd::Cpus::from_json_and_limits(settings.cpus.clone(), settings.version, x)),
CpuLimit::Unknown => Box::new(crate::settings::unknown::Cpus::from_json(settings.cpus.clone(), settings.version)),
};
@ -131,7 +131,7 @@ pub fn auto_detect0(settings_opt: Option<SettingsJson>, json_path: std::path::Pa
let cpu_driver: Box<dyn TCpus> = match cpus {
CpuLimit::SteamDeck => Box::new(crate::settings::steam_deck::Cpus::system_default()),
CpuLimit::SteamDeckAdvance => Box::new(crate::settings::steam_deck::Cpus::system_default()),
CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::from_limits(x)),
CpuLimit::Generic(x) => Box::new(crate::settings::generic::Cpus::<crate::settings::generic::Cpu>::from_limits(x)),
CpuLimit::GenericAMD(x) => Box::new(crate::settings::generic_amd::Cpus::from_limits(x)),
CpuLimit::Unknown => Box::new(crate::settings::unknown::Cpus::system_default()),
};

View file

@ -1,23 +1,24 @@
use std::convert::Into;
use std::convert::{Into, AsMut, AsRef};
use limits_core::json::GenericCpuLimit;
use crate::settings::MinMax;
use crate::settings::{MinMax, min_max_from_json};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpus, TCpu};
use crate::persist::CpuJson;
use super::FromGenericCpuInfo;
const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present";
const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
#[derive(Debug, Clone)]
pub struct Cpus {
pub cpus: Vec<Cpu>,
pub struct Cpus<C: AsMut<Cpu> + AsRef<Cpu> + TCpu> {
pub cpus: Vec<C>,
pub smt: bool,
pub smt_capable: bool,
}
impl OnSet for Cpus {
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + OnSet> OnSet for Cpus<C> {
fn on_set(&mut self) -> Result<(), SettingError> {
if self.smt_capable {
// toggle SMT
@ -44,14 +45,14 @@ impl OnSet for Cpus {
}
}
for (i, cpu) in self.cpus.as_mut_slice().iter_mut().enumerate() {
cpu.state.do_set_online = self.smt || i % 2 == 0 || !self.smt_capable;
cpu.as_mut().state.do_set_online = self.smt || i % 2 == 0 || !self.smt_capable;
cpu.on_set()?;
}
Ok(())
}
}
impl OnResume for Cpus {
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + OnResume> OnResume for Cpus<C> {
fn on_resume(&self) -> Result<(), SettingError> {
for cpu in &self.cpus {
cpu.on_resume()?;
@ -60,7 +61,7 @@ impl OnResume for Cpus {
}
}
impl Cpus {
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + FromGenericCpuInfo> Cpus<C> {
pub fn cpu_count() -> Option<usize> {
let mut data: String = usdpl_back::api::files::read_single(CPU_PRESENT_PATH)
.unwrap_or_else(|_| "0-7".to_string() /* Steam Deck's default */);
@ -86,7 +87,7 @@ impl Cpus {
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 = Cpu::from_limits(i, limits.clone());
let new_cpu = C::from_limits(i, limits.clone());
new_cpus.push(new_cpu);
}
Self {
@ -108,8 +109,8 @@ impl Cpus {
break;
}
}
let new_cpu = Cpu::from_json_and_limits(cpu, version, i, limits.clone());
smt_disabled &= new_cpu.online as usize != i % 2;
let mut new_cpu = C::from_json_and_limits(cpu, version, i, limits.clone());
smt_disabled &= *new_cpu.online() as usize != i % 2;
result.push(new_cpu);
}
if let Some(max_cpus) = max_cpus {
@ -128,17 +129,17 @@ impl Cpus {
}
}
impl TCpus for Cpus {
impl<C: AsMut<Cpu> + AsRef<Cpu> + TCpu + OnResume + OnSet> TCpus for Cpus<C> {
fn limits(&self) -> crate::api::CpusLimits {
crate::api::CpusLimits {
cpus: self.cpus.iter().map(|x| x.limits()).collect(),
cpus: self.cpus.iter().map(|x| x.as_ref().limits()).collect(),
count: self.cpus.len(),
smt_capable: self.smt_capable,
}
}
fn json(&self) -> Vec<crate::persist::CpuJson> {
self.cpus.iter().map(|x| x.to_owned().into()).collect()
self.cpus.iter().map(|x| x.as_ref().to_owned().into()).collect()
}
fn cpus(&mut self) -> Vec<&mut dyn TCpu> {
@ -162,18 +163,40 @@ impl TCpus for Cpus {
pub struct Cpu {
pub online: bool,
pub governor: String,
pub clock_limits: Option<MinMax<u64>>,
limits: GenericCpuLimit,
index: usize,
state: crate::state::steam_deck::Cpu,
}
impl Cpu {
#[inline]
pub fn from_limits(cpu_index: usize, limits: GenericCpuLimit) -> Self {
pub fn index(&self) -> usize {
self.index
}
}
impl AsRef<Cpu> for Cpu {
#[inline]
fn as_ref(&self) -> &Cpu {
self
}
}
impl AsMut<Cpu> for Cpu {
#[inline]
fn as_mut(&mut self) -> &mut Cpu {
self
}
}
impl FromGenericCpuInfo for Cpu {
#[inline]
fn from_limits(cpu_index: usize, limits: GenericCpuLimit) -> Self {
Self {
online: true,
governor: "schedutil".to_owned(),
clock_limits: None,
limits,
index: cpu_index,
state: crate::state::steam_deck::Cpu::default(),
@ -181,11 +204,17 @@ impl Cpu {
}
#[inline]
pub fn from_json_and_limits(other: CpuJson, version: u64, i: usize, limits: GenericCpuLimit) -> Self {
fn from_json_and_limits(other: CpuJson, version: u64, i: usize, limits: GenericCpuLimit) -> 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
};
match version {
0 => Self {
online: other.online,
governor: other.governor,
clock_limits: clock_lims,
limits,
index: i,
state: crate::state::steam_deck::Cpu::default(),
@ -193,13 +222,16 @@ impl Cpu {
_ => Self {
online: other.online,
governor: other.governor,
clock_limits: clock_lims,
limits,
index: i,
state: crate::state::steam_deck::Cpu::default(),
},
}
}
}
impl Cpu {
fn set_all(&mut self) -> Result<(), SettingError> {
// set cpu online/offline
if self.index != 0 && self.state.do_set_online { // cpu0 cannot be disabled
@ -270,7 +302,7 @@ impl Into<CpuJson> for Cpu {
fn into(self) -> CpuJson {
CpuJson {
online: self.online,
clock_limits: None,
clock_limits: self.clock_limits.map(|x| x.into()),
governor: self.governor,
}
}
@ -305,12 +337,13 @@ impl TCpu for Cpu {
}
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
self.limits.clock_min = limits.clone();
self.limits.clock_max = limits.clone();
if self.limits.clock_min.is_some() && self.limits.clock_max.is_some() {
self.clock_limits = limits;
}
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
self.limits.clock_max.as_ref()
self.clock_limits.as_ref()
}
}

View file

@ -2,14 +2,17 @@ use std::convert::Into;
use limits_core::json::GenericGpuLimit;
use crate::settings::MinMax;
use crate::settings::{MinMax, min_max_from_json};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::TGpu;
use crate::persist::GpuJson;
#[derive(Debug, Clone)]
pub struct Gpu {
slow_memory: bool, // ignored
slow_memory: bool,
fast_ppt: Option<u64>,
slow_ppt: Option<u64>,
clock_limits: Option<MinMax<u64>>,
limits: GenericGpuLimit,
}
@ -30,13 +33,24 @@ impl Gpu {
pub fn from_limits(limits: limits_core::json::GenericGpuLimit) -> Self {
Self {
slow_memory: false,
fast_ppt: None,
slow_ppt: None,
clock_limits: None,
limits,
}
}
pub fn from_json_and_limits(_other: GpuJson, _version: u64, limits: limits_core::json::GenericGpuLimit) -> Self {
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,
}
}
@ -46,9 +60,9 @@ impl Into<GpuJson> for Gpu {
#[inline]
fn into(self) -> GpuJson {
GpuJson {
fast_ppt: None,
slow_ppt: None,
clock_limits: None,
fast_ppt: self.fast_ppt,
slow_ppt: self.slow_ppt,
clock_limits: self.clock_limits.map(|x| x.into()),
slow_memory: false,
}
}
@ -86,18 +100,27 @@ impl TGpu for Gpu {
self.clone().into()
}
fn ppt(&mut self, _fast: Option<u64>, _slow: Option<u64>) {
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
if self.limits.fast_ppt.is_some() {
self.fast_ppt = fast;
}
if self.limits.slow_ppt.is_some() {
self.slow_ppt = slow;
}
}
fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
(None, None)
(self.fast_ppt, self.slow_ppt)
}
fn clock_limits(&mut self, _limits: Option<MinMax<u64>>) {
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
if self.limits.clock_min.is_some() && self.limits.clock_max.is_some() {
self.clock_limits = limits;
}
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
None
self.clock_limits.as_ref()
}
fn slow_memory(&mut self) -> &mut bool {

View file

@ -1,7 +1,9 @@
mod battery;
mod cpu;
mod gpu;
mod traits;
pub use battery::Battery;
pub use cpu::{Cpu, Cpus};
pub use gpu::Gpu;
pub use traits::FromGenericCpuInfo;

View file

@ -0,0 +1,8 @@
use limits_core::json::GenericCpuLimit;
use crate::persist::CpuJson;
pub trait FromGenericCpuInfo {
fn from_limits(cpu_index: usize, limits: GenericCpuLimit) -> Self;
fn from_json_and_limits(other: CpuJson, version: u64, cpu_index: usize, limits: GenericCpuLimit) -> Self;
}

View file

@ -1,12 +1,12 @@
use crate::persist::CpuJson;
use crate::settings::MinMax;
use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus};
use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus, FromGenericCpuInfo};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{TCpus, TCpu};
#[derive(Debug)]
pub struct Cpus {
generic: GenericCpus,
generic: GenericCpus<Cpu>,
}
impl Cpus {
@ -68,6 +68,48 @@ pub struct Cpu {
generic: GenericCpu,
}
impl FromGenericCpuInfo for Cpu {
fn from_limits(cpu_index: usize, limits: limits_core::json::GenericCpuLimit) -> Self {
let gen = GenericCpu::from_limits(cpu_index, limits.clone());
Self {
generic: gen,
}
}
fn from_json_and_limits(other: CpuJson, version: u64, cpu_index: usize, limits: limits_core::json::GenericCpuLimit) -> Self {
let gen = GenericCpu::from_json_and_limits(other, version, cpu_index, limits);
Self {
generic: gen,
}
}
}
impl AsRef<GenericCpu> for Cpu {
fn as_ref(&self) -> &GenericCpu {
&self.generic
}
}
impl AsMut<GenericCpu> for Cpu {
fn as_mut(&mut self) -> &mut GenericCpu {
&mut self.generic
}
}
impl OnResume for Cpu {
fn on_resume(&self) -> Result<(), SettingError> {
self.generic.on_resume()
// TODO
}
}
impl OnSet for Cpu {
fn on_set(&mut self) -> Result<(), SettingError> {
self.generic.on_set()
// TODO
}
}
impl TCpu for Cpu {
fn online(&mut self) -> &mut bool {
self.generic.online()
@ -82,10 +124,10 @@ impl TCpu for Cpu {
}
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
self.generic.clock_limits(limits) // TODO
self.generic.clock_limits(limits)
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
self.generic.get_clock_limits() // TODO
self.generic.get_clock_limits()
}
}

View file

@ -47,15 +47,15 @@ impl TGpu for Gpu {
}
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
// TODO
self.generic.ppt(fast, slow)
}
fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
self.generic.get_ppt() // TODO
self.generic.get_ppt()
}
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
// TODO
self.generic.clock_limits(limits)
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {