forked from NG-SD-Plugins/PowerTools
Improve memory clock selection for #140, fix dpm_performance enforcement check for GPU
This commit is contained in:
parent
622f161560
commit
a1c44cdea7
19 changed files with 285 additions and 113 deletions
|
@ -43,5 +43,5 @@ pub struct Gpu {
|
|||
pub tdp: Option<u64>,
|
||||
pub tdp_boost: Option<u64>,
|
||||
pub clock_limits: Option<MinMax<u64>>,
|
||||
pub slow_memory: bool,
|
||||
pub memory_clock: Option<u64>,
|
||||
}
|
||||
|
|
|
@ -16,35 +16,11 @@ 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)|(0932)\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)|(0932)\n".to_owned()),
|
||||
cpuinfo: Some("model name\t: AMD Custom APU 0405\n".to_owned()),
|
||||
os: None,
|
||||
command: None,
|
||||
file_exists: None,
|
||||
|
@ -64,6 +40,30 @@ impl Default for Base {
|
|||
},
|
||||
}
|
||||
},
|
||||
super::Config {
|
||||
name: "Steam Deck OLED".to_owned(),
|
||||
conditions: super::Conditions {
|
||||
dmi: None,
|
||||
cpuinfo: Some("model name\t: AMD Custom APU 0932\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::SteamDeckOLED),
|
||||
},
|
||||
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 {
|
||||
|
|
|
@ -8,6 +8,8 @@ pub enum GpuLimitType {
|
|||
SteamDeck,
|
||||
#[serde(rename = "GabeBoyAdvance", alias = "SteamDeckAdvance")]
|
||||
SteamDeckAdvance,
|
||||
#[serde(rename = "GabeBoy101", alias = "SteamDeckOLED")]
|
||||
SteamDeckOLED,
|
||||
Generic,
|
||||
GenericAMD,
|
||||
Unknown,
|
||||
|
@ -27,6 +29,8 @@ pub struct GenericGpuLimit {
|
|||
pub clock_min: Option<RangeLimit<u64>>,
|
||||
pub clock_max: Option<RangeLimit<u64>>,
|
||||
pub clock_step: Option<u64>,
|
||||
pub memory_clock: Option<RangeLimit<u64>>,
|
||||
pub memory_clock_step: Option<u64>,
|
||||
pub skip_resume_reclock: bool,
|
||||
}
|
||||
|
||||
|
@ -34,6 +38,7 @@ impl GenericGpuLimit {
|
|||
pub fn default_for(t: GpuLimitType) -> Self {
|
||||
match t {
|
||||
GpuLimitType::SteamDeck | GpuLimitType::SteamDeckAdvance => Self::default_steam_deck(),
|
||||
GpuLimitType::SteamDeckOLED => Self::default_steam_deck_oled(),
|
||||
_t => Self::default(),
|
||||
}
|
||||
}
|
||||
|
@ -64,10 +69,24 @@ impl GenericGpuLimit {
|
|||
max: Some(1600),
|
||||
}),
|
||||
clock_step: Some(100),
|
||||
// Disabled for now since LCD version is a bit broken on sysfs right now
|
||||
/*memory_clock: Some(RangeLimit {
|
||||
min: Some(400),
|
||||
max: Some(800),
|
||||
}),
|
||||
memory_clock_step: Some(400),*/
|
||||
memory_clock: None,
|
||||
memory_clock_step: None,
|
||||
skip_resume_reclock: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn default_steam_deck_oled() -> Self {
|
||||
let mut sd = Self::default_steam_deck();
|
||||
sd.memory_clock_step = Some(200);
|
||||
sd
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -59,7 +59,8 @@ pub struct GpuLimits {
|
|||
pub clock_min_limits: Option<RangeLimit<u64>>,
|
||||
pub clock_max_limits: Option<RangeLimit<u64>>,
|
||||
pub clock_step: u64,
|
||||
pub memory_control_capable: bool,
|
||||
pub memory_control: Option<RangeLimit<u64>>,
|
||||
pub memory_step: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
|
|
@ -160,17 +160,17 @@ pub fn set_slow_memory(
|
|||
sender: Sender<ApiMessage>,
|
||||
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||
let setter = move |value: bool| {
|
||||
let setter = move |value: u64| {
|
||||
sender
|
||||
.lock()
|
||||
.unwrap()
|
||||
.send(ApiMessage::Gpu(GpuMessage::SetSlowMemory(value)))
|
||||
.send(ApiMessage::Gpu(GpuMessage::SetMemoryClock(Some(value))))
|
||||
.expect("unset_clock_limits send failed")
|
||||
};
|
||||
move |params_in: super::ApiParameterType| {
|
||||
if let Some(&Primitive::Bool(memory_is_slow)) = params_in.get(0) {
|
||||
setter(memory_is_slow);
|
||||
vec![memory_is_slow.into()]
|
||||
if let Some(&Primitive::F64(mem_clock)) = params_in.get(0) {
|
||||
setter(mem_clock as _);
|
||||
vec![mem_clock.into()]
|
||||
} else {
|
||||
vec!["set_slow_memory missing parameter 0".into()]
|
||||
}
|
||||
|
@ -183,14 +183,14 @@ pub fn get_slow_memory(sender: Sender<ApiMessage>) -> impl AsyncCallable {
|
|||
let sender2 = sender.clone();
|
||||
move || {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let callback = move |value: bool| {
|
||||
let callback = move |value: Option<u64>| {
|
||||
tx.send(value)
|
||||
.expect("get_slow_memory callback send failed")
|
||||
};
|
||||
sender2
|
||||
.lock()
|
||||
.unwrap()
|
||||
.send(ApiMessage::Gpu(GpuMessage::GetSlowMemory(Box::new(
|
||||
.send(ApiMessage::Gpu(GpuMessage::GetMemoryClock(Box::new(
|
||||
callback,
|
||||
))))
|
||||
.expect("get_slow_memory send failed");
|
||||
|
@ -199,6 +199,23 @@ pub fn get_slow_memory(sender: Sender<ApiMessage>) -> impl AsyncCallable {
|
|||
};
|
||||
super::async_utils::AsyncIshGetter {
|
||||
set_get: getter,
|
||||
trans_getter: |value: bool| vec![value.into()],
|
||||
trans_getter: |value: Option<u64>| vec![super::utility::map_optional(value)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unset_slow_memory(
|
||||
sender: Sender<ApiMessage>,
|
||||
) -> impl Fn(super::ApiParameterType) -> super::ApiParameterType {
|
||||
let sender = Mutex::new(sender); // Sender is not Sync; this is required for safety
|
||||
let setter = move || {
|
||||
sender
|
||||
.lock()
|
||||
.unwrap()
|
||||
.send(ApiMessage::Gpu(GpuMessage::SetMemoryClock(None)))
|
||||
.expect("unset_slow_memory send failed")
|
||||
};
|
||||
move |_: super::ApiParameterType| {
|
||||
setter();
|
||||
vec![true.into()]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,8 +198,8 @@ pub enum GpuMessage {
|
|||
GetPpt(Callback<(Option<u64>, Option<u64>)>),
|
||||
SetClockLimits(Option<MinMax<u64>>),
|
||||
GetClockLimits(Callback<Option<MinMax<u64>>>),
|
||||
SetSlowMemory(bool),
|
||||
GetSlowMemory(Callback<bool>),
|
||||
SetMemoryClock(Option<u64>),
|
||||
GetMemoryClock(Callback<Option<u64>>),
|
||||
}
|
||||
|
||||
impl GpuMessage {
|
||||
|
@ -210,8 +210,8 @@ impl GpuMessage {
|
|||
Self::GetPpt(cb) => cb(settings.get_ppt()),
|
||||
Self::SetClockLimits(clocks) => settings.clock_limits(clocks),
|
||||
Self::GetClockLimits(cb) => cb(settings.get_clock_limits().map(|x| x.to_owned())),
|
||||
Self::SetSlowMemory(val) => *settings.slow_memory() = val,
|
||||
Self::GetSlowMemory(cb) => cb(*settings.slow_memory()),
|
||||
Self::SetMemoryClock(val) => settings.memory_clock(val),
|
||||
Self::GetMemoryClock(cb) => cb(settings.get_memory_clock()),
|
||||
}
|
||||
dirty
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ impl GpuMessage {
|
|||
fn is_modify(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::SetPpt(_, _) | Self::SetClockLimits(_) | Self::SetSlowMemory(_)
|
||||
Self::SetPpt(_, _) | Self::SetClockLimits(_) | Self::SetMemoryClock(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ fn web_config_to_settings_json(meta: community_settings_core::v1::Metadata) -> c
|
|||
min: lim.min,
|
||||
max: lim.max,
|
||||
}),
|
||||
slow_memory: meta.config.gpu.slow_memory,
|
||||
memory_clock: meta.config.gpu.memory_clock,
|
||||
root: None,
|
||||
},
|
||||
battery: crate::persist::BatteryJson {
|
||||
|
@ -138,7 +138,7 @@ fn settings_to_web_config(app_id: u32, user_id: u64, username: String, settings:
|
|||
min: lim.min,
|
||||
max: lim.max,
|
||||
}),
|
||||
slow_memory: settings.gpu.slow_memory,
|
||||
memory_clock: settings.gpu.memory_clock,
|
||||
},
|
||||
battery: community_settings_core::v1::Battery {
|
||||
charge_rate: settings.battery.charge_rate,
|
||||
|
|
|
@ -243,6 +243,10 @@ fn main() -> Result<(), ()> {
|
|||
"GPU_get_slow_memory",
|
||||
api::gpu::get_slow_memory(api_sender.clone()),
|
||||
)
|
||||
.register(
|
||||
"GPU_unset_slow_memory",
|
||||
api::gpu::unset_slow_memory(api_sender.clone()),
|
||||
)
|
||||
// general API functions
|
||||
.register(
|
||||
"GENERAL_set_persistent",
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct GpuJson {
|
|||
pub tdp: Option<u64>,
|
||||
pub tdp_boost: Option<u64>,
|
||||
pub clock_limits: Option<MinMaxJson<u64>>,
|
||||
pub slow_memory: bool,
|
||||
pub memory_clock: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub root: Option<String>,
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ impl Default for GpuJson {
|
|||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
memory_clock: None,
|
||||
root: None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,6 +203,13 @@ pub fn auto_detect0(
|
|||
relevant_limits.gpu.limits,
|
||||
))
|
||||
}
|
||||
GpuLimitType::SteamDeckOLED => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_json_and_limits(
|
||||
settings.gpu.clone(),
|
||||
settings.version,
|
||||
relevant_limits.gpu.limits,
|
||||
))
|
||||
}
|
||||
GpuLimitType::Generic => {
|
||||
Box::new(crate::settings::generic::Gpu::from_json_and_limits(
|
||||
settings.gpu.clone(),
|
||||
|
@ -289,6 +296,9 @@ pub fn auto_detect0(
|
|||
GpuLimitType::SteamDeckAdvance => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
GpuLimitType::SteamDeckOLED => {
|
||||
Box::new(crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
GpuLimitType::Generic => {
|
||||
Box::new(crate::settings::generic::Gpu::from_limits(relevant_limits.gpu.limits))
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ impl Into<GpuJson> for Gpu {
|
|||
tdp: self.tdp,
|
||||
tdp_boost: self.tdp_boost,
|
||||
clock_limits: self.clock_limits.map(|x| x.into()),
|
||||
slow_memory: false,
|
||||
memory_clock: None,
|
||||
root: self.sysfs.root().and_then(|p| p.as_ref().to_str().map(|s| s.to_owned()))
|
||||
}
|
||||
}
|
||||
|
@ -177,7 +177,8 @@ impl TGpu for Gpu {
|
|||
.clone()
|
||||
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))),
|
||||
clock_step: self.limits.clock_step.unwrap_or(100),
|
||||
memory_control_capable: false,
|
||||
memory_control: None,
|
||||
memory_step: 100,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,8 +228,10 @@ impl TGpu for Gpu {
|
|||
self.clock_limits.as_ref()
|
||||
}
|
||||
|
||||
fn slow_memory(&mut self) -> &mut bool {
|
||||
&mut self.slow_memory
|
||||
fn memory_clock(&mut self, _speed: Option<u64>) {}
|
||||
|
||||
fn get_memory_clock(&self) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
fn provider(&self) -> crate::persist::DriverJson {
|
||||
|
|
|
@ -299,7 +299,8 @@ fn bad_gpu_limits() -> crate::api::GpuLimits {
|
|||
clock_min_limits: None,
|
||||
clock_max_limits: None,
|
||||
clock_step: 100,
|
||||
memory_control_capable: false,
|
||||
memory_control: None,
|
||||
memory_step: 400,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,8 +334,12 @@ impl TGpu for Gpu {
|
|||
self.generic.get_clock_limits()
|
||||
}
|
||||
|
||||
fn slow_memory(&mut self) -> &mut bool {
|
||||
self.generic.slow_memory()
|
||||
fn memory_clock(&mut self, speed: Option<u64>) {
|
||||
self.generic.memory_clock(speed)
|
||||
}
|
||||
|
||||
fn get_memory_clock(&self) -> Option<u64> {
|
||||
self.generic.get_memory_clock()
|
||||
}
|
||||
|
||||
fn provider(&self) -> crate::persist::DriverJson {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::convert::Into;
|
||||
|
||||
use sysfuss::{BasicEntityPath, HwMonPath, SysEntity, capability::attributes, SysEntityAttributesExt, SysAttribute};
|
||||
use sysfuss::{BasicEntityPath, HwMonPath, SysEntity, capability::attributes, SysEntityAttributes, SysEntityAttributesExt, SysAttribute};
|
||||
|
||||
use limits_core::json_v2::GenericGpuLimit;
|
||||
|
||||
|
@ -20,7 +20,7 @@ pub struct Gpu {
|
|||
pub fast_ppt: Option<u64>,
|
||||
pub slow_ppt: Option<u64>,
|
||||
pub clock_limits: Option<MinMax<u64>>,
|
||||
pub slow_memory: bool,
|
||||
pub memory_clock: Option<u64>,
|
||||
limits: GenericGpuLimit,
|
||||
state: crate::state::steam_deck::Gpu,
|
||||
sysfs_card: BasicEntityPath,
|
||||
|
@ -47,6 +47,8 @@ enum ClockType {
|
|||
|
||||
const MAX_CLOCK: u64 = 1600;
|
||||
const MIN_CLOCK: u64 = 200;
|
||||
const MAX_MEMORY_CLOCK: u64 = 800;
|
||||
const MIN_MEMORY_CLOCK: u64 = 400;
|
||||
const MAX_FAST_PPT: u64 = 30_000_000;
|
||||
const MIN_FAST_PPT: u64 = 1_000_000;
|
||||
const MAX_SLOW_PPT: u64 = 29_000_000;
|
||||
|
@ -108,6 +110,63 @@ impl Gpu {
|
|||
})
|
||||
}
|
||||
|
||||
fn is_memory_clock_maxed(&self) -> bool {
|
||||
if let Some(clock) = &self.memory_clock {
|
||||
if let Some(limit) = &self.limits.memory_clock {
|
||||
if let Some(limit) = &limit.max {
|
||||
if let Some(step) = &self.limits.memory_clock_step {
|
||||
log::debug!("chosen_clock: {}, limit_clock: {}, step: {}", clock, limit, step);
|
||||
return clock > &(limit - step);
|
||||
} else {
|
||||
log::debug!("chosen_clock: {}, limit_clock: {}", clock, limit);
|
||||
return clock == limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn quantize_memory_clock(&self, clock: u64) -> u64 {
|
||||
if let Ok(f) = self.sysfs_card.read_value(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned()) {
|
||||
let options = parse_pp_dpm_fclk(&String::from_utf8_lossy(&f));
|
||||
// round (and find) nearest valid clock step
|
||||
// roughly price is right strategy (clock step will always be lower or equal to chosen)
|
||||
for i in 0..options.len() {
|
||||
let (current_val_opt, current_speed_opt) = &options[i];
|
||||
let current_speed_opt = *current_speed_opt as u64;
|
||||
if clock == current_speed_opt {
|
||||
return *current_val_opt as _;
|
||||
} else if current_speed_opt > clock {
|
||||
if i == 0 {
|
||||
return *current_val_opt as _;
|
||||
} else {
|
||||
return options[i-1].0 as _;
|
||||
}
|
||||
}
|
||||
}
|
||||
options[options.len() - 1].0 as _
|
||||
} else {
|
||||
self.is_memory_clock_maxed() as u64
|
||||
}
|
||||
}
|
||||
|
||||
fn build_memory_clock_payload(&self, clock: u64) -> String {
|
||||
let max_val = self.quantize_memory_clock(clock);
|
||||
match max_val {
|
||||
0 => "0\n".to_owned(),
|
||||
max_val => {
|
||||
use std::fmt::Write;
|
||||
let mut payload = String::from("0");
|
||||
for i in 1..max_val {
|
||||
write!(payload, " {}", i).expect("Failed to write to memory payload (should be infallible!?)");
|
||||
}
|
||||
write!(payload, " {}\n", max_val).expect("Failed to write to memory payload (should be infallible!?)");
|
||||
payload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_clocks(&mut self) -> Result<(), Vec<SettingError>> {
|
||||
let mut errors = Vec::new();
|
||||
if let Some(clock_limits) = &self.clock_limits {
|
||||
|
@ -130,7 +189,7 @@ impl Gpu {
|
|||
|| POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual()
|
||||
{
|
||||
self.state.clock_limits_set = false;
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.slow_memory);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(!self.is_memory_clock_maxed());
|
||||
if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.enforce_level(&self.sysfs_card)?;
|
||||
// disable manual clock limits
|
||||
|
@ -155,47 +214,36 @@ impl Gpu {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_slow_memory(&self, slow: bool) -> Result<(), SettingError> {
|
||||
fn set_memory_speed(&self, clock: u64) -> Result<(), SettingError> {
|
||||
let path = GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.path(&self.sysfs_card);
|
||||
if slow {
|
||||
self.sysfs_card.set(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned(), slow as u8).map_err(|e| {
|
||||
let payload = self.build_memory_clock_payload(clock);
|
||||
log::debug!("Generated payload for gpu fclk (memory): `{}` (is maxed? {})", payload, self.is_memory_clock_maxed());
|
||||
self.sysfs_card.set(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned(), payload).map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", path.display(), e),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// NOTE: there is a GPU driver/hardware bug that prevents this from working
|
||||
self.sysfs_card.set(GPU_MEMORY_DOWNCLOCK_ATTRIBUTE.to_owned(), "0 1\n").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", path.display(), e),
|
||||
setting: crate::settings::SettingVariant::Gpu,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn set_force_performance_related(&mut self) -> Result<(), Vec<SettingError>> {
|
||||
let mut errors = Vec::new();
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(!self.is_memory_clock_maxed() || self.clock_limits.is_some());
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
|
||||
.enforce_level(&self.sysfs_card)
|
||||
.unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
// enable/disable downclock of GPU memory (to 400Mhz?)
|
||||
if self.slow_memory {
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(true);
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
|
||||
.enforce_level(&self.sysfs_card)
|
||||
.unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
self.set_slow_memory(self.slow_memory).unwrap_or_else(|e| errors.push(e));
|
||||
} else if POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.needs_manual() {
|
||||
self.set_slow_memory(self.slow_memory).unwrap_or_else(|e| errors.push(e));
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT.set_gpu(self.clock_limits.is_some());
|
||||
POWER_DPM_FORCE_PERFORMANCE_LEVEL_MGMT
|
||||
.enforce_level(&self.sysfs_card)
|
||||
.unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
}
|
||||
self.set_memory_speed(
|
||||
self.memory_clock
|
||||
.or_else(|| self.limits.memory_clock
|
||||
.map(|lim| lim.max.unwrap_or(MAX_MEMORY_CLOCK))
|
||||
).unwrap_or(MAX_MEMORY_CLOCK)
|
||||
).unwrap_or_else(|e| errors.push(e));
|
||||
self.set_clocks()
|
||||
.unwrap_or_else(|mut e| errors.append(&mut e));
|
||||
// commit changes (if no errors have already occured)
|
||||
if errors.is_empty() {
|
||||
if self.slow_memory || self.clock_limits.is_some() {
|
||||
if !self.is_memory_clock_maxed() || self.clock_limits.is_some() {
|
||||
self.set_confirm().map_err(|e| {
|
||||
errors.push(e);
|
||||
errors
|
||||
|
@ -294,6 +342,9 @@ impl Gpu {
|
|||
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)));
|
||||
}
|
||||
}
|
||||
if let Some(mem_clock) = self.memory_clock {
|
||||
self.memory_clock = Some(mem_clock.clamp(self.limits.memory_clock.and_then(|lim| lim.min).unwrap_or(MIN_MEMORY_CLOCK), self.limits.memory_clock.and_then(|lim| lim.max).unwrap_or(MAX_MEMORY_CLOCK)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,7 +357,7 @@ impl Into<GpuJson> for Gpu {
|
|||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: self.clock_limits.map(|x| x.into()),
|
||||
slow_memory: self.slow_memory,
|
||||
memory_clock: self.memory_clock,
|
||||
root: self.sysfs_card.root().or(self.sysfs_hwmon.root()).and_then(|p| p.as_ref().to_str().map(|r| r.to_owned()))
|
||||
}
|
||||
}
|
||||
|
@ -319,7 +370,7 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
|
|||
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,
|
||||
memory_clock: persistent.memory_clock,
|
||||
limits: limits,
|
||||
state: crate::state::steam_deck::Gpu::default(),
|
||||
sysfs_card: Self::find_card_sysfs(persistent.root.clone()),
|
||||
|
@ -329,7 +380,7 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
|
|||
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,
|
||||
memory_clock: persistent.memory_clock,
|
||||
limits: limits,
|
||||
state: crate::state::steam_deck::Gpu::default(),
|
||||
sysfs_card: Self::find_card_sysfs(persistent.root.clone()),
|
||||
|
@ -343,7 +394,7 @@ impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
|
|||
fast_ppt: None,
|
||||
slow_ppt: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
memory_clock: None,
|
||||
limits: limits,
|
||||
state: crate::state::steam_deck::Gpu::default(),
|
||||
sysfs_card: Self::find_card_sysfs(None::<&'static str>),
|
||||
|
@ -393,7 +444,11 @@ impl TGpu for Gpu {
|
|||
max: super::util::range_max_or_fallback(&self.limits.clock_max, MAX_CLOCK),
|
||||
}),
|
||||
clock_step: self.limits.clock_step.unwrap_or(100),
|
||||
memory_control_capable: true,
|
||||
memory_control: Some(RangeLimit {
|
||||
min: super::util::range_min_or_fallback(&self.limits.memory_clock, MIN_MEMORY_CLOCK),
|
||||
max: super::util::range_max_or_fallback(&self.limits.memory_clock, MAX_MEMORY_CLOCK),
|
||||
}),
|
||||
memory_step: self.limits.memory_clock_step.unwrap_or(400),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,11 +476,35 @@ impl TGpu for Gpu {
|
|||
self.clock_limits.as_ref()
|
||||
}
|
||||
|
||||
fn slow_memory(&mut self) -> &mut bool {
|
||||
&mut self.slow_memory
|
||||
fn memory_clock(&mut self, speed: Option<u64>) {
|
||||
self.memory_clock = speed;
|
||||
}
|
||||
|
||||
fn get_memory_clock(&self) -> Option<u64> {
|
||||
self.memory_clock
|
||||
}
|
||||
|
||||
fn provider(&self) -> crate::persist::DriverJson {
|
||||
crate::persist::DriverJson::SteamDeck
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pp_dpm_fclk(s: &str) -> Vec<(usize, usize)> { // (value, MHz)
|
||||
let mut result = Vec::new();
|
||||
for line in s.split('\n') {
|
||||
if !line.is_empty() {
|
||||
if let Some((val, freq_mess)) = line.split_once(':') {
|
||||
if let Ok(val) = val.parse::<usize>() {
|
||||
if let Some((freq, _unit)) = freq_mess.trim().split_once(|c: char| !c.is_digit(10)) {
|
||||
if let Ok(freq) = freq.parse::<usize>() {
|
||||
result.push((val, freq));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ impl PDFPLManager {
|
|||
if let Ok(mode_now) =
|
||||
entity.attribute::<String, _>(DPM_FORCE_LIMITS_ATTRIBUTE.to_owned())
|
||||
{
|
||||
log::debug!("Mode for `{}` is now `{}`", path.display(), mode_now);
|
||||
log::debug!("Mode for `{}` is now `{}` ({:#b})", path.display(), mode_now, self.get());
|
||||
} else {
|
||||
log::debug!("Error getting new mode for debugging purposes");
|
||||
}
|
||||
|
|
|
@ -59,7 +59,9 @@ pub trait TGpu: OnSet + OnResume + OnPowerEvent + Debug + Send {
|
|||
|
||||
fn get_clock_limits(&self) -> Option<&MinMax<u64>>;
|
||||
|
||||
fn slow_memory(&mut self) -> &mut bool;
|
||||
fn memory_clock(&mut self, speed: Option<u64>);
|
||||
|
||||
fn get_memory_clock(&self) -> Option<u64>;
|
||||
|
||||
fn provider(&self) -> crate::persist::DriverJson {
|
||||
crate::persist::DriverJson::AutoDetect
|
||||
|
|
|
@ -8,13 +8,11 @@ use crate::settings::{TGpu, ProviderBuilder};
|
|||
use crate::settings::{OnResume, OnSet, SettingError};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Gpu {
|
||||
slow_memory: bool, // ignored
|
||||
}
|
||||
pub struct Gpu {}
|
||||
|
||||
impl Gpu {
|
||||
pub fn system_default() -> Self {
|
||||
Self { slow_memory: false }
|
||||
Self { }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +35,7 @@ impl Into<GpuJson> for Gpu {
|
|||
tdp: None,
|
||||
tdp_boost: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
memory_clock: None,
|
||||
root: None,
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +67,8 @@ impl TGpu for Gpu {
|
|||
clock_min_limits: None,
|
||||
clock_max_limits: None,
|
||||
clock_step: 100,
|
||||
memory_control_capable: false,
|
||||
memory_control: None,
|
||||
memory_step: 400,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,8 +88,10 @@ impl TGpu for Gpu {
|
|||
None
|
||||
}
|
||||
|
||||
fn slow_memory(&mut self) -> &mut bool {
|
||||
&mut self.slow_memory
|
||||
fn memory_clock(&mut self, _speed: Option<u64>) {}
|
||||
|
||||
fn get_memory_clock(&self) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
fn provider(&self) -> crate::persist::DriverJson {
|
||||
|
|
|
@ -90,7 +90,8 @@ export type GpuLimits = {
|
|||
clock_min_limits: RangeLimit | null;
|
||||
clock_max_limits: RangeLimit | null;
|
||||
clock_step: number;
|
||||
memory_control_capable: boolean;
|
||||
memory_control: RangeLimit | null,
|
||||
memory_step: number,
|
||||
};
|
||||
|
||||
// API
|
||||
|
@ -229,14 +230,18 @@ export async function unsetGpuClockLimits(): Promise<any[]> {
|
|||
return (await call_backend("GPU_unset_clock_limits", []));
|
||||
}
|
||||
|
||||
export async function setGpuSlowMemory(val: boolean): Promise<boolean> {
|
||||
return (await call_backend("GPU_set_slow_memory", [val]))[0];
|
||||
export async function setGpuSlowMemory(clock: number): Promise<number> {
|
||||
return (await call_backend("GPU_set_slow_memory", [clock]))[0];
|
||||
}
|
||||
|
||||
export async function getGpuSlowMemory(): Promise<boolean> {
|
||||
export async function getGpuSlowMemory(): Promise<number> {
|
||||
return (await call_backend("GPU_get_slow_memory", []))[0];
|
||||
}
|
||||
|
||||
export async function unsetGpuSlowMemory(): Promise<any[]> {
|
||||
return (await call_backend("GPU_unset_slow_memory", []));
|
||||
}
|
||||
|
||||
// general
|
||||
|
||||
export async function setGeneralPersistent(val: boolean): Promise<boolean> {
|
||||
|
|
|
@ -180,16 +180,42 @@ export class Gpu extends Component<backend.IdcProps> {
|
|||
}}
|
||||
/>}
|
||||
</PanelSectionRow>
|
||||
{(get_value(LIMITS_INFO) as backend.SettingsLimits).gpu.memory_control_capable && <PanelSectionRow>
|
||||
{((get_value(LIMITS_INFO) as backend.SettingsLimits).gpu.memory_control) && <PanelSectionRow>
|
||||
<ToggleField
|
||||
checked={get_value(SLOW_MEMORY_GPU)}
|
||||
checked={get_value(SLOW_MEMORY_GPU) != null}
|
||||
label={tr("Downclock Memory")}
|
||||
description={tr("Force RAM into low-power mode")}
|
||||
onChange={(value: boolean) => {
|
||||
backend.resolve(backend.setGpuSlowMemory(value), (val: boolean) => {
|
||||
if (value) {
|
||||
set_value(SLOW_MEMORY_GPU, (get_value(LIMITS_INFO) as backend.SettingsLimits).gpu.memory_control!.max);
|
||||
reloadGUI("GPUMemFreqToggle");
|
||||
} else {
|
||||
set_value(SLOW_MEMORY_GPU, null);
|
||||
backend.resolve(backend.unsetGpuSlowMemory(), (_: any[]) => {
|
||||
reloadGUI("GPUUnsetMemFreq");
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</PanelSectionRow>}
|
||||
{get_value(SLOW_MEMORY_GPU) != null && <PanelSectionRow>
|
||||
<SliderField
|
||||
label={tr("Maximum (MHz)")}
|
||||
value={get_value(SLOW_MEMORY_GPU)}
|
||||
max={(get_value(LIMITS_INFO) as backend.SettingsLimits).gpu.memory_control!.max}
|
||||
min={(get_value(LIMITS_INFO) as backend.SettingsLimits).gpu.memory_control!.min}
|
||||
step={(get_value(LIMITS_INFO) as backend.SettingsLimits).gpu.memory_step}
|
||||
showValue={true}
|
||||
disabled={get_value(SLOW_MEMORY_GPU) == null}
|
||||
onChange={(val: number) => {
|
||||
backend.log(backend.LogLevel.Debug, "GPU memory clock Max is now " + val.toString());
|
||||
backend.resolve(
|
||||
backend.setGpuSlowMemory(val),
|
||||
(val: number) => {
|
||||
set_value(SLOW_MEMORY_GPU, val);
|
||||
reloadGUI("GPUSlowMemory");
|
||||
})
|
||||
reloadGUI("GPUSetMemFreq");
|
||||
}
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</PanelSectionRow>}
|
||||
|
|
|
@ -170,7 +170,7 @@ const reload = function() {
|
|||
set_value(CLOCK_MIN_GPU, limits[0]);
|
||||
set_value(CLOCK_MAX_GPU, limits[1]);
|
||||
});
|
||||
backend.resolve(backend.getGpuSlowMemory(), (status: boolean) => { set_value(SLOW_MEMORY_GPU, status) });
|
||||
backend.resolve(backend.getGpuSlowMemory(), (status: number) => { set_value(SLOW_MEMORY_GPU, status) });
|
||||
|
||||
backend.resolve(backend.getGeneralPersistent(), (value: boolean) => { set_value(PERSISTENT_GEN, value) });
|
||||
backend.resolve(backend.getGeneralSettingsName(), (name: string) => { set_value(NAME_GEN, name) });
|
||||
|
|
Loading…
Reference in a new issue