diff --git a/lact-daemon/src/server/gpu_controller/intel.rs b/lact-daemon/src/server/gpu_controller/intel.rs index f8848f6..fd9e2ed 100644 --- a/lact-daemon/src/server/gpu_controller/intel.rs +++ b/lact-daemon/src/server/gpu_controller/intel.rs @@ -1,10 +1,11 @@ use super::GpuController; use crate::{config, server::vulkan::get_vulkan_info}; use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable; -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use futures::future::LocalBoxFuture; use lact_schema::{ - ClocksInfo, ClockspeedStats, DeviceInfo, DeviceStats, GpuPciInfo, LinkInfo, PowerStates, + ClocksInfo, ClocksTable, ClockspeedStats, DeviceInfo, DeviceStats, GpuPciInfo, + IntelClocksTable, LinkInfo, PowerStates, }; use std::{ fmt::Display, @@ -14,15 +15,15 @@ use std::{ }; use tracing::{error, info, warn}; -enum DriverType { - Xe, - I915, -} +// enum DriverType { +// Xe, +// I915, +// } pub struct IntelGpuController { sysfs_path: PathBuf, driver: String, - driver_type: DriverType, + // driver_type: DriverType, pci_slot_id: Option, pci_info: GpuPciInfo, tile_gts: Vec, @@ -35,40 +36,37 @@ impl IntelGpuController { pci_slot_id: Option, pci_info: GpuPciInfo, ) -> Self { - let driver_type = match driver.as_str() { - "xe" => DriverType::Xe, - "i915" => DriverType::I915, - _ => unreachable!(), - }; + // let driver_type = match driver.as_str() { + // "xe" => DriverType::Xe, + // "i915" => DriverType::I915, + // _ => unreachable!(), + // }; let mut tile_gts = vec![]; - if let DriverType::Xe = driver_type { - for entry in fs::read_dir(&sysfs_path).into_iter().flatten().flatten() { - if let Some(name) = entry.file_name().to_str() { - if name.starts_with("tile") { - for gt_entry in fs::read_dir(entry.path()).into_iter().flatten().flatten() { - if let Some(gt_name) = gt_entry.file_name().to_str() { - if gt_name.starts_with("gt") { - tile_gts.push(gt_entry.path()); - } + for entry in fs::read_dir(&sysfs_path).into_iter().flatten().flatten() { + if let Some(name) = entry.file_name().to_str() { + if name.starts_with("tile") { + for gt_entry in fs::read_dir(entry.path()).into_iter().flatten().flatten() { + if let Some(gt_name) = gt_entry.file_name().to_str() { + if gt_name.starts_with("gt") { + tile_gts.push(gt_entry.path()); } } } } } - - info!( - "initialized {} gt at '{}'", - tile_gts.len(), - sysfs_path.display() - ); } + info!( + "initialized {} gt at '{}'", + tile_gts.len(), + sysfs_path.display() + ); + Self { sysfs_path, driver, - driver_type, pci_slot_id, pci_info, tile_gts, @@ -133,9 +131,20 @@ impl GpuController for IntelGpuController { fn apply_config<'a>( &'a self, - _config: &'a config::Gpu, + config: &'a config::Gpu, ) -> LocalBoxFuture<'a, anyhow::Result<()>> { - Box::pin(async { Ok(()) }) + Box::pin(async { + if let Some(max_clock) = config.clocks_configuration.max_core_clock { + self.write_gt_file("freq0/max_freq", &max_clock.to_string()) + .context("Could not set max clock")?; + } + if let Some(min_clock) = config.clocks_configuration.min_core_clock { + self.write_gt_file("freq0/min_freq", &min_clock.to_string()) + .context("Could not set min clock")?; + } + + Ok(()) + }) } fn get_stats(&self, _gpu_config: Option<&config::Gpu>) -> DeviceStats { @@ -157,7 +166,25 @@ impl GpuController for IntelGpuController { } fn get_clocks_info(&self) -> anyhow::Result { - Err(anyhow!("Not supported")) + let clocks_table = IntelClocksTable { + gt_freq: self + .read_gt_file("freq0/min_freq") + .zip(self.read_gt_file("freq0/max_freq")), + rp0_freq: self.read_gt_file("freq0/rp0_freq"), + rpe_freq: self.read_gt_file("freq0/rpe_freq"), + rpn_freq: self.read_gt_file("freq0/rpn_freq"), + }; + + let table = if clocks_table == IntelClocksTable::default() { + None + } else { + Some(ClocksTable::Intel(clocks_table)) + }; + + Ok(ClocksInfo { + table, + ..Default::default() + }) } fn get_power_states(&self, _gpu_config: Option<&config::Gpu>) -> PowerStates { @@ -189,7 +216,9 @@ impl IntelGpuController { T: FromStr, T::Err: Display, { - if let Some(file_path) = self.first_tile_gt().map(|path| path.join(file_name)) { + if let Some(gt_path) = self.first_tile_gt() { + let file_path = gt_path.join(file_name); + if file_path.exists() { match fs::read_to_string(&file_path) { Ok(contents) => match contents.trim().parse() { @@ -210,4 +239,20 @@ impl IntelGpuController { None } + + fn write_gt_file(&self, file_name: &str, contents: &str) -> anyhow::Result<()> { + if let Some(gt_path) = self.first_tile_gt() { + let file_path = gt_path.join(file_name); + + if file_path.exists() { + fs::write(&file_path, contents) + .with_context(|| format!("Could not write to '{}'", file_path.display()))?; + Ok(()) + } else { + Err(anyhow!("File '{}' does not exist", file_path.display())) + } + } else { + Err(anyhow!("No GTs available")) + } + } } diff --git a/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__cometlake.snap b/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__cometlake.snap index 337c21f..818e0c1 100644 --- a/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__cometlake.snap +++ b/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__cometlake.snap @@ -3,7 +3,7 @@ source: lact-daemon/src/tests/mod.rs expression: device_info --- { - "clocks_info": null, + "clocks_info": {}, "info": { "driver": "i915", "link_info": {}, diff --git a/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__tigerlake.snap b/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__tigerlake.snap index de0d806..93066d6 100644 --- a/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__tigerlake.snap +++ b/lact-daemon/src/tests/snapshots/lact_daemon__tests__intel__tigerlake.snap @@ -3,7 +3,20 @@ source: lact-daemon/src/tests/mod.rs expression: device_info --- { - "clocks_info": null, + "clocks_info": { + "table": { + "type": "intel", + "value": { + "gt_freq": [ + 1100, + 1300 + ], + "rp0_freq": 1300, + "rpe_freq": 600, + "rpn_freq": 100 + } + } + }, "info": { "driver": "xe", "link_info": {}, diff --git a/lact-gui/src/app/pages/oc_page/clocks_frame.rs b/lact-gui/src/app/pages/oc_page/clocks_frame.rs index d3182db..b510e41 100644 --- a/lact-gui/src/app/pages/oc_page/clocks_frame.rs +++ b/lact-gui/src/app/pages/oc_page/clocks_frame.rs @@ -7,7 +7,9 @@ use amdgpu_sysfs::gpu_handle::overdrive::{ClocksTable as _, ClocksTableGen as Am use glib::clone; use gtk::prelude::*; use gtk::*; -use lact_schema::{request::SetClocksCommand, ClocksTable, NvidiaClockInfo, NvidiaClocksTable}; +use lact_schema::{ + request::SetClocksCommand, ClocksTable, IntelClocksTable, NvidiaClockInfo, NvidiaClocksTable, +}; use subclass::prelude::ObjectSubclassIsExt; use tracing::debug; @@ -165,6 +167,7 @@ impl ClocksFrame { match table { ClocksTable::Amd(table) => self.set_amd_table(table), ClocksTable::Nvidia(table) => self.set_nvidia_table(table), + ClocksTable::Intel(table) => self.set_intel_table(table), } for adjustment in adjustments { @@ -284,6 +287,42 @@ impl ClocksFrame { } } + fn set_intel_table(&self, table: IntelClocksTable) { + if let Some((current_gt_min, current_gt_max)) = table.gt_freq { + if let (Some(min_clock), Some(max_clock)) = (table.rpn_freq, table.rp0_freq) { + self.min_sclk_adjustment + .imp() + .adjustment + .set_lower(min_clock as f64); + self.min_sclk_adjustment + .imp() + .adjustment + .set_upper(max_clock as f64); + self.min_sclk_adjustment + .imp() + .adjustment + .set_value(current_gt_min as f64); + + self.min_sclk_adjustment.set_visible(true); + + self.max_sclk_adjustment + .imp() + .adjustment + .set_lower(min_clock as f64); + self.max_sclk_adjustment + .imp() + .adjustment + .set_upper(max_clock as f64); + self.max_sclk_adjustment + .imp() + .adjustment + .set_value(current_gt_max as f64); + + self.max_sclk_adjustment.set_visible(true); + } + } + } + fn set_nvidia_table(&self, table: NvidiaClocksTable) { if let Some(gpc_info) = &table.gpc { set_nvidia_clock_offset(gpc_info, &self.max_sclk_adjustment); diff --git a/lact-schema/src/lib.rs b/lact-schema/src/lib.rs index df2b459..f5f30c3 100644 --- a/lact-schema/src/lib.rs +++ b/lact-schema/src/lib.rs @@ -146,6 +146,7 @@ pub struct ClocksInfo { pub enum ClocksTable { Amd(AmdClocksTableGen), Nvidia(NvidiaClocksTable), + Intel(IntelClocksTable), } #[skip_serializing_none] @@ -155,6 +156,19 @@ pub struct NvidiaClocksTable { pub mem: Option, } +/// Doc from `xe_gt_freq.c` +#[skip_serializing_none] +#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] +pub struct IntelClocksTable { + pub gt_freq: Option<(u32, u32)>, + /// - rpn_freq: The Render Performance (RP) N level, which is the minimal one. + pub rpn_freq: Option, + /// - rpe_freq: The Render Performance (RP) E level, which is the efficient one. + pub rpe_freq: Option, + /// - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one. + pub rp0_freq: Option, +} + #[derive(Serialize, Deserialize, Default, Debug, Clone)] pub struct NvidiaClockInfo { pub max: i32,