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 super::GpuController;
|
||||||
use crate::{config, server::vulkan::get_vulkan_info};
|
use crate::{config, server::vulkan::get_vulkan_info};
|
||||||
use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable;
|
use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable;
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
use lact_schema::{
|
use lact_schema::{
|
||||||
ClocksInfo, ClockspeedStats, DeviceInfo, DeviceStats, GpuPciInfo, LinkInfo, PowerStates,
|
ClocksInfo, ClocksTable, ClockspeedStats, DeviceInfo, DeviceStats, GpuPciInfo,
|
||||||
|
IntelClocksTable, LinkInfo, PowerStates,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
@ -14,15 +15,15 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
enum DriverType {
|
// enum DriverType {
|
||||||
Xe,
|
// Xe,
|
||||||
I915,
|
// I915,
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub struct IntelGpuController {
|
pub struct IntelGpuController {
|
||||||
sysfs_path: PathBuf,
|
sysfs_path: PathBuf,
|
||||||
driver: String,
|
driver: String,
|
||||||
driver_type: DriverType,
|
// driver_type: DriverType,
|
||||||
pci_slot_id: Option<String>,
|
pci_slot_id: Option<String>,
|
||||||
pci_info: GpuPciInfo,
|
pci_info: GpuPciInfo,
|
||||||
tile_gts: Vec<PathBuf>,
|
tile_gts: Vec<PathBuf>,
|
||||||
@ -35,15 +36,14 @@ impl IntelGpuController {
|
|||||||
pci_slot_id: Option<String>,
|
pci_slot_id: Option<String>,
|
||||||
pci_info: GpuPciInfo,
|
pci_info: GpuPciInfo,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let driver_type = match driver.as_str() {
|
// let driver_type = match driver.as_str() {
|
||||||
"xe" => DriverType::Xe,
|
// "xe" => DriverType::Xe,
|
||||||
"i915" => DriverType::I915,
|
// "i915" => DriverType::I915,
|
||||||
_ => unreachable!(),
|
// _ => unreachable!(),
|
||||||
};
|
// };
|
||||||
|
|
||||||
let mut tile_gts = vec![];
|
let mut tile_gts = vec![];
|
||||||
|
|
||||||
if let DriverType::Xe = driver_type {
|
|
||||||
for entry in fs::read_dir(&sysfs_path).into_iter().flatten().flatten() {
|
for entry in fs::read_dir(&sysfs_path).into_iter().flatten().flatten() {
|
||||||
if let Some(name) = entry.file_name().to_str() {
|
if let Some(name) = entry.file_name().to_str() {
|
||||||
if name.starts_with("tile") {
|
if name.starts_with("tile") {
|
||||||
@ -63,12 +63,10 @@ impl IntelGpuController {
|
|||||||
tile_gts.len(),
|
tile_gts.len(),
|
||||||
sysfs_path.display()
|
sysfs_path.display()
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sysfs_path,
|
sysfs_path,
|
||||||
driver,
|
driver,
|
||||||
driver_type,
|
|
||||||
pci_slot_id,
|
pci_slot_id,
|
||||||
pci_info,
|
pci_info,
|
||||||
tile_gts,
|
tile_gts,
|
||||||
@ -133,9 +131,20 @@ impl GpuController for IntelGpuController {
|
|||||||
|
|
||||||
fn apply_config<'a>(
|
fn apply_config<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
_config: &'a config::Gpu,
|
config: &'a config::Gpu,
|
||||||
) -> LocalBoxFuture<'a, anyhow::Result<()>> {
|
) -> 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 {
|
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> {
|
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 {
|
fn get_power_states(&self, _gpu_config: Option<&config::Gpu>) -> PowerStates {
|
||||||
@ -189,7 +216,9 @@ impl IntelGpuController {
|
|||||||
T: FromStr,
|
T: FromStr,
|
||||||
T::Err: Display,
|
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() {
|
if file_path.exists() {
|
||||||
match fs::read_to_string(&file_path) {
|
match fs::read_to_string(&file_path) {
|
||||||
Ok(contents) => match contents.trim().parse() {
|
Ok(contents) => match contents.trim().parse() {
|
||||||
@ -210,4 +239,20 @@ impl IntelGpuController {
|
|||||||
|
|
||||||
None
|
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
|
expression: device_info
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
"clocks_info": null,
|
"clocks_info": {},
|
||||||
"info": {
|
"info": {
|
||||||
"driver": "i915",
|
"driver": "i915",
|
||||||
"link_info": {},
|
"link_info": {},
|
||||||
|
@ -3,7 +3,20 @@ source: lact-daemon/src/tests/mod.rs
|
|||||||
expression: device_info
|
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": {
|
"info": {
|
||||||
"driver": "xe",
|
"driver": "xe",
|
||||||
"link_info": {},
|
"link_info": {},
|
||||||
|
@ -7,7 +7,9 @@ use amdgpu_sysfs::gpu_handle::overdrive::{ClocksTable as _, ClocksTableGen as Am
|
|||||||
use glib::clone;
|
use glib::clone;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::*;
|
use gtk::*;
|
||||||
use lact_schema::{request::SetClocksCommand, ClocksTable, NvidiaClockInfo, NvidiaClocksTable};
|
use lact_schema::{
|
||||||
|
request::SetClocksCommand, ClocksTable, IntelClocksTable, NvidiaClockInfo, NvidiaClocksTable,
|
||||||
|
};
|
||||||
use subclass::prelude::ObjectSubclassIsExt;
|
use subclass::prelude::ObjectSubclassIsExt;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
@ -165,6 +167,7 @@ impl ClocksFrame {
|
|||||||
match table {
|
match table {
|
||||||
ClocksTable::Amd(table) => self.set_amd_table(table),
|
ClocksTable::Amd(table) => self.set_amd_table(table),
|
||||||
ClocksTable::Nvidia(table) => self.set_nvidia_table(table),
|
ClocksTable::Nvidia(table) => self.set_nvidia_table(table),
|
||||||
|
ClocksTable::Intel(table) => self.set_intel_table(table),
|
||||||
}
|
}
|
||||||
|
|
||||||
for adjustment in adjustments {
|
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) {
|
fn set_nvidia_table(&self, table: NvidiaClocksTable) {
|
||||||
if let Some(gpc_info) = &table.gpc {
|
if let Some(gpc_info) = &table.gpc {
|
||||||
set_nvidia_clock_offset(gpc_info, &self.max_sclk_adjustment);
|
set_nvidia_clock_offset(gpc_info, &self.max_sclk_adjustment);
|
||||||
|
@ -146,6 +146,7 @@ pub struct ClocksInfo {
|
|||||||
pub enum ClocksTable {
|
pub enum ClocksTable {
|
||||||
Amd(AmdClocksTableGen),
|
Amd(AmdClocksTableGen),
|
||||||
Nvidia(NvidiaClocksTable),
|
Nvidia(NvidiaClocksTable),
|
||||||
|
Intel(IntelClocksTable),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
@ -155,6 +156,19 @@ pub struct NvidiaClocksTable {
|
|||||||
pub mem: Option<NvidiaClockInfo>,
|
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)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
||||||
pub struct NvidiaClockInfo {
|
pub struct NvidiaClockInfo {
|
||||||
pub max: i32,
|
pub max: i32,
|
||||||
|
Loading…
Reference in New Issue
Block a user