mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-17 16:34:54 -05:00
feat: report clockspeed of extra clock domains on nvidia (#1155)
This commit is contained in:
@@ -6,7 +6,9 @@ use crate::{
|
||||
bindings::nvidia::NvPhysicalGpuHandle,
|
||||
server::gpu_controller::{
|
||||
common::{fan_control::FanCurveExt, resolve_process_name},
|
||||
nvidia::nvapi::{CLOCK_CLIENT_CLK_VF_POINT_TYPE_PROG, ClockClientClkVfPointInfoV1},
|
||||
nvidia::nvapi::{
|
||||
CLOCK_CLIENT_CLK_VF_POINT_TYPE_PROG, ClockClientClkVfPointInfoV1, NvGpuClockDomainId,
|
||||
},
|
||||
},
|
||||
};
|
||||
use amdgpu_sysfs::{
|
||||
@@ -882,6 +884,14 @@ impl GpuController for NvidiaGpuController {
|
||||
);
|
||||
}
|
||||
|
||||
let mut extra_clocks = [
|
||||
("SM", device.clock_info(Clock::SM)),
|
||||
("Video", device.clock_info(Clock::Video)),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(name, value)| Some((name.to_owned(), u64::from(value.ok()?))))
|
||||
.collect::<HashMap<String, u64>>();
|
||||
|
||||
let mut voltage = None;
|
||||
|
||||
if let Some((nvapi, handle)) = self.nvapi.as_ref() {
|
||||
@@ -952,6 +962,15 @@ impl GpuController for NvidiaGpuController {
|
||||
if let Ok(value) = nvapi.get_voltage(*handle) {
|
||||
voltage = Some(u64::from(value) / 1000);
|
||||
}
|
||||
|
||||
if let Ok(clocks) = nvapi.get_all_clocks(*handle) {
|
||||
for domain in NvGpuClockDomainId::EXTRA {
|
||||
if let Some(info) = clocks.get_domain(domain) {
|
||||
extra_clocks
|
||||
.insert(domain.to_string(), u64::from(info.frequency) / 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1048,13 +1067,7 @@ impl GpuController for NvidiaGpuController {
|
||||
gpu_clockspeed: device.clock_info(Clock::Graphics).map(Into::into).ok(),
|
||||
vram_clockspeed: device.clock_info(Clock::Memory).map(Into::into).ok(),
|
||||
target_gpu_clockspeed: None,
|
||||
sensors: [
|
||||
("SM", device.clock_info(Clock::SM)),
|
||||
("Video", device.clock_info(Clock::Video)),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(label, result)| Some((label.to_owned(), result.ok()?.into())))
|
||||
.collect(),
|
||||
sensors: extra_clocks,
|
||||
},
|
||||
throttle_info: device.current_throttle_reasons().ok().map(|reasons| {
|
||||
reasons
|
||||
|
||||
@@ -36,6 +36,7 @@ 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;
|
||||
const QUERY_NVAPI_GPU_CLOCK_CLIENT_CLK_VF_POINTS_GET_CONTROL: u32 = 0x23f1b133;
|
||||
const QUERY_NVAPI_GPU_REGISTER_OP: u32 = 0x2eb3c140;
|
||||
const QUERY_NVAPI_GPU_GET_ALL_CLOCKS: u32 = 0x1BD69F49;
|
||||
|
||||
const REG_OFFSET_BLACKWELL_HOTSPOT_AGGREGATED: u32 = 0xad0aa0;
|
||||
|
||||
@@ -114,7 +115,6 @@ impl NvApi {
|
||||
|
||||
pub unsafe fn get_voltage(&self, handle: NvPhysicalGpuHandle) -> anyhow::Result<u32> {
|
||||
let mut data = NvApiVoltage::default();
|
||||
|
||||
self.physical_gpu_query(handle, &mut data, QUERY_NVAPI_VOLTAGE)?;
|
||||
|
||||
Ok(data.rails[0].current_voltage_uv)
|
||||
@@ -122,12 +122,21 @@ impl NvApi {
|
||||
|
||||
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 get_all_clocks(
|
||||
&self,
|
||||
handle: NvPhysicalGpuHandle,
|
||||
) -> anyhow::Result<NvGpuClockInfoV2> {
|
||||
let mut data = NvGpuClockInfoV2::default();
|
||||
self.physical_gpu_query(handle, &mut data, QUERY_NVAPI_GPU_GET_ALL_CLOCKS)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub unsafe fn set_voltage_boost(
|
||||
&self,
|
||||
handle: NvPhysicalGpuHandle,
|
||||
@@ -137,7 +146,6 @@ impl NvApi {
|
||||
percent,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.physical_gpu_query(handle, &mut data, QUERY_NVAPI_VOLTAGE_BOOST_SET)?;
|
||||
|
||||
Ok(())
|
||||
@@ -711,6 +719,133 @@ impl Default for NvGpuRegisterOpDataV1 {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NvGpuClockInfoV2 {
|
||||
version: NvU32,
|
||||
domain: [NvGpuClockInfoDomain; 32usize],
|
||||
extended_domain: [NvGpuClockInfoV2ExtendedDomain; 32usize],
|
||||
}
|
||||
|
||||
impl NvGpuClockInfoV2 {
|
||||
pub fn get_domain(&self, domain: NvGpuClockDomainId) -> Option<NvGpuClockInfoDomain> {
|
||||
self.domain
|
||||
.get(domain as usize)
|
||||
.filter(|domain| domain.bitfield & 1 != 0 && domain.frequency != 0)
|
||||
.copied()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NvGpuClockInfoV2 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: make_version::<Self>(2),
|
||||
domain: Default::default(),
|
||||
extended_domain: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct NvGpuClockInfoDomain {
|
||||
pub frequency: NvU32,
|
||||
bitfield: NvU32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub struct NvGpuClockInfoV2ExtendedDomain {
|
||||
effective_frequency: NvU32,
|
||||
ratio_domain: NvGpuClockDomainId,
|
||||
ratio: NvU32,
|
||||
reserved: [NvU32; 4usize],
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||
pub enum NvGpuClockDomainId {
|
||||
// Gpc = 0,
|
||||
Xbar = 1,
|
||||
Sys = 2,
|
||||
Hub = 3,
|
||||
// M = 4,
|
||||
Host = 5,
|
||||
Disp = 6,
|
||||
Pclk0 = 8,
|
||||
Pclk1 = 9,
|
||||
Xclk = 11,
|
||||
Leg = 19,
|
||||
Pwr = 20,
|
||||
Msd = 21,
|
||||
Utils = 22,
|
||||
_2D = 26,
|
||||
_3D = 27,
|
||||
Host1x = 28,
|
||||
Disp0 = 29,
|
||||
Disp1 = 30,
|
||||
// Pciegen = 31,
|
||||
#[default]
|
||||
Undefined = 32,
|
||||
}
|
||||
|
||||
impl NvGpuClockDomainId {
|
||||
/// Excludes the domains already reported through NVML
|
||||
pub const EXTRA: [Self; 17] = [
|
||||
// Self::Gpc,
|
||||
Self::Xbar,
|
||||
Self::Sys,
|
||||
Self::Hub,
|
||||
// Self::M,
|
||||
Self::Host,
|
||||
Self::Disp,
|
||||
Self::Pclk0,
|
||||
Self::Pclk1,
|
||||
Self::Xclk,
|
||||
Self::Leg,
|
||||
Self::Pwr,
|
||||
Self::Msd,
|
||||
Self::Utils,
|
||||
Self::_2D,
|
||||
Self::_3D,
|
||||
Self::Host1x,
|
||||
Self::Disp0,
|
||||
Self::Disp1,
|
||||
];
|
||||
|
||||
pub fn into_str(self) -> &'static str {
|
||||
match self {
|
||||
// Self::Gpc => "GPC",
|
||||
Self::Xbar => "XBAR",
|
||||
Self::Sys => "SYS",
|
||||
Self::Hub => "HUB",
|
||||
// Self::M => "Memory",
|
||||
Self::Host => "Host",
|
||||
Self::Disp => "Display",
|
||||
Self::Pclk0 => "Pixel Clock 0",
|
||||
Self::Pclk1 => "Pixel Clock 1",
|
||||
Self::Xclk => "External Clock",
|
||||
Self::Leg => "Legacy",
|
||||
Self::Pwr => "Power",
|
||||
Self::Msd => "MSD",
|
||||
Self::Utils => "Utils",
|
||||
Self::_2D => "2D",
|
||||
Self::_3D => "3D",
|
||||
Self::Host1x => "Host1x",
|
||||
Self::Disp0 => "Display 0",
|
||||
Self::Disp1 => "Display 1",
|
||||
// Self::Pciegen => "PCIe",
|
||||
Self::Undefined => "Undefined",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NvGpuClockDomainId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.into_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
const fn make_version<T>(version: usize) -> u32 {
|
||||
(mem::size_of::<T>() | (version << 16)) as u32
|
||||
|
||||
Reference in New Issue
Block a user