mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-17 16:34:54 -05:00
feat: support nvidia voltage boost (#1133)
* feat: implement voltage boost for nvidia * make NvApiVoltageBoost private * fix typo * cleanups * switch from tooltip to popover
This commit is contained in:
@@ -188,6 +188,8 @@ gpus:
|
||||
max_voltage: 1200
|
||||
# Voltage offset value in mV for RDNA and newer AMD GPUs.
|
||||
voltage_offset: 0
|
||||
# Nvidia core voltage boost, in percent (0-100) of available boost, not total voltage
|
||||
voltage_boost: 0
|
||||
|
||||
# GPU V/F curve with voltage and frequency points per each power state.
|
||||
# Applicable only to AMD GCN and RDNA1 GPUs. Overrides the values of min/max clock/voltage fields.
|
||||
|
||||
@@ -13,7 +13,7 @@ use amdgpu_sysfs::{
|
||||
gpu_handle::{PowerLevelId, fan_control::FanInfo, power_profile_mode::PowerProfileModesTable},
|
||||
hw_mon::Temperature,
|
||||
};
|
||||
use anyhow::{Context, anyhow, bail};
|
||||
use anyhow::{Context, anyhow, bail, ensure};
|
||||
use driver::DriverHandle;
|
||||
use futures::{FutureExt, future::LocalBoxFuture};
|
||||
use indexmap::IndexMap;
|
||||
@@ -21,8 +21,8 @@ use lact_schema::{
|
||||
ActivePowerStates, CacheInfo, ClocksInfo, ClocksTable, ClockspeedStats, DeviceApiInfo,
|
||||
DeviceFlag, DeviceInfo, DeviceStats, DeviceType, DrmInfo, DrmMemoryInfo, FanControlMode,
|
||||
FanStats, IntelDrmInfo, LinkInfo, NvidiaClockOffset, NvidiaClocksTable, NvidiaThermalInfo,
|
||||
NvidiaVfPoint, PmfwInfo, PowerState, PowerStates, PowerStats, ProcessInfo, ProcessList,
|
||||
ProcessType, ProcessUtilizationType, TemperatureEntry, VoltageStats, VramStats,
|
||||
NvidiaVfPoint, NvidiaVoltageBoost, PmfwInfo, PowerState, PowerStates, PowerStats, ProcessInfo,
|
||||
ProcessList, ProcessType, ProcessUtilizationType, TemperatureEntry, VoltageStats, VramStats,
|
||||
config::{CurvePoint, FanControlSettings, FanCurve, GpuConfig},
|
||||
};
|
||||
use nvapi::NvApi;
|
||||
@@ -68,6 +68,7 @@ pub struct NvidiaGpuController {
|
||||
last_applied_vram_locked_clocks: RefCell<Option<(u32, u32)>>,
|
||||
// Check if reset is needed to avoid unnecessarily going to nvapi
|
||||
vf_curve_written: Cell<bool>,
|
||||
voltage_boost_written: Cell<bool>,
|
||||
// Used as the initial value on cards which do not report base VF points themselves (Turing)
|
||||
base_vf_curve: RefCell<Option<Vec<NvidiaVfPoint>>>,
|
||||
}
|
||||
@@ -144,6 +145,7 @@ impl NvidiaGpuController {
|
||||
last_applied_gpu_locked_clocks: RefCell::new(None),
|
||||
last_applied_vram_locked_clocks: RefCell::new(None),
|
||||
vf_curve_written: Cell::new(false),
|
||||
voltage_boost_written: Cell::new(false),
|
||||
base_vf_curve: RefCell::new(None),
|
||||
})
|
||||
}
|
||||
@@ -1087,6 +1089,17 @@ impl GpuController for NvidiaGpuController {
|
||||
.inspect_err(|err| warn!("could not get VF curve: {err:#}"))
|
||||
.unwrap_or_default();
|
||||
|
||||
let voltage_boost = self.nvapi.as_ref().and_then(|(nvapi, handle)| {
|
||||
unsafe { nvapi.get_voltage_boost(*handle) }
|
||||
.inspect_err(|err| warn!("could not get voltage boost: {err:#}"))
|
||||
.ok()
|
||||
.map(|current| NvidiaVoltageBoost {
|
||||
current: current.into(),
|
||||
min: 0,
|
||||
max: 100,
|
||||
})
|
||||
});
|
||||
|
||||
let table = NvidiaClocksTable {
|
||||
gpu_offsets,
|
||||
mem_offsets,
|
||||
@@ -1095,6 +1108,7 @@ impl GpuController for NvidiaGpuController {
|
||||
gpu_clock_range,
|
||||
vram_clock_range,
|
||||
gpu_vf_curve,
|
||||
voltage_boost,
|
||||
};
|
||||
|
||||
Ok(ClocksInfo {
|
||||
@@ -1198,6 +1212,27 @@ impl GpuController for NvidiaGpuController {
|
||||
.context("Could not apply VF curve")?;
|
||||
}
|
||||
|
||||
if let Some(percent) = clocks.voltage_boost {
|
||||
let (nvapi, handle) = self.nvapi.as_ref().context("NvAPI not available")?;
|
||||
|
||||
// The driver field is a single byte, out of range values would be truncated instead of rejected
|
||||
let percent =
|
||||
u8::try_from(percent.clamp(0, 100)).expect("Clamped value fits into u8");
|
||||
debug!("applying voltage boost {percent}%");
|
||||
|
||||
unsafe { nvapi.set_voltage_boost(*handle, percent) }
|
||||
.context("Could not apply voltage boost")?;
|
||||
self.voltage_boost_written.set(true);
|
||||
|
||||
// verify the boost was applied
|
||||
let applied = unsafe { nvapi.get_voltage_boost(*handle) }
|
||||
.context("Could not verify voltage boost")?;
|
||||
ensure!(
|
||||
applied == percent,
|
||||
"Voltage boost was not applied: requested {percent}%, driver reports {applied}%"
|
||||
);
|
||||
}
|
||||
|
||||
if config.fan_control_enabled {
|
||||
let settings = config
|
||||
.fan_control_settings
|
||||
@@ -1317,6 +1352,13 @@ impl GpuController for NvidiaGpuController {
|
||||
self.reset_vf_curve().context("Could not reset VF curve")?;
|
||||
}
|
||||
|
||||
if self.voltage_boost_written.get() {
|
||||
let (nvapi, handle) = self.nvapi.as_ref().context("NvAPI not available")?;
|
||||
unsafe { nvapi.set_voltage_boost(*handle, 0) }
|
||||
.context("Could not reset voltage boost")?;
|
||||
self.voltage_boost_written.set(false);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ const QUERY_NVAPI_GET_ERROR_MESSAGE: u32 = 0x6c2d048c;
|
||||
// Undocumented calls
|
||||
const QUERY_NVAPI_THERMALS: u32 = 0x65fe3aad;
|
||||
const QUERY_NVAPI_VOLTAGE: u32 = 0x465f9bcf;
|
||||
const QUERY_NVAPI_VOLTAGE_BOOST_GET: u32 = 0x9df23ca1;
|
||||
const QUERY_NVAPI_VOLTAGE_BOOST_SET: u32 = 0xb9306d9b;
|
||||
const QUERY_NVAPI_GPU_CLOCK_CLIENT_CLK_VF_POINTS_GET_STATUS: u32 = 0x21537ad4;
|
||||
const QUERY_NVAPI_GPU_CLOCK_CLIENT_CLK_VF_POINTS_GET_INFO: u32 = 0x507b4b59;
|
||||
const QUERY_NVAPI_GPU_CLOCK_CLIENT_CLK_VF_POINTS_SET_CONTROL: u32 = 0x733e009;
|
||||
@@ -111,18 +113,34 @@ impl NvApi {
|
||||
}
|
||||
|
||||
pub unsafe fn get_voltage(&self, handle: NvPhysicalGpuHandle) -> anyhow::Result<u32> {
|
||||
let mut data = NvApiVoltage {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
version: make_version::<NvApiVoltage>(1),
|
||||
flags: 0,
|
||||
padding_1: [0; 8],
|
||||
value_uv: 0,
|
||||
padding_2: [0; 8],
|
||||
};
|
||||
let mut data = NvApiVoltage::default();
|
||||
|
||||
self.physical_gpu_query(handle, &mut data, QUERY_NVAPI_VOLTAGE)?;
|
||||
|
||||
Ok(data.value_uv)
|
||||
Ok(data.rails[0].current_voltage_uv)
|
||||
}
|
||||
|
||||
pub unsafe fn get_voltage_boost(&self, handle: NvPhysicalGpuHandle) -> anyhow::Result<u8> {
|
||||
let mut data = NvApiVoltageBoost::default();
|
||||
|
||||
self.physical_gpu_query(handle, &mut data, QUERY_NVAPI_VOLTAGE_BOOST_GET)?;
|
||||
|
||||
Ok(data.percent)
|
||||
}
|
||||
|
||||
pub unsafe fn set_voltage_boost(
|
||||
&self,
|
||||
handle: NvPhysicalGpuHandle,
|
||||
percent: u8,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut data = NvApiVoltageBoost {
|
||||
percent,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.physical_gpu_query(handle, &mut data, QUERY_NVAPI_VOLTAGE_BOOST_SET)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn clock_client_clk_vf_points_get_info(
|
||||
@@ -488,14 +506,52 @@ impl NvApiThermals {
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the sizes used in the version fields stay correct
|
||||
const _: () = assert!(mem::size_of::<NvApiVoltage>() == 76);
|
||||
const _: () = assert!(mem::size_of::<NvApiVoltageBoost>() == 40);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
struct NvApiVoltage {
|
||||
version: u32,
|
||||
flags: u32,
|
||||
padding_1: [u32; 8],
|
||||
value_uv: u32,
|
||||
padding_2: [u32; 8],
|
||||
version: NvU32,
|
||||
rsvd: [NvU8; 32],
|
||||
rails: [NvApiVoltageRail; 1],
|
||||
}
|
||||
|
||||
impl Default for NvApiVoltage {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: make_version::<Self>(1),
|
||||
rsvd: [0; 32],
|
||||
rails: [NvApiVoltageRail::default()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default)]
|
||||
struct NvApiVoltageRail {
|
||||
rail_id: NvU32,
|
||||
current_voltage_uv: NvU32,
|
||||
rsvd: [NvU8; 32],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct NvApiVoltageBoost {
|
||||
version: NvU32,
|
||||
percent: NvU8,
|
||||
rsvd: [NvU8; 32],
|
||||
}
|
||||
|
||||
impl Default for NvApiVoltageBoost {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: make_version::<Self>(1),
|
||||
percent: 0,
|
||||
rsvd: [0; 32],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
@@ -61,6 +61,7 @@ gpus:
|
||||
3:
|
||||
clockspeed: 920
|
||||
voltage_offset: 0
|
||||
voltage_boost: 0
|
||||
power_profile_mode_index: 0
|
||||
custom_power_profile_mode_hueristics:
|
||||
- - 0
|
||||
|
||||
@@ -196,6 +196,8 @@ min-gpu-clock = Minimum GPU Clock (MHz)
|
||||
min-vram-clock = Minimum VRAM Clock (MHz)
|
||||
min-gpu-voltage = Minimum GPU Voltage (mV)
|
||||
gpu-voltage-offset = GPU voltage offset (mV)
|
||||
gpu-voltage-boost = GPU Voltage Boost (%)
|
||||
gpu-voltage-boost-tooltip = Controls how much of the additional voltage headroom defined by the driver is available. 100% means all of this headroom, not 100% of total GPU voltage. More headroom may sustain higher clockspeeds but increases power draw and heat.
|
||||
gpu-pstate-clock-offset = GPU P-State {$pstate} Clock Offset (MHz)
|
||||
vram-pstate-clock-offset = VRAM P-State {$pstate} Clock Offset (MHz)
|
||||
gpu-pstate-clock = GPU P-State {$pstate} Clock (MHz)
|
||||
|
||||
@@ -22,7 +22,8 @@ impl ClockCategory {
|
||||
| ClockspeedType::GpuClockOffset(_) => ClockCategory::CoreClock,
|
||||
ClockspeedType::MinVoltage
|
||||
| ClockspeedType::MaxVoltage
|
||||
| ClockspeedType::VoltageOffset => ClockCategory::CoreVoltage,
|
||||
| ClockspeedType::VoltageOffset
|
||||
| ClockspeedType::VoltageBoost => ClockCategory::CoreVoltage,
|
||||
ClockspeedType::MaxMemoryClock
|
||||
| ClockspeedType::MinMemoryClock
|
||||
| ClockspeedType::MemClockOffset(_) => ClockCategory::VramClock,
|
||||
|
||||
@@ -7,11 +7,11 @@ use crate::{
|
||||
};
|
||||
use gtk::{
|
||||
glib::{SignalHandlerId, object::ObjectExt},
|
||||
prelude::{AdjustmentExt, EditableExt, OrientableExt, RangeExt, ScaleExt, WidgetExt},
|
||||
prelude::{AdjustmentExt, BoxExt, EditableExt, OrientableExt, RangeExt, ScaleExt, WidgetExt},
|
||||
};
|
||||
use i18n_embed_fl::fl;
|
||||
use lact_schema::request::ClockspeedType;
|
||||
use relm4::prelude::FactoryComponent;
|
||||
use relm4::{RelmWidgetExt, prelude::FactoryComponent};
|
||||
|
||||
pub struct ClockAdjustmentRow {
|
||||
clock_type: ClockspeedType,
|
||||
@@ -28,6 +28,20 @@ pub struct ClocksData {
|
||||
pub max: i32,
|
||||
pub custom_title: Option<String>,
|
||||
pub is_secondary: bool,
|
||||
pub step: i32,
|
||||
}
|
||||
|
||||
impl Default for ClocksData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
custom_title: None,
|
||||
is_secondary: false,
|
||||
step: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClocksData {
|
||||
@@ -36,8 +50,7 @@ impl ClocksData {
|
||||
current,
|
||||
min,
|
||||
max,
|
||||
is_secondary: false,
|
||||
custom_title: None,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,31 +82,55 @@ impl FactoryComponent for ClockAdjustmentRow {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
|
||||
#[name = "title_label"]
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
#[watch]
|
||||
set_markup: &match &self.custom_title {
|
||||
Some(title) => title.clone(),
|
||||
None => {
|
||||
match self.clock_type {
|
||||
ClockspeedType::MaxCoreClock => fl!(I18N, "max-gpu-clock"),
|
||||
ClockspeedType::MaxMemoryClock => fl!(I18N, "max-vram-clock"),
|
||||
ClockspeedType::MaxVoltage => fl!(I18N, "max-gpu-voltage"),
|
||||
ClockspeedType::MinCoreClock => fl!(I18N, "min-gpu-clock"),
|
||||
ClockspeedType::MinMemoryClock => fl!(I18N, "min-vram-clock"),
|
||||
ClockspeedType::MinVoltage => fl!(I18N, "min-gpu-voltage"),
|
||||
ClockspeedType::VoltageOffset => fl!(I18N, "gpu-voltage-offset"),
|
||||
ClockspeedType::GpuClockOffset(pstate) => fl!(I18N, "gpu-pstate-clock-offset", pstate = pstate),
|
||||
ClockspeedType::MemClockOffset(pstate) => fl!(I18N, "vram-pstate-clock-offset", pstate = pstate),
|
||||
ClockspeedType::GpuVfCurveClock(pstate) => fl!(I18N, "gpu-pstate-clock", pstate = pstate),
|
||||
ClockspeedType::MemVfCurveClock(pstate) => fl!(I18N, "mem-pstate-clock", pstate = pstate),
|
||||
ClockspeedType::GpuVfCurveVoltage(pstate) => fl!(I18N, "gpu-pstate-clock-voltage", pstate = pstate),
|
||||
ClockspeedType::MemVfCurveVoltage(pstate) => fl!(I18N, "mem-pstate-clock-voltage", pstate = pstate),
|
||||
ClockspeedType::Reset => unreachable!(),
|
||||
#[name = "title_box"]
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 5,
|
||||
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
#[watch]
|
||||
set_markup: &match &self.custom_title {
|
||||
Some(title) => title.clone(),
|
||||
None => {
|
||||
match self.clock_type {
|
||||
ClockspeedType::MaxCoreClock => fl!(I18N, "max-gpu-clock"),
|
||||
ClockspeedType::MaxMemoryClock => fl!(I18N, "max-vram-clock"),
|
||||
ClockspeedType::MaxVoltage => fl!(I18N, "max-gpu-voltage"),
|
||||
ClockspeedType::MinCoreClock => fl!(I18N, "min-gpu-clock"),
|
||||
ClockspeedType::MinMemoryClock => fl!(I18N, "min-vram-clock"),
|
||||
ClockspeedType::MinVoltage => fl!(I18N, "min-gpu-voltage"),
|
||||
ClockspeedType::VoltageOffset => fl!(I18N, "gpu-voltage-offset"),
|
||||
ClockspeedType::VoltageBoost => fl!(I18N, "gpu-voltage-boost"),
|
||||
ClockspeedType::GpuClockOffset(pstate) => fl!(I18N, "gpu-pstate-clock-offset", pstate = pstate),
|
||||
ClockspeedType::MemClockOffset(pstate) => fl!(I18N, "vram-pstate-clock-offset", pstate = pstate),
|
||||
ClockspeedType::GpuVfCurveClock(pstate) => fl!(I18N, "gpu-pstate-clock", pstate = pstate),
|
||||
ClockspeedType::MemVfCurveClock(pstate) => fl!(I18N, "mem-pstate-clock", pstate = pstate),
|
||||
ClockspeedType::GpuVfCurveVoltage(pstate) => fl!(I18N, "gpu-pstate-clock-voltage", pstate = pstate),
|
||||
ClockspeedType::MemVfCurveVoltage(pstate) => fl!(I18N, "mem-pstate-clock-voltage", pstate = pstate),
|
||||
ClockspeedType::Reset => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
gtk::MenuButton {
|
||||
set_icon_name: "dialog-information-symbolic",
|
||||
set_always_show_arrow: false,
|
||||
add_css_class: "flat",
|
||||
set_visible: self.clock_type == ClockspeedType::VoltageBoost,
|
||||
|
||||
#[wrap(Some)]
|
||||
set_popover = >k::Popover {
|
||||
gtk::Label {
|
||||
set_margin_all: 5,
|
||||
set_label: &fl!(I18N, "gpu-voltage-boost-tooltip"),
|
||||
set_wrap: true,
|
||||
set_wrap_mode: gtk::pango::WrapMode::Word,
|
||||
set_max_width_chars: 55,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
gtk::Scale {
|
||||
@@ -128,7 +165,7 @@ impl FactoryComponent for ClockAdjustmentRow {
|
||||
data.current as f64,
|
||||
data.min as f64,
|
||||
data.max as f64,
|
||||
10.0,
|
||||
data.step as f64,
|
||||
10.0,
|
||||
);
|
||||
|
||||
@@ -178,7 +215,7 @@ impl FactoryComponent for ClockAdjustmentRow {
|
||||
label_group,
|
||||
input_group,
|
||||
} => {
|
||||
label_group.add_widget(&widgets.title_label);
|
||||
label_group.add_widget(&widgets.title_box);
|
||||
input_group.add_widget(&widgets.input_button);
|
||||
}
|
||||
ClockAdjustmentRowMsg::SetVisible(visible) => {
|
||||
|
||||
@@ -420,7 +420,7 @@ impl ClocksFrame {
|
||||
min: sclk_offset_min,
|
||||
max: sclk_offset_max,
|
||||
custom_title: Some(fl!(I18N, "gpu-clock-offset")),
|
||||
is_secondary: false,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -457,8 +457,7 @@ impl ClocksFrame {
|
||||
current: level.clockspeed,
|
||||
min: min_sclk,
|
||||
max: max_sclk,
|
||||
is_secondary: false,
|
||||
custom_title: None,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -477,8 +476,7 @@ impl ClocksFrame {
|
||||
current: level.voltage,
|
||||
min: min_vddc,
|
||||
max: max_vddc,
|
||||
is_secondary: false,
|
||||
custom_title: None,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -540,7 +538,7 @@ impl ClocksFrame {
|
||||
min,
|
||||
max,
|
||||
is_secondary,
|
||||
custom_title: None,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -600,6 +598,19 @@ impl ClocksFrame {
|
||||
nvidia_clock_offset_to_data(offset, *pstate > 0),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(voltage_boost) = table.voltage_boost {
|
||||
self.set_clock(
|
||||
ClockspeedType::VoltageBoost,
|
||||
ClocksData {
|
||||
current: voltage_boost.current,
|
||||
min: voltage_boost.min,
|
||||
max: voltage_boost.max,
|
||||
step: 1,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_intel_table(&mut self, table: &IntelClocksTable) {
|
||||
@@ -664,7 +675,7 @@ fn nvidia_clock_offset_to_data(clock_info: &NvidiaClockOffset, is_secondary: boo
|
||||
current: clock_info.current,
|
||||
min: clock_info.min,
|
||||
max: clock_info.max,
|
||||
custom_title: None,
|
||||
is_secondary,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ pub struct ClocksConfiguration {
|
||||
)]
|
||||
pub mem_vf_curve: IndexMap<u8, CurvePoint>,
|
||||
pub voltage_offset: Option<i32>,
|
||||
pub voltage_boost: Option<i32>,
|
||||
}
|
||||
|
||||
impl ClocksConfiguration {
|
||||
@@ -102,6 +103,7 @@ impl ClocksConfiguration {
|
||||
ClockspeedType::MinMemoryClock => self.min_memory_clock = value,
|
||||
ClockspeedType::MinVoltage => self.min_voltage = value,
|
||||
ClockspeedType::VoltageOffset => self.voltage_offset = value,
|
||||
ClockspeedType::VoltageBoost => self.voltage_boost = value,
|
||||
ClockspeedType::GpuClockOffset(pstate) => match value {
|
||||
Some(value) => {
|
||||
self.gpu_clock_offsets.insert(pstate, value);
|
||||
|
||||
@@ -478,6 +478,16 @@ pub struct NvidiaClocksTable {
|
||||
pub vram_clock_range: Option<(u32, u32)>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub gpu_vf_curve: Vec<NvidiaVfPoint>,
|
||||
#[serde(default)]
|
||||
pub voltage_boost: Option<NvidiaVoltageBoost>,
|
||||
}
|
||||
|
||||
/// Nvidia core voltage boost, in percent
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, Copy)]
|
||||
pub struct NvidiaVoltageBoost {
|
||||
pub current: i32,
|
||||
pub min: i32,
|
||||
pub max: i32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, Copy)]
|
||||
|
||||
@@ -163,6 +163,7 @@ pub enum ClockspeedType {
|
||||
MinVoltage,
|
||||
MaxVoltage,
|
||||
VoltageOffset,
|
||||
VoltageBoost,
|
||||
|
||||
MaxMemoryClock,
|
||||
MinMemoryClock,
|
||||
|
||||
Reference in New Issue
Block a user