mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: use VRAM offset ratio on Ada, add config migration system to erase old
memory clock settings
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::server::gpu_controller::fan_control::FanCurve;
|
||||
use crate::server::gpu_controller::{fan_control::FanCurve, VENDOR_NVIDIA};
|
||||
use amdgpu_sysfs::gpu_handle::{PerformanceLevel, PowerLevelKind};
|
||||
use anyhow::Context;
|
||||
use indexmap::IndexMap;
|
||||
@@ -18,7 +18,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::{sync::mpsc, time};
|
||||
use tracing::{debug, error};
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
const FILE_NAME: &str = "config.yaml";
|
||||
const DEFAULT_ADMIN_GROUPS: [&str; 2] = ["wheel", "sudo"];
|
||||
@@ -29,6 +29,8 @@ const SELF_CONFIG_EDIT_PERIOD_MILLIS: u64 = 1000;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
pub version: u64,
|
||||
pub daemon: Daemon,
|
||||
#[serde(default = "default_apply_settings_timer")]
|
||||
pub apply_settings_timer: u64,
|
||||
@@ -51,6 +53,7 @@ impl Default for Config {
|
||||
profiles: IndexMap::new(),
|
||||
current_profile: None,
|
||||
auto_switch_profiles: false,
|
||||
version: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,6 +209,36 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn migrate_versions(&mut self) {
|
||||
loop {
|
||||
let next_version = self.version + 1;
|
||||
match next_version {
|
||||
0 => unreachable!(),
|
||||
// Reset VRAM settings on Nvidia after new offset ratio logic
|
||||
1 => {
|
||||
for (id, gpu) in &mut self.gpus {
|
||||
if id.starts_with(VENDOR_NVIDIA) {
|
||||
gpu.clocks_configuration.max_memory_clock = None;
|
||||
gpu.clocks_configuration.min_memory_clock = None;
|
||||
}
|
||||
}
|
||||
|
||||
for profile in &mut self.profiles.values_mut() {
|
||||
for (id, gpu) in &mut profile.gpus {
|
||||
if id.starts_with(VENDOR_NVIDIA) {
|
||||
gpu.clocks_configuration.max_memory_clock = None;
|
||||
gpu.clocks_configuration.min_memory_clock = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
info!("migrated config version {} to {next_version}", self.version);
|
||||
self.version = next_version;
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the GPU configs according to the current profile. Returns an error if the current profile could not be found.
|
||||
pub fn gpus(&self) -> anyhow::Result<&IndexMap<String, Gpu>> {
|
||||
match &self.current_profile {
|
||||
@@ -364,6 +397,7 @@ fn default_apply_settings_timer() -> u64 {
|
||||
mod tests {
|
||||
use super::{ClocksConfiguration, Config, Daemon, FanControlSettings, Gpu};
|
||||
use crate::server::gpu_controller::fan_control::FanCurve;
|
||||
use indexmap::IndexMap;
|
||||
use insta::assert_yaml_snapshot;
|
||||
use lact_schema::{FanControlMode, PmfwOptions};
|
||||
use std::collections::HashMap;
|
||||
@@ -431,4 +465,70 @@ mod tests {
|
||||
gpu.clocks_configuration.voltage_offset = Some(10);
|
||||
assert!(gpu.is_core_clocks_used());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn migrate_versions() {
|
||||
let mut config = Config {
|
||||
version: 0,
|
||||
daemon: Daemon::default(),
|
||||
apply_settings_timer: 5,
|
||||
gpus: IndexMap::from([
|
||||
(
|
||||
"10DE:2704-1462:5110-0000:09:00.0".to_owned(),
|
||||
Gpu {
|
||||
clocks_configuration: ClocksConfiguration {
|
||||
max_core_clock: Some(3000),
|
||||
max_memory_clock: Some(10_000),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
(
|
||||
"1002:687F-1043:0555-0000:0b:00.0".to_owned(),
|
||||
Gpu {
|
||||
clocks_configuration: ClocksConfiguration {
|
||||
max_core_clock: Some(1500),
|
||||
max_memory_clock: Some(920),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
]),
|
||||
profiles: IndexMap::new(),
|
||||
current_profile: None,
|
||||
auto_switch_profiles: false,
|
||||
};
|
||||
|
||||
config.migrate_versions();
|
||||
|
||||
assert_eq!(
|
||||
config
|
||||
.gpus
|
||||
.get("10DE:2704-1462:5110-0000:09:00.0")
|
||||
.unwrap()
|
||||
.clocks_configuration
|
||||
.max_core_clock,
|
||||
Some(3000)
|
||||
);
|
||||
assert_eq!(
|
||||
config
|
||||
.gpus
|
||||
.get("10DE:2704-1462:5110-0000:09:00.0")
|
||||
.unwrap()
|
||||
.clocks_configuration
|
||||
.max_memory_clock,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
config
|
||||
.gpus
|
||||
.get("1002:687F-1043:0555-0000:0b:00.0")
|
||||
.unwrap()
|
||||
.clocks_configuration
|
||||
.max_memory_clock,
|
||||
Some(920),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ use anyhow::Context;
|
||||
use config::Config;
|
||||
use futures::future::select_all;
|
||||
use server::{handle_stream, handler::Handler, Server};
|
||||
use std::cell::Cell;
|
||||
use std::time::Instant;
|
||||
use std::{os::unix::net::UnixStream as StdUnixStream, time::Duration};
|
||||
use tokio::net::UnixStream;
|
||||
use tokio::{
|
||||
@@ -46,7 +48,7 @@ pub fn run() -> anyhow::Result<()> {
|
||||
.build()
|
||||
.expect("Could not initialize tokio runtime");
|
||||
rt.block_on(async {
|
||||
let config = Config::load_or_create()?;
|
||||
let mut config = Config::load_or_create()?;
|
||||
|
||||
let env_filter = EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
@@ -54,6 +56,12 @@ pub fn run() -> anyhow::Result<()> {
|
||||
.context("Invalid log level")?;
|
||||
tracing_subscriber::fmt().with_env_filter(env_filter).init();
|
||||
|
||||
let original_version = config.version;
|
||||
config.migrate_versions();
|
||||
if config.version != original_version {
|
||||
config.save(&Cell::new(Instant::now()))?;
|
||||
}
|
||||
|
||||
ensure_sufficient_uptime().await;
|
||||
|
||||
LocalSet::new()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{fan_control::FanCurve, FanControlHandle, GpuController};
|
||||
use super::{fan_control::FanCurve, FanControlHandle, GpuController, VENDOR_AMD};
|
||||
use crate::{
|
||||
config::{self, ClocksConfiguration, FanControlSettings},
|
||||
server::vulkan::get_vulkan_info,
|
||||
@@ -47,7 +47,6 @@ use {
|
||||
|
||||
const GPU_CLOCKDOWN_TIMEOUT_SECS: u64 = 3;
|
||||
const MAX_PSTATE_READ_ATTEMPTS: u32 = 5;
|
||||
const VENDOR_AMD: &str = "1002";
|
||||
const STEAM_DECK_IDS: [&str; 2] = ["163F", "1435"];
|
||||
|
||||
pub struct AmdGpuController {
|
||||
|
||||
@@ -3,6 +3,9 @@ mod amd;
|
||||
pub mod fan_control;
|
||||
mod nvidia;
|
||||
|
||||
pub const VENDOR_AMD: &str = "1002";
|
||||
pub const VENDOR_NVIDIA: &str = "10DE";
|
||||
|
||||
pub use amd::AmdGpuController;
|
||||
pub use nvidia::NvidiaGpuController;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ use lact_schema::{
|
||||
};
|
||||
use nvml_wrapper::{
|
||||
bitmasks::device::ThrottleReasons,
|
||||
enum_wrappers::device::{Clock, TemperatureSensor, TemperatureThreshold},
|
||||
enum_wrappers::device::{Brand, Clock, TemperatureSensor, TemperatureThreshold},
|
||||
enums::device::DeviceArchitecture,
|
||||
Device, Nvml,
|
||||
};
|
||||
use std::{
|
||||
@@ -248,6 +249,20 @@ impl NvidiaGpuController {
|
||||
|
||||
Ok(power_states)
|
||||
}
|
||||
|
||||
// See https://github.com/ilya-zlobintsev/LACT/issues/418
|
||||
fn vram_offset_ratio(&self) -> i32 {
|
||||
let device = self.device();
|
||||
if let (Ok(brand), Ok(architecture)) = (device.brand(), device.architecture()) {
|
||||
let ratio = match (brand, architecture) {
|
||||
(Brand::GeForce, DeviceArchitecture::Ada) => 2,
|
||||
// TODO: check others
|
||||
_ => 1,
|
||||
};
|
||||
return ratio;
|
||||
}
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl GpuController for NvidiaGpuController {
|
||||
@@ -495,6 +510,7 @@ impl GpuController for NvidiaGpuController {
|
||||
gpc = Some(NvidiaClockInfo {
|
||||
max: max as i32,
|
||||
offset,
|
||||
offset_ratio: 1,
|
||||
offset_range,
|
||||
});
|
||||
}
|
||||
@@ -511,6 +527,7 @@ impl GpuController for NvidiaGpuController {
|
||||
mem = Some(NvidiaClockInfo {
|
||||
max: max as i32,
|
||||
offset,
|
||||
offset_ratio: self.vram_offset_ratio(),
|
||||
offset_range,
|
||||
});
|
||||
}
|
||||
@@ -600,7 +617,7 @@ impl GpuController for NvidiaGpuController {
|
||||
let default_max_clock = device
|
||||
.max_clock_info(Clock::Memory)
|
||||
.context("Could not read max memory clock")?;
|
||||
let offset = max_mem_clock - default_max_clock as i32;
|
||||
let offset = (max_mem_clock - default_max_clock as i32) * self.vram_offset_ratio();
|
||||
debug!("Using mem clock offset {offset} (default max clock: {default_max_clock})");
|
||||
|
||||
device
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
source: lact-daemon/src/config.rs
|
||||
expression: deserialized_config
|
||||
snapshot_kind: text
|
||||
---
|
||||
version: 0
|
||||
daemon:
|
||||
log_level: info
|
||||
admin_groups:
|
||||
|
||||
@@ -412,7 +412,8 @@ fn set_nvidia_clock_offset(clock_info: &NvidiaClockInfo, adjustment_row: &Adjust
|
||||
let oc_adjustment = &adjustment_row.imp().adjustment;
|
||||
oc_adjustment.set_lower((clock_info.max + clock_info.offset_range.0) as f64);
|
||||
oc_adjustment.set_upper((clock_info.max + clock_info.offset_range.1) as f64);
|
||||
oc_adjustment.set_value((clock_info.max + clock_info.offset) as f64);
|
||||
oc_adjustment
|
||||
.set_value((clock_info.max + (clock_info.offset / clock_info.offset_ratio)) as f64);
|
||||
|
||||
adjustment_row.set_visible(true);
|
||||
}
|
||||
|
||||
@@ -159,6 +159,7 @@ pub struct NvidiaClocksTable {
|
||||
pub struct NvidiaClockInfo {
|
||||
pub max: i32,
|
||||
pub offset: i32,
|
||||
pub offset_ratio: i32,
|
||||
pub offset_range: (i32, i32),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user