Improve generic support, add Framework 13 AMD support for test platform (ryzenadj v0.14 update not included)

This commit is contained in:
NGnius (Graham) 2023-12-10 23:15:31 -05:00
parent 8f219a3255
commit a2d5103f12
7 changed files with 483 additions and 74 deletions

View file

@ -90,9 +90,10 @@ impl Default for Base {
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),
fast_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(25_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(25_000) }),
ppt_step: Some(1_000),
ppt_divisor: Some(1_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),
@ -131,9 +132,10 @@ impl Default for Base {
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),
fast_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(25_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(25_000) }),
ppt_step: Some(1_000),
ppt_divisor: Some(1_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),
@ -172,9 +174,10 @@ impl Default for Base {
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),
fast_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(28_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(28_000) }),
ppt_step: Some(1_000),
ppt_divisor: Some(1_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),
@ -213,9 +216,10 @@ impl Default for Base {
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),
fast_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(28_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(28_000) }),
ppt_step: Some(1_000),
ppt_divisor: Some(1_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),
@ -228,6 +232,48 @@ impl Default for Base {
}
}
},
super::Config {
name: "AMD R7 7840U".to_owned(),
conditions: super::Conditions {
dmi: None,
cpuinfo: Some("model name\\s+: AMD Ryzen 7 7840U( w\\/ Radeon 780M Graphics)?\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(400), max: Some(5100) }),
clock_max: Some(super::RangeLimit { min: Some(400), max: Some(5100) }),
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), max: Some(53_000) }),
slow_ppt: Some(super::RangeLimit { min: Some(1_000), max: Some(43_000) }),
ppt_step: Some(1_000),
ppt_divisor: Some(1_000),
clock_min: None,
clock_max: None,
clock_step: None,
..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 {

View file

@ -11,7 +11,7 @@
},
"limits": {
"cpu": {
"provider": "SteamDeckAdvance",
"provider": "GabeBoyAdvance",
"limits": {
"cpus": [
{
@ -115,7 +115,7 @@
}
},
"gpu": {
"provider": "SteamDeckAdvance",
"provider": "GabeBoyAdvance",
"limits": {
"fast_ppt": {
"min": 1000000,
@ -145,7 +145,7 @@
}
},
"battery": {
"provider": "SteamDeckAdvance",
"provider": "GabeBoyAdvance",
"limits": {
"charge_rate": {
"min": 250,
@ -176,7 +176,7 @@
},
"limits": {
"cpu": {
"provider": "SteamDeck",
"provider": "GabeBoy",
"limits": {
"cpus": [
{
@ -280,7 +280,7 @@
}
},
"gpu": {
"provider": "SteamDeck",
"provider": "GabeBoy",
"limits": {
"fast_ppt": {
"min": 1000000,
@ -310,7 +310,7 @@
}
},
"battery": {
"provider": "SteamDeck",
"provider": "GabeBoy",
"limits": {
"charge_rate": {
"min": 250,
@ -400,17 +400,17 @@
"provider": "GenericAMD",
"limits": {
"fast_ppt": {
"min": 1000000,
"max": 25000000
"min": 1000,
"max": 25000
},
"fast_ppt_default": null,
"slow_ppt": {
"min": 1000000,
"max": 25000000
"min": 1000,
"max": 25000
},
"slow_ppt_default": null,
"ppt_divisor": null,
"ppt_step": 1000000,
"ppt_divisor": 1000,
"ppt_step": 1000,
"tdp": null,
"tdp_boost": null,
"tdp_step": null,
@ -603,17 +603,17 @@
"provider": "GenericAMD",
"limits": {
"fast_ppt": {
"min": 1000000,
"max": 25000000
"min": 1000,
"max": 25000
},
"fast_ppt_default": null,
"slow_ppt": {
"min": 1000000,
"max": 25000000
"min": 1000,
"max": 25000
},
"slow_ppt_default": null,
"ppt_divisor": null,
"ppt_step": 1000000,
"ppt_divisor": 1000,
"ppt_step": 1000,
"tdp": null,
"tdp_boost": null,
"tdp_step": null,
@ -854,17 +854,17 @@
"provider": "GenericAMD",
"limits": {
"fast_ppt": {
"min": 1000000,
"max": 28000000
"min": 1000,
"max": 28000
},
"fast_ppt_default": null,
"slow_ppt": {
"min": 1000000,
"max": 28000000
"min": 1000,
"max": 28000
},
"slow_ppt_default": null,
"ppt_divisor": null,
"ppt_step": 1000000,
"ppt_divisor": 1000,
"ppt_step": 1000,
"tdp": null,
"tdp_boost": null,
"tdp_step": null,
@ -1105,17 +1105,17 @@
"provider": "GenericAMD",
"limits": {
"fast_ppt": {
"min": 1000000,
"max": 28000000
"min": 1000,
"max": 28000
},
"fast_ppt_default": null,
"slow_ppt": {
"min": 1000000,
"max": 28000000
"min": 1000,
"max": 28000
},
"slow_ppt_default": null,
"ppt_divisor": null,
"ppt_step": 1000000,
"ppt_divisor": 1000,
"ppt_step": 1000,
"tdp": null,
"tdp_boost": null,
"tdp_step": null,
@ -1142,6 +1142,251 @@
}
}
},
{
"name": "AMD R7 7840U",
"conditions": {
"dmi": null,
"cpuinfo": "model name\\s+: AMD Ryzen 7 7840U( w\\/ Radeon 780M Graphics)?\n",
"os": null,
"command": null,
"file_exists": null
},
"limits": {
"cpu": {
"provider": "GenericAMD",
"limits": {
"cpus": [
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
},
{
"clock_min": {
"min": 400,
"max": 5100
},
"clock_max": {
"min": 400,
"max": 5100
},
"clock_step": 100,
"skip_resume_reclock": false
}
],
"global_governors": true
}
},
"gpu": {
"provider": "GenericAMD",
"limits": {
"fast_ppt": {
"min": 1000,
"max": 53000
},
"fast_ppt_default": null,
"slow_ppt": {
"min": 1000,
"max": 43000
},
"slow_ppt_default": null,
"ppt_divisor": 1000,
"ppt_step": 1000,
"tdp": null,
"tdp_boost": null,
"tdp_step": null,
"clock_min": null,
"clock_max": null,
"clock_step": null,
"skip_resume_reclock": false
}
},
"battery": {
"provider": "Generic",
"limits": {
"charge_rate": null,
"charge_modes": [],
"charge_limit": null,
"extra_readouts": false
}
}
}
},
{
"name": "Fallback",
"conditions": {

View file

@ -25,6 +25,7 @@ fn main() -> Result<(), ()> {
.join(PACKAGE_NAME.to_owned() + ".log");
#[cfg(not(debug_assertions))]
let log_filepath = std::path::Path::new("/tmp").join(format!("{}.log", PACKAGE_NAME));
println!("Logging to: {:?}", log_filepath);
#[cfg(debug_assertions)]
let old_log_filepath = usdpl_back::api::dirs::home()
.unwrap_or_else(|| "/tmp/".into())
@ -46,12 +47,11 @@ fn main() -> Result<(), ()> {
LevelFilter::Info
},
Default::default(),
std::fs::File::create(&log_filepath).unwrap(),
std::fs::File::create(&log_filepath).expect("Failed to create log file"),
//std::fs::File::create("/home/deck/powertools-rs.log").unwrap(),
)
.unwrap();
log::debug!("Logging to: {:?}.", log_filepath);
println!("Logging to: {:?}", log_filepath);
log::info!("Starting back-end ({} v{})", PACKAGE_NAME, PACKAGE_VERSION);
println!("Starting back-end ({} v{})", PACKAGE_NAME, PACKAGE_VERSION);
log::info!(

View file

@ -1,7 +1,7 @@
use std::convert::Into;
use limits_core::json_v2::GenericBatteryLimit;
use sysfuss::SysEntity;
use sysfuss::{SysEntity, SysEntityAttributesExt};
use crate::persist::BatteryJson;
use crate::settings::{TBattery, ProviderBuilder};
@ -27,7 +27,7 @@ impl Into<BatteryJson> for Battery {
}
impl Battery {
fn read_f64<P: AsRef<std::path::Path>>(path: P) -> Result<f64, SettingError> {
/*fn read_f64<P: AsRef<std::path::Path>>(path: P) -> Result<f64, SettingError> {
let path = path.as_ref();
match usdpl_back::api::files::read_single::<_, f64, _>(path) {
Err(e) => Err(SettingError {
@ -38,13 +38,14 @@ impl Battery {
// so convert this to mA for consistency
Ok(val) => Ok(val / 1000.0),
}
}
}*/
fn find_psu_sysfs(root: Option<impl AsRef<std::path::Path>>) -> sysfuss::PowerSupplyPath {
let root = crate::settings::util::root_or_default_sysfs(root);
match root.power_supply(crate::settings::util::always_satisfied) {
Ok(mut iter) => {
iter.next()
Ok(iter) => {
iter.filter(|x| x.name().is_ok_and(|name| name.starts_with("BAT")))
.next()
.unwrap_or_else(|| {
log::error!("Failed to find generic battery power_supply in sysfs (no results), using naive fallback");
root.power_supply_by_name("BAT0")
@ -56,6 +57,28 @@ impl Battery {
}
}
}
fn get_design_voltage(&self) -> Option<f64> {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMax) {
Ok(x) => Some(x/1000000.0),
Err(e) => {
log::debug!("get_design_voltage voltage_max err: {}", e);
match sysfuss::SysEntityRawExt::attribute::<_, f64, _>(&self.sysfs, "voltage_min_design".to_owned()) { // Framework 13 AMD
Ok(x) => Some(x/1000000.0),
Err(e) => {
log::debug!("get_design_voltage voltage_min_design err: {}", e);
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::VoltageMin) {
Ok(x) => Some(x/1000000.0),
Err(e) => {
log::debug!("get_design_voltage voltage_min err: {}", e);
None
}
}
}
}
}
}
}
}
impl ProviderBuilder<BatteryJson, GenericBatteryLimit> for Battery {
@ -124,37 +147,55 @@ impl TBattery for Battery {
}
fn read_charge_full(&self) -> Option<f64> {
match Self::read_f64("/sys/class/power_supply/BAT0/energy_full") {
Ok(x) => Some(x),
Err(e) => {
log::warn!("read_charge_full err: {}", e.msg);
None
if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFull) {
Ok(x) => Some(x/1000000.0 * battery_voltage),
Err(e) => {
log::warn!("read_charge_full err: {}", e);
None
}
}
} else {
None
}
}
fn read_charge_now(&self) -> Option<f64> {
match Self::read_f64("/sys/class/power_supply/BAT0/energy_now") {
Ok(x) => Some(x),
Err(e) => {
log::warn!("read_charge_now err: {}", e.msg);
None
if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeNow) {
Ok(x) => Some(x/1000000.0 * battery_voltage),
Err(e) => {
log::warn!("read_charge_now err: {}", e);
None
}
}
} else {
None
}
}
fn read_charge_design(&self) -> Option<f64> {
match Self::read_f64("/sys/class/power_supply/BAT0/energy_design") {
Ok(x) => Some(x),
Err(e) => {
log::warn!("read_charge_design err: {}", e.msg);
None
if let Some(battery_voltage) = self.get_design_voltage() {
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeFullDesign) {
Ok(x) => Some(x/1000000.0 * battery_voltage),
Err(e) => {
log::warn!("read_charge_design err: {}", e);
None
}
}
} else {
None
}
}
fn read_current_now(&self) -> Option<f64> {
None
match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::CurrentNow) {
Ok(x) => Some(x/1000.0), // expects mA, reads uA
Err(e) => {
log::warn!("read_current_now err: {}", e);
None
}
}
}
fn read_charge_power(&self) -> Option<f64> {
@ -164,6 +205,13 @@ impl TBattery for Battery {
fn charge_limit(&mut self, _limit: Option<f64>) {}
fn get_charge_limit(&self) -> Option<f64> {
/*match self.sysfs.attribute::<f64, _>(sysfuss::PowerSupplyAttribute::ChargeControlLimit) {
Ok(x) => Some(x/1000.0),
Err(e) => {
log::warn!("read_charge_design err: {}", e);
None
}
}*/
None
}

View file

@ -218,6 +218,13 @@ pub struct Cpu {
}
}*/
impl Cpu {
#[inline]
fn current_governor(index: usize) -> String {
usdpl_back::api::files::read_single(cpu_governor_path(index)).unwrap_or_else(|_| "schedutil".to_owned())
}
}
impl AsRef<Cpu> for Cpu {
#[inline]
fn as_ref(&self) -> &Cpu {
@ -237,7 +244,7 @@ impl FromGenericCpuInfo for Cpu {
fn from_limits(cpu_index: usize, limits: GenericCpuLimit) -> Self {
Self {
online: true,
governor: "schedutil".to_owned(),
governor: Self::current_governor(cpu_index),
clock_limits: None,
limits,
index: cpu_index,

View file

@ -15,7 +15,7 @@ pub struct Gpu {
pub fast_ppt: Option<u64>,
pub slow_ppt: Option<u64>,
pub clock_limits: Option<MinMax<u64>>,
limits: GenericGpuLimit,
pub limits: GenericGpuLimit,
sysfs: BasicEntityPath,
}
@ -122,13 +122,23 @@ impl TGpu for Gpu {
.limits
.fast_ppt
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15)))
.map(|mut x| if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {x}),
slow_ppt_limits: self
.limits
.slow_ppt
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
ppt_step: self.limits.ppt_step.unwrap_or(1_000_000),
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15)))
.map(|mut x| if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {x}),
ppt_step: self.limits.ppt_step.unwrap_or(1),
tdp_limits: self
.limits
.tdp
@ -161,7 +171,8 @@ impl TGpu for Gpu {
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
if let Some(fast_lims) = &self.limits.fast_ppt {
self.fast_ppt = fast.map(|x| {
self.fast_ppt = fast.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x * ppt_divisor } else { x })
.map(|x| {
x.clamp(
fast_lims.min.unwrap_or(0),
fast_lims.max.unwrap_or(u64::MAX),
@ -169,7 +180,8 @@ impl TGpu for Gpu {
});
}
if let Some(slow_lims) = &self.limits.slow_ppt {
self.slow_ppt = slow.map(|x| {
self.slow_ppt = slow.map(|x| if let Some(ppt_divisor) = self.limits.ppt_divisor { x * ppt_divisor } else { x })
.map(|x| {
x.clamp(
slow_lims.min.unwrap_or(0),
slow_lims.max.unwrap_or(u64::MAX),

View file

@ -7,9 +7,40 @@ use crate::settings::MinMax;
use crate::settings::{TGpu, ProviderBuilder};
use crate::settings::{OnResume, OnSet, SettingError, SettingVariant};
fn msg_or_err<D: std::fmt::Display, E: std::fmt::Display>(output: &mut String, msg: &str, result: Result<D, E>) {
use std::fmt::Write;
match result {
Ok(val) => writeln!(output, "{}: {}", msg, val).unwrap(),
Err(e) => writeln!(output, "{} failed: {}", msg, e).unwrap(),
}
}
fn log_capabilities(ryzenadj: &RyzenAdj) {
log::info!("RyzenAdj v{}.{}.{}", libryzenadj::libryzenadj_sys::RYZENADJ_REVISION_VER, libryzenadj::libryzenadj_sys::RYZENADJ_MAJOR_VER, libryzenadj::libryzenadj_sys::RYZENADJ_MINIOR_VER);
if let Some(x) = ryzenadj.get_init_table_err() {
log::warn!("RyzenAdj table init error: {}", x);
}
let mut log_msg = String::new();
msg_or_err(&mut log_msg, "bios version", ryzenadj.get_bios_if_ver());
msg_or_err(&mut log_msg, "refresh", ryzenadj.refresh().map(|_| "success"));
msg_or_err(&mut log_msg, "CPU family", ryzenadj.get_cpu_family().map(|fam| {
let fam_dbg = format!("{:?}", fam);
format!("{} (#{})", fam_dbg, fam as i32)
}));
msg_or_err(&mut log_msg, "get_fast_value (PPT)", ryzenadj.get_fast_value());
msg_or_err(&mut log_msg, "get_slow_value (PPT)", ryzenadj.get_slow_value());
msg_or_err(&mut log_msg, "get_gfx_clk", ryzenadj.get_gfx_clk());
msg_or_err(&mut log_msg, "get_gfx_volt", ryzenadj.get_gfx_volt());
log::info!("RyzenAdj GPU info:\n{}", log_msg);
}
fn ryzen_adj_or_log() -> Option<Mutex<RyzenAdj>> {
match RyzenAdj::new() {
Ok(x) => Some(Mutex::new(x)),
Ok(x) => {
log_capabilities(&x);
Some(Mutex::new(x))
},
Err(e) => {
log::error!("RyzenAdj init error: {}", e);
None
@ -256,9 +287,29 @@ impl OnSet for Gpu {
impl crate::settings::OnPowerEvent for Gpu {}
fn bad_gpu_limits() -> crate::api::GpuLimits {
crate::api::GpuLimits {
fast_ppt_limits: None,
slow_ppt_limits: None,
ppt_step: 1,
tdp_limits: None,
tdp_boost_limits: None,
tdp_step: 1,
clock_min_limits: None,
clock_max_limits: None,
clock_step: 100,
memory_control_capable: false,
}
}
impl TGpu for Gpu {
fn limits(&self) -> crate::api::GpuLimits {
self.generic.limits()
if self.implementor.is_some() {
// NOTE: since set functions may succeed when gets do not, there is no good way to (automatically) check whether things are working
self.generic.limits()
} else {
bad_gpu_limits()
}
}
fn json(&self) -> crate::persist::GpuJson {