mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: basic gpu clock configuration
This commit is contained in:
parent
22bf7257f8
commit
29f04bd687
@ -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<String>,
|
||||
pci_info: GpuPciInfo,
|
||||
tile_gts: Vec<PathBuf>,
|
||||
@ -35,40 +36,37 @@ impl IntelGpuController {
|
||||
pci_slot_id: Option<String>,
|
||||
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<ClocksInfo> {
|
||||
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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ source: lact-daemon/src/tests/mod.rs
|
||||
expression: device_info
|
||||
---
|
||||
{
|
||||
"clocks_info": null,
|
||||
"clocks_info": {},
|
||||
"info": {
|
||||
"driver": "i915",
|
||||
"link_info": {},
|
||||
|
@ -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": {},
|
||||
|
@ -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);
|
||||
|
@ -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<NvidiaClockInfo>,
|
||||
}
|
||||
|
||||
/// 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<u32>,
|
||||
/// - rpe_freq: The Render Performance (RP) E level, which is the efficient one.
|
||||
pub rpe_freq: Option<u32>,
|
||||
/// - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one.
|
||||
pub rp0_freq: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
||||
pub struct NvidiaClockInfo {
|
||||
pub max: i32,
|
||||
|
Loading…
Reference in New Issue
Block a user