forked from NG-SD-Plugins/PowerTools
Add experimental Decky CI back-end building, fix frequency controls crashing the kernel
This commit is contained in:
parent
18433bf5c5
commit
db3f4a85c0
45 changed files with 289 additions and 97 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -41,5 +41,6 @@ __pycache__/
|
|||
yalc.lock
|
||||
|
||||
# rust
|
||||
/powertools-rs/target
|
||||
/backend/target
|
||||
/bin
|
||||
/backend/out
|
||||
|
|
6
powertools-rs/Cargo.lock → backend/Cargo.lock
generated
6
powertools-rs/Cargo.lock → backend/Cargo.lock
generated
|
@ -567,7 +567,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "powertools-rs"
|
||||
version = "1.0.0"
|
||||
version = "1.0.0-beta4"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
|
@ -1054,6 +1054,8 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "usdpl-back"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbbc0781e83ba990f8239142e33173a2d2548701775f3db66702d1af4fd0319a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"hex",
|
||||
|
@ -1066,6 +1068,8 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "usdpl-core"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "862153581fac266458521f49e5906a71c1eee1665cb4c7d71e9586bd34b45394"
|
||||
dependencies = [
|
||||
"aes-gcm-siv",
|
||||
"base64",
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "powertools-rs"
|
||||
version = "1.0.0"
|
||||
version = "1.0.0-beta4"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
usdpl-back = { version = "0.6.0", features = ["blocking"], path = "../../usdpl-rs/usdpl-back"}
|
||||
usdpl-back = { version = "0.6.0", features = ["blocking"]}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
|
@ -19,3 +19,9 @@ default = []
|
|||
decky = ["usdpl-back/decky"]
|
||||
crankshaft = ["usdpl-back/crankshaft"]
|
||||
encrypt = ["usdpl-back/encrypt"]
|
||||
|
||||
[profile.release]
|
||||
debug = false
|
||||
strip = true
|
||||
lto = true
|
||||
codegen-units = 4
|
3
backend/Dockerfile
Normal file
3
backend/Dockerfile
Normal file
|
@ -0,0 +1,3 @@
|
|||
FROM ghcr.io/steamdeckhomebrew/holo-toolchain-rust:latest
|
||||
|
||||
ENTRYPOINT [ "/backend/entrypoint.sh" ]
|
14
backend/Makefile
Normal file
14
backend/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
# This is the default target, which will be built when
|
||||
# you invoke make
|
||||
.PHONY: all
|
||||
all: hello
|
||||
|
||||
# This rule tells make how to build hello from hello.cpp
|
||||
hello:
|
||||
mkdir -p ./out
|
||||
gcc -o ./out/hello ./src/main.c
|
||||
|
||||
# This rule tells make to delete hello and hello.o
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f hello
|
15
backend/build-docker.sh
Executable file
15
backend/build-docker.sh
Executable file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "--- Rust version info ---"
|
||||
rustup --version
|
||||
rustc --version
|
||||
cargo --version
|
||||
|
||||
echo "--- Building plugin backend ---"
|
||||
cargo build --release
|
||||
mkdir -p out
|
||||
cp target/release/powertools-rs out/backend
|
||||
|
||||
echo " --- Cleaning up ---"
|
||||
# remove root-owned target folder
|
||||
cargo clean
|
4
backend/create_docker_img.sh
Executable file
4
backend/create_docker_img.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
# build docker container locally (for testing)
|
||||
|
||||
docker build -t powertools_backend .
|
8
backend/entrypoint.sh
Executable file
8
backend/entrypoint.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Container's IP address: `awk 'END{print $1}' /etc/hosts`"
|
||||
|
||||
cd /backend
|
||||
|
||||
sudo bash build-docker.sh
|
7
backend/run_docker_img.sh
Executable file
7
backend/run_docker_img.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
# run docker container locally (for testing)
|
||||
# assumes you're running in the backend/ dir of the project
|
||||
|
||||
docker run -i --entrypoint /backend/entrypoint.sh -v $PWD:/backend powertools_backend
|
||||
mkdir -p ../bin
|
||||
cp ./out/backend ../bin
|
|
@ -59,6 +59,6 @@ pub fn unset_charge_rate(
|
|||
unwrap_lock(saver.lock(), "save channel").send(()),
|
||||
"Failed to send on save channel",
|
||||
);
|
||||
vec![]
|
||||
super::utility::map_empty_result(settings_lock.on_set(), true)
|
||||
}
|
||||
}
|
|
@ -139,7 +139,7 @@ pub fn unset_clock_limits(
|
|||
unwrap_lock(saver.lock(), "save channel").send(()),
|
||||
"Failed to send on save channel",
|
||||
);
|
||||
vec![]
|
||||
super::utility::map_empty_result(cpu.on_set(), true)
|
||||
} else {
|
||||
vec!["get_clock_limits cpu index out of bounds".into()]
|
||||
}
|
|
@ -97,7 +97,7 @@ pub fn get_name(
|
|||
}
|
||||
}
|
||||
|
||||
/// Generate get current settings name
|
||||
/// Generate wait for all locks to be available web method
|
||||
pub fn lock_unlock_all(
|
||||
settings: Settings,
|
||||
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
|
@ -124,7 +124,7 @@ pub fn unset_clock_limits(
|
|||
unwrap_lock(saver.lock(), "save channel").send(()),
|
||||
"Failed to send on save channel",
|
||||
);
|
||||
vec![]
|
||||
super::utility::map_empty_result(settings_lock.on_set(), true)
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,13 @@ use usdpl_back::core::serdes::Primitive;
|
|||
use usdpl_back::Instance;
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
let log_filepath = format!("/tmp/{}.log", PACKAGE_NAME);
|
||||
let log_filepath = format!("/home/deck/{}.log", PACKAGE_NAME);
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if std::path::Path::new(&log_filepath).exists() {
|
||||
std::fs::copy(&log_filepath, "/home/deck/powertools.log.old").unwrap();
|
||||
}
|
||||
}
|
||||
WriteLogger::init(
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
|
@ -6,6 +6,7 @@ use crate::persist::BatteryJson;
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Battery {
|
||||
pub charge_rate: Option<u64>,
|
||||
state: crate::state::Battery,
|
||||
}
|
||||
|
||||
const BATTERY_CHARGE_RATE_PATH: &str = "/sys/class/hwmon/hwmon5/maximum_battery_charge_rate"; // write-only
|
||||
|
@ -17,21 +18,32 @@ impl Battery {
|
|||
match version {
|
||||
0 => Self {
|
||||
charge_rate: other.charge_rate,
|
||||
state: crate::state::Battery::default(),
|
||||
},
|
||||
_ => Self {
|
||||
charge_rate: other.charge_rate,
|
||||
state: crate::state::Battery::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn set_all(&self) -> Result<(), SettingError> {
|
||||
fn set_all(&mut self) -> Result<(), SettingError> {
|
||||
if let Some(charge_rate) = self.charge_rate {
|
||||
self.state.charge_rate_set = true;
|
||||
usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, charge_rate).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
|
||||
setting: super::SettingVariant::Battery,
|
||||
},
|
||||
)
|
||||
} else if self.state.charge_rate_set {
|
||||
self.state.charge_rate_set = false;
|
||||
usdpl_back::api::files::write_single(BATTERY_CHARGE_RATE_PATH, Self::max().charge_rate.unwrap()).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", BATTERY_CHARGE_RATE_PATH, e),
|
||||
setting: super::SettingVariant::Battery,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -66,7 +78,10 @@ impl Battery {
|
|||
}
|
||||
|
||||
pub fn system_default() -> Self {
|
||||
Self { charge_rate: None }
|
||||
Self {
|
||||
charge_rate: None,
|
||||
state: crate::state::Battery::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +103,7 @@ impl OnSet for Battery {
|
|||
|
||||
impl OnResume for Battery {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
self.set_all()
|
||||
self.clone().set_all()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,6 +112,7 @@ impl SettingsRange for Battery {
|
|||
fn max() -> Self {
|
||||
Self {
|
||||
charge_rate: Some(2500),
|
||||
state: crate::state::Battery::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +120,7 @@ impl SettingsRange for Battery {
|
|||
fn min() -> Self {
|
||||
Self {
|
||||
charge_rate: Some(250),
|
||||
state: crate::state::Battery::default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ pub struct Cpu {
|
|||
pub clock_limits: Option<MinMax<u64>>,
|
||||
pub governor: String,
|
||||
index: usize,
|
||||
state: crate::state::Cpu,
|
||||
}
|
||||
|
||||
const CPU_CLOCK_LIMITS_PATH: &str = "/sys/class/drm/card0/device/pp_od_clk_voltage";
|
||||
|
@ -26,17 +27,19 @@ impl Cpu {
|
|||
clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)),
|
||||
governor: other.governor,
|
||||
index: i,
|
||||
state: crate::state::Cpu::default(),
|
||||
},
|
||||
_ => Self {
|
||||
online: other.online,
|
||||
clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)),
|
||||
governor: other.governor,
|
||||
index: i,
|
||||
state: crate::state::Cpu::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn set_all(&self) -> Result<(), SettingError> {
|
||||
fn set_all(&mut self) -> Result<(), SettingError> {
|
||||
// set cpu online/offline
|
||||
if self.index != 0 { // cpu0 cannot be disabled
|
||||
let online_path = cpu_online_path(self.index);
|
||||
|
@ -48,7 +51,9 @@ impl Cpu {
|
|||
})?;
|
||||
}
|
||||
// set clock limits
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
log::debug!("Setting {} to manual", CPU_FORCE_LIMITS_PATH);
|
||||
let mode: String = usdpl_back::api::files::read_single(CPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
|
||||
if mode != "manual" {
|
||||
// set manual control
|
||||
usdpl_back::api::files::write_single(CPU_FORCE_LIMITS_PATH, "manual").map_err(|e| {
|
||||
SettingError {
|
||||
|
@ -59,8 +64,12 @@ impl Cpu {
|
|||
setting: super::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
}
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
log::debug!("Setting CPU {} (min, max) clockspeed to ({}, {})", self.index, clock_limits.min, clock_limits.max);
|
||||
self.state.clock_limits_set = true;
|
||||
// max clock
|
||||
let payload_max = format!("p {} 1 {}", self.index / 2, clock_limits.max);
|
||||
let payload_max = format!("p {} 1 {}\n", self.index / 2, clock_limits.max);
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
|
@ -71,7 +80,7 @@ impl Cpu {
|
|||
},
|
||||
)?;
|
||||
// min clock
|
||||
let payload_min = format!("p {} 0 {}", self.index / 2, clock_limits.min);
|
||||
let payload_min = format!("p {} 0 {}\n", self.index / 2, clock_limits.min);
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
|
@ -81,25 +90,41 @@ impl Cpu {
|
|||
setting: super::SettingVariant::Cpu,
|
||||
},
|
||||
)?;
|
||||
// commit changes
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, "c").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", CPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: super::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
} else {
|
||||
} else if self.state.clock_limits_set {
|
||||
self.state.clock_limits_set = false;
|
||||
// disable manual clock limits
|
||||
usdpl_back::api::files::write_single(CPU_FORCE_LIMITS_PATH, "auto").map_err(|e| {
|
||||
SettingError {
|
||||
log::debug!("Setting CPU {} to default clockspeed", self.index);
|
||||
// max clock
|
||||
let payload_max = format!("p {} 1 {}\n", self.index / 2, Self::max().clock_limits.unwrap().max);
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_max).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `auto` to `{}`: {}",
|
||||
CPU_FORCE_LIMITS_PATH, e
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_max, CPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
// min clock
|
||||
let payload_min = format!("p {} 0 {}\n", self.index / 2, Self::min().clock_limits.unwrap().min);
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, &payload_min).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_min, CPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Cpu,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
// commit changes
|
||||
usdpl_back::api::files::write_single(CPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", CPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: super::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
|
||||
// set governor
|
||||
if self.index == 0 || self.online {
|
||||
let governor_path = cpu_governor_path(self.index);
|
||||
|
@ -134,6 +159,7 @@ impl Cpu {
|
|||
governor: usdpl_back::api::files::read_single(cpu_governor_path(index))
|
||||
.unwrap_or("schedutil".to_owned()),
|
||||
index: index,
|
||||
state: crate::state::Cpu::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,8 +178,8 @@ impl Cpu {
|
|||
|
||||
pub fn system_default() -> Vec<Self> {
|
||||
if let Some(max_cpu) = Self::cpu_count() {
|
||||
let mut cpus = Vec::with_capacity(max_cpu + 1);
|
||||
for i in 0..=max_cpu {
|
||||
let mut cpus = Vec::with_capacity(max_cpu);
|
||||
for i in 0..max_cpu {
|
||||
cpus.push(Self::from_sys(i));
|
||||
}
|
||||
cpus
|
||||
|
@ -183,7 +209,7 @@ impl OnSet for Cpu {
|
|||
|
||||
impl OnResume for Cpu {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
self.set_all()
|
||||
self.clone().set_all()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +224,7 @@ impl SettingsRange for Cpu {
|
|||
}),
|
||||
governor: "schedutil".to_owned(),
|
||||
index: usize::MAX,
|
||||
state: crate::state::Cpu::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +234,8 @@ impl SettingsRange for Cpu {
|
|||
online: false,
|
||||
clock_limits: Some(MinMax { max: 500, min: 1400 }),
|
||||
governor: "schedutil".to_owned(),
|
||||
index: 0,
|
||||
index: usize::MIN,
|
||||
state: crate::state::Cpu::default(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -120,7 +120,8 @@ impl Settings {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn load_file(&self, json_path: PathBuf, name: String) -> Result<bool, SettingError> {
|
||||
pub fn load_file(&self, filename: PathBuf, name: String) -> Result<bool, SettingError> {
|
||||
let json_path = crate::utility::settings_dir().join(filename);
|
||||
let mut general_lock = unwrap_lock(self.general.lock(), "general");
|
||||
if json_path.exists() {
|
||||
let settings_json = SettingsJson::open(&json_path).map_err(|e| SettingError {
|
|
@ -13,6 +13,7 @@ pub struct Gpu {
|
|||
pub slow_ppt: Option<u64>,
|
||||
pub clock_limits: Option<MinMax<u64>>,
|
||||
pub slow_memory: bool,
|
||||
state: crate::state::Gpu,
|
||||
}
|
||||
|
||||
// same as CPU
|
||||
|
@ -29,17 +30,19 @@ impl Gpu {
|
|||
slow_ppt: other.slow_ppt,
|
||||
clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)),
|
||||
slow_memory: other.slow_memory,
|
||||
state: crate::state::Gpu::default(),
|
||||
},
|
||||
_ => Self {
|
||||
fast_ppt: other.fast_ppt,
|
||||
slow_ppt: other.slow_ppt,
|
||||
clock_limits: other.clock_limits.map(|x| MinMax::from_json(x, version)),
|
||||
slow_memory: other.slow_memory,
|
||||
state: crate::state::Gpu::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn set_all(&self) -> Result<(), SettingError> {
|
||||
fn set_all(&mut self) -> Result<(), SettingError> {
|
||||
// set fast PPT
|
||||
if let Some(fast_ppt) = &self.fast_ppt {
|
||||
let fast_ppt_path = gpu_power_path(FAST_PPT);
|
||||
|
@ -67,7 +70,8 @@ impl Gpu {
|
|||
})?;
|
||||
}
|
||||
// settings using force_performance_level
|
||||
if self.clock_limits.is_some() || self.slow_memory {
|
||||
let mode: String = usdpl_back::api::files::read_single(GPU_FORCE_LIMITS_PATH.to_owned()).unwrap();
|
||||
if mode != "manual" {
|
||||
// set manual control
|
||||
usdpl_back::api::files::write_single(GPU_FORCE_LIMITS_PATH, "manual").map_err(|e| {
|
||||
SettingError {
|
||||
|
@ -78,58 +82,73 @@ impl Gpu {
|
|||
setting: super::SettingVariant::Gpu,
|
||||
}
|
||||
})?;
|
||||
// set clock limits
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
// max clock
|
||||
let payload_max = format!("s 1 {}", clock_limits.max);
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_max, GPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
},
|
||||
)?;
|
||||
// min clock
|
||||
let payload_min = format!("s 0 {}", clock_limits.min);
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_min, GPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
// force downclock of GPU memory (to 400Mhz?)
|
||||
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8)
|
||||
.map_err(|e| SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
})?;
|
||||
// commit changes
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
}
|
||||
}
|
||||
// enable/disable downclock of GPU memory (to 400Mhz?)
|
||||
usdpl_back::api::files::write_single(GPU_MEMORY_DOWNCLOCK_PATH, self.slow_memory as u8)
|
||||
.map_err(|e| SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", GPU_MEMORY_DOWNCLOCK_PATH, e),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
})?;
|
||||
} else {
|
||||
// disable manual clock limits
|
||||
usdpl_back::api::files::write_single(GPU_FORCE_LIMITS_PATH, "auto").map_err(|e| {
|
||||
SettingError {
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
// set clock limits
|
||||
self.state.clock_limits_set = true;
|
||||
// max clock
|
||||
let payload_max = format!("s 1 {}\n", clock_limits.max);
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `auto` to `{}`: {}",
|
||||
GPU_FORCE_LIMITS_PATH, e
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_max, GPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
}
|
||||
})?;
|
||||
},
|
||||
)?;
|
||||
// min clock
|
||||
let payload_min = format!("s 0 {}\n", clock_limits.min);
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_min, GPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
},
|
||||
)?;
|
||||
} else if self.state.clock_limits_set {
|
||||
self.state.clock_limits_set = false;
|
||||
// disable manual clock limits
|
||||
// max clock
|
||||
let payload_max = format!("s 1 {}\n", Self::max().clock_limits.unwrap().max);
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_max).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_max, GPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
},
|
||||
)?;
|
||||
// min clock
|
||||
let payload_min = format!("s 0 {}\n", Self::min().clock_limits.unwrap().min);
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, &payload_min).map_err(
|
||||
|e| SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&payload_min, GPU_CLOCK_LIMITS_PATH, e
|
||||
),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
// commit changes
|
||||
usdpl_back::api::files::write_single(GPU_CLOCK_LIMITS_PATH, "c\n").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write `c` to `{}`: {}", GPU_CLOCK_LIMITS_PATH, e),
|
||||
setting: super::SettingVariant::Gpu,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(()) // TODO
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clamp_all(&mut self) {
|
||||
|
@ -161,6 +180,7 @@ impl Gpu {
|
|||
slow_ppt: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
state: crate::state::Gpu::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +206,7 @@ impl OnSet for Gpu {
|
|||
|
||||
impl OnResume for Gpu {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
self.set_all()
|
||||
self.clone().set_all()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,6 +221,7 @@ impl SettingsRange for Gpu {
|
|||
max: 1600,
|
||||
}),
|
||||
slow_memory: false,
|
||||
state: crate::state::Gpu::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +232,7 @@ impl SettingsRange for Gpu {
|
|||
slow_ppt: Some(1000000),
|
||||
clock_limits: Some(MinMax { min: 200, max: 200 }),
|
||||
slow_memory: true,
|
||||
state: crate::state::Gpu::default(),
|
||||
}
|
||||
}
|
||||
}
|
12
backend/src/state/battery.rs
Normal file
12
backend/src/state/battery.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Battery {
|
||||
pub charge_rate_set: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for Battery {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
charge_rate_set: false,
|
||||
}
|
||||
}
|
||||
}
|
12
backend/src/state/cpu.rs
Normal file
12
backend/src/state/cpu.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Cpu {
|
||||
pub clock_limits_set: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for Cpu {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
clock_limits_set: false,
|
||||
}
|
||||
}
|
||||
}
|
12
backend/src/state/gpu.rs
Normal file
12
backend/src/state/gpu.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Gpu {
|
||||
pub clock_limits_set: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for Gpu {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
clock_limits_set: false,
|
||||
}
|
||||
}
|
||||
}
|
11
backend/src/state/mod.rs
Normal file
11
backend/src/state/mod.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
mod battery;
|
||||
mod cpu;
|
||||
mod error;
|
||||
mod gpu;
|
||||
mod traits;
|
||||
|
||||
pub use battery::Battery;
|
||||
pub use cpu::Cpu;
|
||||
pub use error::StateError;
|
||||
pub use gpu::Gpu;
|
||||
pub use traits::OnPoll;
|
2
main.py
2
main.py
|
@ -11,6 +11,6 @@ class Plugin:
|
|||
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
||||
async def _main(self):
|
||||
# startup
|
||||
self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"])
|
||||
#self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend"])
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
mod error;
|
||||
mod traits;
|
||||
|
||||
pub use error::StateError;
|
||||
pub use traits::OnPoll;
|
|
@ -173,16 +173,21 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
onChange={(smt: boolean) => {
|
||||
console.debug("SMT is now " + smt.toString());
|
||||
const cpus = get_value(ONLINE_CPUS);
|
||||
set_value(ONLINE_CPUS, 0);
|
||||
smtGlobal = smt && smtAllowed;
|
||||
for (let i = 0; i < total_cpus; i++) {
|
||||
const online = (smtGlobal? i < cpus : (i % 2 == 0) && (i < cpus * 2))
|
||||
|| (!smtGlobal && cpus == 4);
|
||||
backend.resolve(backend.setCpuOnline(i, online), (value: boolean) => {
|
||||
if (value) {set_value(ONLINE_CPUS, get_value(ONLINE_CPUS) + 1)}
|
||||
})
|
||||
backend.resolve(backend.setCpuOnline(i, online), (_value: boolean) => {});
|
||||
}
|
||||
backend.resolve(backend.waitForComplete(), (_: boolean[]) => {
|
||||
backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => {
|
||||
// TODO: allow for per-core control of online status
|
||||
let count = 0;
|
||||
for (let i = 0; i < statii.length; i++) {
|
||||
if (statii[i]) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
set_value(ONLINE_CPUS, count);
|
||||
reloadGUI("SMT");
|
||||
});
|
||||
}}
|
||||
|
@ -200,14 +205,21 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
console.debug("CPU slider is now " + cpus.toString());
|
||||
const onlines = get_value(ONLINE_CPUS);
|
||||
if (cpus != onlines) {
|
||||
set_value(ONLINE_CPUS, 0);
|
||||
for (let i = 0; i < total_cpus; i++) {
|
||||
const online = smtGlobal? i < cpus : (i % 2 == 0) && (i < cpus * 2);
|
||||
backend.resolve(backend.setCpuOnline(i, online), (value: boolean) => {
|
||||
if (value) {set_value(ONLINE_CPUS, get_value(ONLINE_CPUS) + 1)}
|
||||
})
|
||||
}
|
||||
backend.resolve(backend.waitForComplete(), (_: boolean[]) => {
|
||||
backend.resolve(backend.getCpusOnline(), (statii: boolean[]) => {
|
||||
// TODO: allow for per-core control of online status
|
||||
let count = 0;
|
||||
for (let i = 0; i < statii.length; i++) {
|
||||
if (statii[i]) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
set_value(ONLINE_CPUS, count);
|
||||
reloadGUI("CPUs");
|
||||
});
|
||||
}
|
||||
|
@ -218,6 +230,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
<ToggleField
|
||||
checked={get_value(CLOCK_MIN_CPU) != null && get_value(CLOCK_MAX_CPU) != null}
|
||||
label="Frequency Limits"
|
||||
description="Set bounds on clock speed"
|
||||
onChange={(value: boolean) => {
|
||||
if (value) {
|
||||
set_value(CLOCK_MIN_CPU, 1400);
|
||||
|
@ -365,6 +378,7 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
<ToggleField
|
||||
checked={get_value(CLOCK_MIN_GPU) != null && get_value(CLOCK_MAX_GPU) != null}
|
||||
label="Frequency Limits"
|
||||
description="Override bounds on gpu clock"
|
||||
onChange={(value: boolean) => {
|
||||
if (value) {
|
||||
set_value(CLOCK_MIN_GPU, 200);
|
||||
|
|
Loading…
Reference in a new issue