mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
feat: numerous i915 additions
This commit is contained in:
parent
543265ddb2
commit
c5d2996a30
@ -377,11 +377,12 @@ impl AmdGpuController {
|
|||||||
.context("GPU has no hardware monitor")
|
.context("GPU has no hardware monitor")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_current_gfxclk(&self) -> Option<u16> {
|
fn get_current_gfxclk(&self) -> Option<u64> {
|
||||||
self.drm_handle
|
self.drm_handle
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|drm_handle| drm_handle.get_gpu_metrics().ok())
|
.and_then(|drm_handle| drm_handle.get_gpu_metrics().ok())
|
||||||
.and_then(|metrics| metrics.get_current_gfxclk())
|
.and_then(|metrics| metrics.get_current_gfxclk())
|
||||||
|
.map(u64::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_full_vbios_version(&self) -> Option<String> {
|
fn get_full_vbios_version(&self) -> Option<String> {
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use super::{CommonControllerInfo, GpuController};
|
use super::{CommonControllerInfo, GpuController};
|
||||||
use crate::{bindings::intel::IntelDrm, config, server::vulkan::get_vulkan_info};
|
use crate::{bindings::intel::IntelDrm, config, server::vulkan::get_vulkan_info};
|
||||||
use amdgpu_sysfs::gpu_handle::power_profile_mode::PowerProfileModesTable;
|
use amdgpu_sysfs::{gpu_handle::power_profile_mode::PowerProfileModesTable, hw_mon::Temperature};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
use lact_schema::{
|
use lact_schema::{
|
||||||
ClocksInfo, ClocksTable, ClockspeedStats, DeviceInfo, DeviceStats, DrmInfo, IntelClocksTable,
|
ClocksInfo, ClocksTable, ClockspeedStats, DeviceInfo, DeviceStats, DrmInfo, IntelClocksTable,
|
||||||
IntelDrmInfo, LinkInfo, PowerStates, VramStats,
|
IntelDrmInfo, LinkInfo, PowerStates, PowerStats, VoltageStats, VramStats,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
fs,
|
fs,
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
@ -20,6 +21,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tracing::{debug, error, info, trace, warn};
|
use tracing::{debug, error, info, trace, warn};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
enum DriverType {
|
enum DriverType {
|
||||||
I915,
|
I915,
|
||||||
Xe,
|
Xe,
|
||||||
@ -29,9 +31,12 @@ pub struct IntelGpuController {
|
|||||||
driver_type: DriverType,
|
driver_type: DriverType,
|
||||||
common: CommonControllerInfo,
|
common: CommonControllerInfo,
|
||||||
tile_gts: Vec<PathBuf>,
|
tile_gts: Vec<PathBuf>,
|
||||||
|
hwmon_path: Option<PathBuf>,
|
||||||
drm_file: fs::File,
|
drm_file: fs::File,
|
||||||
drm: Rc<IntelDrm>,
|
drm: Rc<IntelDrm>,
|
||||||
last_gpu_busy: Cell<Option<(Instant, u64)>>,
|
last_gpu_busy: Cell<Option<(Instant, u64)>>,
|
||||||
|
last_energy_value: Cell<Option<(Instant, u64)>>,
|
||||||
|
initial_power_cap: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntelGpuController {
|
impl IntelGpuController {
|
||||||
@ -86,14 +91,29 @@ impl IntelGpuController {
|
|||||||
fs::File::open("/dev/null").unwrap()
|
fs::File::open("/dev/null").unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
let hwmon_path = fs::read_dir(common.sysfs_path.join("hwmon"))
|
||||||
|
.ok()
|
||||||
|
.and_then(|mut read_dir| read_dir.next())
|
||||||
|
.and_then(Result::ok)
|
||||||
|
.map(|entry| entry.path());
|
||||||
|
debug!("Initialized hwmon: {hwmon_path:?}");
|
||||||
|
|
||||||
|
let mut controller = Self {
|
||||||
common,
|
common,
|
||||||
driver_type,
|
driver_type,
|
||||||
tile_gts,
|
tile_gts,
|
||||||
|
hwmon_path,
|
||||||
drm_file,
|
drm_file,
|
||||||
drm,
|
drm,
|
||||||
last_gpu_busy: Cell::new(None),
|
last_gpu_busy: Cell::new(None),
|
||||||
})
|
last_energy_value: Cell::new(None),
|
||||||
|
initial_power_cap: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let stats = controller.get_stats(None);
|
||||||
|
controller.initial_power_cap = stats.power.cap_current.filter(|cap| *cap != 0.0);
|
||||||
|
|
||||||
|
Ok(controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,32 +150,25 @@ impl GpuController for IntelGpuController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||||
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 {
|
Box::pin(async {
|
||||||
match self.driver_type {
|
|
||||||
DriverType::Xe => {
|
|
||||||
if let Some(max_clock) = config.clocks_configuration.max_core_clock {
|
if let Some(max_clock) = config.clocks_configuration.max_core_clock {
|
||||||
self.write_gt_file("freq0/max_freq", &max_clock.to_string())
|
self.write_freq(FrequencyType::Max, max_clock)
|
||||||
.context("Could not set max clock")?;
|
.context("Could not set max clock")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(min_clock) = config.clocks_configuration.min_core_clock {
|
if let Some(min_clock) = config.clocks_configuration.min_core_clock {
|
||||||
self.write_gt_file("freq0/min_freq", &min_clock.to_string())
|
self.write_freq(FrequencyType::Min, min_clock)
|
||||||
.context("Could not set min clock")?;
|
.context("Could not set min clock")?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
DriverType::I915 => {
|
if let Some(cap) = config.power_cap {
|
||||||
if let Some(max_clock) = config.clocks_configuration.max_core_clock {
|
self.write_hwmon_file("power1_max", &((cap * 1_000_000.0) as u64).to_string())
|
||||||
self.write_file("../gt_max_freq_mhz", &max_clock.to_string())
|
.context("Could not set power cap")?;
|
||||||
.context("Could not set max clock")?;
|
|
||||||
}
|
|
||||||
if let Some(min_clock) = config.clocks_configuration.min_core_clock {
|
|
||||||
self.write_file("../gt_min_freq_mhz", &min_clock.to_string())
|
|
||||||
.context("Could not set min clock")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -163,22 +176,11 @@ impl GpuController for IntelGpuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_stats(&self, _gpu_config: Option<&config::Gpu>) -> DeviceStats {
|
fn get_stats(&self, _gpu_config: Option<&config::Gpu>) -> DeviceStats {
|
||||||
let current_gfxclk;
|
let current_gfxclk = self.read_freq(FrequencyType::Cur);
|
||||||
let gpu_clockspeed;
|
let gpu_clockspeed = self
|
||||||
|
.read_freq(FrequencyType::Act)
|
||||||
match self.driver_type {
|
.filter(|value| *value != 0)
|
||||||
DriverType::Xe => {
|
.or(current_gfxclk);
|
||||||
current_gfxclk = self.read_gt_file("freq0/cur_freq");
|
|
||||||
gpu_clockspeed = self
|
|
||||||
.read_gt_file("freq0/act_freq")
|
|
||||||
.filter(|freq| *freq != 0)
|
|
||||||
.or_else(|| current_gfxclk.map(u64::from));
|
|
||||||
}
|
|
||||||
DriverType::I915 => {
|
|
||||||
current_gfxclk = self.read_file("../gt_cur_freq_mhz");
|
|
||||||
gpu_clockspeed = self.read_file("../gt_act_freq_mhz");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let clockspeed = ClockspeedStats {
|
let clockspeed = ClockspeedStats {
|
||||||
gpu_clockspeed,
|
gpu_clockspeed,
|
||||||
@ -186,37 +188,56 @@ impl GpuController for IntelGpuController {
|
|||||||
vram_clockspeed: None,
|
vram_clockspeed: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
DeviceStats {
|
let cap_current = self
|
||||||
clockspeed,
|
.read_hwmon_file("power1_max")
|
||||||
vram: VramStats {
|
.map(|value: f64| value / 1_000_000.0)
|
||||||
|
.map(|cap| if cap == 0.0 { 100.0 } else { cap }); // Placeholder max value
|
||||||
|
|
||||||
|
let power = PowerStats {
|
||||||
|
average: None,
|
||||||
|
current: self.get_power_usage(),
|
||||||
|
cap_current,
|
||||||
|
cap_min: Some(0.0),
|
||||||
|
cap_max: self
|
||||||
|
.read_hwmon_file::<f64>("power1_rated_max")
|
||||||
|
.filter(|max| *max != 0.0)
|
||||||
|
.map(|cap| cap / 1_000_000.0)
|
||||||
|
.or_else(|| cap_current.map(|current| current * 2.0)),
|
||||||
|
cap_default: self.initial_power_cap,
|
||||||
|
};
|
||||||
|
|
||||||
|
let voltage = VoltageStats {
|
||||||
|
gpu: self.read_hwmon_file("in0_input"),
|
||||||
|
northbridge: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let vram = VramStats {
|
||||||
total: self
|
total: self
|
||||||
.drm_try_2(IntelDrm::drm_intel_get_aperture_sizes)
|
.drm_try_2(IntelDrm::drm_intel_get_aperture_sizes)
|
||||||
.map(|(_, total)| total as u64),
|
.map(|(_, total)| total as u64),
|
||||||
used: None,
|
used: None,
|
||||||
},
|
};
|
||||||
|
|
||||||
|
DeviceStats {
|
||||||
|
clockspeed,
|
||||||
|
vram,
|
||||||
busy_percent: self.get_busy_percent(),
|
busy_percent: self.get_busy_percent(),
|
||||||
|
power,
|
||||||
|
temps: self.get_temperatures(),
|
||||||
|
voltage,
|
||||||
|
throttle_info: self.get_throttle_info(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_clocks_info(&self) -> anyhow::Result<ClocksInfo> {
|
fn get_clocks_info(&self) -> anyhow::Result<ClocksInfo> {
|
||||||
let clocks_table = match self.driver_type {
|
let clocks_table = IntelClocksTable {
|
||||||
DriverType::Xe => IntelClocksTable {
|
|
||||||
gt_freq: self
|
gt_freq: self
|
||||||
.read_gt_file("freq0/min_freq")
|
.read_freq(FrequencyType::Min)
|
||||||
.zip(self.read_gt_file("freq0/max_freq")),
|
.zip(self.read_freq(FrequencyType::Max)),
|
||||||
rp0_freq: self.read_gt_file("freq0/rp0_freq"),
|
rp0_freq: self.read_freq(FrequencyType::Rp0),
|
||||||
rpe_freq: self.read_gt_file("freq0/rpe_freq"),
|
rpe_freq: self.read_freq(FrequencyType::Rpe),
|
||||||
rpn_freq: self.read_gt_file("freq0/rpn_freq"),
|
rpn_freq: self.read_freq(FrequencyType::Rpn),
|
||||||
},
|
|
||||||
DriverType::I915 => IntelClocksTable {
|
|
||||||
gt_freq: self
|
|
||||||
.read_file("../gt_min_freq_mhz")
|
|
||||||
.zip(self.read_file("../gt_max_freq_mhz")),
|
|
||||||
rpn_freq: self.read_file("../gt_RPn_freq_mhz"),
|
|
||||||
rpe_freq: self.read_file("../gt_RP1_freq_mhz"),
|
|
||||||
rp0_freq: self.read_file("../gt_RP0_freq_mhz"),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let table = if clocks_table == IntelClocksTable::default() {
|
let table = if clocks_table == IntelClocksTable::default() {
|
||||||
@ -237,7 +258,20 @@ impl GpuController for IntelGpuController {
|
|||||||
|
|
||||||
fn reset_pmfw_settings(&self) {}
|
fn reset_pmfw_settings(&self) {}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
fn cleanup_clocks(&self) -> anyhow::Result<()> {
|
fn cleanup_clocks(&self) -> anyhow::Result<()> {
|
||||||
|
if let Some(rp0) = self.read_freq(FrequencyType::Rp0) {
|
||||||
|
if let Err(err) = self.write_freq(FrequencyType::Max, rp0 as i32) {
|
||||||
|
warn!("could not reset max clock: {err:#}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rpn) = self.read_freq(FrequencyType::Rpn) {
|
||||||
|
if let Err(err) = self.write_freq(FrequencyType::Min, rpn as i32) {
|
||||||
|
warn!("could not reset min clock: {err:#}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,29 +298,12 @@ impl IntelGpuController {
|
|||||||
self.tile_gts.first().map(PathBuf::as_ref)
|
self.tile_gts.first().map(PathBuf::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Based on the input path, this has the following behaviour:
|
|
||||||
/// - Basic relative paths are resolved relative to the sysfs device
|
|
||||||
/// - Parent paths (starting with (../) are resolved on the sysfs card entry, without resolving device symlink
|
|
||||||
fn sysfs_file_path(&self, path: impl AsRef<Path>) -> PathBuf {
|
|
||||||
let path = path.as_ref();
|
|
||||||
|
|
||||||
match path.strip_prefix("../") {
|
|
||||||
Ok(path_relative_to_parent) => self
|
|
||||||
.common
|
|
||||||
.sysfs_path
|
|
||||||
.parent()
|
|
||||||
.expect("Device path has no parent")
|
|
||||||
.join(path_relative_to_parent),
|
|
||||||
Err(_) => self.common.sysfs_path.join(path),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_file<T>(&self, path: impl AsRef<Path>) -> Option<T>
|
fn read_file<T>(&self, path: impl AsRef<Path>) -> Option<T>
|
||||||
where
|
where
|
||||||
T: FromStr,
|
T: FromStr,
|
||||||
T::Err: Display,
|
T::Err: Display,
|
||||||
{
|
{
|
||||||
let file_path = self.sysfs_file_path(path);
|
let file_path = self.common.sysfs_path.join(path);
|
||||||
|
|
||||||
trace!("reading file from '{}'", file_path.display());
|
trace!("reading file from '{}'", file_path.display());
|
||||||
|
|
||||||
@ -310,7 +327,7 @@ impl IntelGpuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_file(&self, path: impl AsRef<Path>, contents: &str) -> anyhow::Result<()> {
|
fn write_file(&self, path: impl AsRef<Path>, contents: &str) -> anyhow::Result<()> {
|
||||||
let file_path = self.sysfs_file_path(path);
|
let file_path = self.common.sysfs_path.join(path);
|
||||||
|
|
||||||
if file_path.exists() {
|
if file_path.exists() {
|
||||||
fs::write(&file_path, contents)
|
fs::write(&file_path, contents)
|
||||||
@ -321,23 +338,24 @@ impl IntelGpuController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_gt_file<T>(&self, file_name: &str) -> Option<T>
|
fn read_hwmon_file<T>(&self, file_name: &str) -> Option<T>
|
||||||
where
|
where
|
||||||
T: FromStr,
|
T: FromStr,
|
||||||
T::Err: Display,
|
T::Err: Display,
|
||||||
{
|
{
|
||||||
self.first_tile_gt().and_then(|gt_path| {
|
self.hwmon_path.as_ref().and_then(|hwmon_path| {
|
||||||
let file_path = gt_path.join(file_name);
|
let file_path = hwmon_path.join(file_name);
|
||||||
self.read_file(file_path)
|
self.read_file(file_path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_gt_file(&self, file_name: &str, contents: &str) -> anyhow::Result<()> {
|
fn write_hwmon_file(&self, file_name: &str, contents: &str) -> anyhow::Result<()> {
|
||||||
if let Some(gt_path) = self.first_tile_gt() {
|
debug!("writing value '{contents}' to '{file_name}'");
|
||||||
let file_path = gt_path.join(file_name);
|
if let Some(hwmon_path) = &self.hwmon_path {
|
||||||
|
let file_path = hwmon_path.join(file_name);
|
||||||
self.write_file(file_path, contents)
|
self.write_file(file_path, contents)
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("No GTs available"))
|
Err(anyhow!("No hwmon available"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,4 +444,128 @@ impl IntelGpuController {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
|
||||||
|
fn get_power_usage(&self) -> Option<f64> {
|
||||||
|
self.read_hwmon_file::<u64>("power1_input")
|
||||||
|
.or_else(|| {
|
||||||
|
let energy = self.read_hwmon_file("energy1_input")?;
|
||||||
|
let timestamp = Instant::now();
|
||||||
|
|
||||||
|
match self.last_energy_value.replace(Some((timestamp, energy))) {
|
||||||
|
Some((last_timestamp, last_energy)) => {
|
||||||
|
let time_delta = timestamp - last_timestamp;
|
||||||
|
let energy_delta = energy - last_energy;
|
||||||
|
|
||||||
|
Some(energy_delta / time_delta.as_millis() as u64 * 1000)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|value| value as f64 / 1_000_000.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_temperatures(&self) -> HashMap<String, Temperature> {
|
||||||
|
self.read_hwmon_file::<f32>("temp1_input")
|
||||||
|
.into_iter()
|
||||||
|
.map(|temp| {
|
||||||
|
let key = "gpu".to_owned();
|
||||||
|
let temperature = Temperature {
|
||||||
|
current: Some(temp / 1000.0),
|
||||||
|
crit: None,
|
||||||
|
crit_hyst: None,
|
||||||
|
};
|
||||||
|
(key, temperature)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_freq(&self, freq: FrequencyType) -> Option<u64> {
|
||||||
|
self.freq_path(freq).and_then(|path| self.read_file(&path))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_freq(&self, freq: FrequencyType, value: i32) -> anyhow::Result<()> {
|
||||||
|
let path = self.freq_path(freq).context("Frequency info not found")?;
|
||||||
|
self.write_file(path, &value.to_string())
|
||||||
|
.context("Could not write frequency")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freq_path(&self, freq: FrequencyType) -> Option<PathBuf> {
|
||||||
|
let path = &self.common.sysfs_path;
|
||||||
|
|
||||||
|
match self.driver_type {
|
||||||
|
DriverType::I915 => {
|
||||||
|
let card_path = path.parent().expect("Device has no parent path");
|
||||||
|
|
||||||
|
let infix = match freq {
|
||||||
|
FrequencyType::Cur => "cur",
|
||||||
|
FrequencyType::Act => "act",
|
||||||
|
FrequencyType::Min => "min",
|
||||||
|
FrequencyType::Max => "max",
|
||||||
|
FrequencyType::Rp0 => "RP0",
|
||||||
|
FrequencyType::Rpe => "RP1",
|
||||||
|
FrequencyType::Rpn => "RPn",
|
||||||
|
};
|
||||||
|
Some(card_path.join(format!("gt_{infix}_freq_mhz")))
|
||||||
|
}
|
||||||
|
DriverType::Xe => self.first_tile_gt().map(|gt_path| {
|
||||||
|
let prefix = match freq {
|
||||||
|
FrequencyType::Cur => "cur",
|
||||||
|
FrequencyType::Act => "act",
|
||||||
|
FrequencyType::Min => "min",
|
||||||
|
FrequencyType::Max => "max",
|
||||||
|
FrequencyType::Rp0 => "rp0",
|
||||||
|
FrequencyType::Rpe => "rpe",
|
||||||
|
FrequencyType::Rpn => "rpn",
|
||||||
|
};
|
||||||
|
gt_path.join("freq0").join(format!("{prefix}_freq"))
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_throttle_info(&self) -> Option<BTreeMap<String, Vec<String>>> {
|
||||||
|
match self.driver_type {
|
||||||
|
DriverType::I915 => {
|
||||||
|
let mut reasons = BTreeMap::new();
|
||||||
|
|
||||||
|
let card_path = self
|
||||||
|
.common
|
||||||
|
.sysfs_path
|
||||||
|
.parent()
|
||||||
|
.expect("Device has no parent path");
|
||||||
|
let gt_path = card_path.join("gt").join("gt0");
|
||||||
|
let gt_files = fs::read_dir(gt_path).ok()?;
|
||||||
|
for file in gt_files.flatten() {
|
||||||
|
if let Some(name) = file.file_name().to_str() {
|
||||||
|
if let Some(reason) = name.strip_prefix("throttle_reason_") {
|
||||||
|
if reason == "status" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(value) = self.read_file::<i32>(file.path()) {
|
||||||
|
if value != 0 {
|
||||||
|
reasons.insert(reason.to_owned(), vec![]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(reasons)
|
||||||
|
}
|
||||||
|
DriverType::Xe => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum FrequencyType {
|
||||||
|
Cur,
|
||||||
|
Act,
|
||||||
|
Min,
|
||||||
|
Max,
|
||||||
|
Rp0,
|
||||||
|
Rpe,
|
||||||
|
Rpn,
|
||||||
}
|
}
|
||||||
|
1
lact-daemon/src/tests/data/intel/a380-i915/card1/dev
Normal file
1
lact-daemon/src/tests/data/intel/a380-i915/card1/dev
Normal file
@ -0,0 +1 @@
|
|||||||
|
226:1
|
@ -0,0 +1 @@
|
|||||||
|
2.5 GT/s PCIe
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1 @@
|
|||||||
|
25637161804
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
603
|
@ -0,0 +1 @@
|
|||||||
|
i915
|
@ -0,0 +1 @@
|
|||||||
|
auto
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
unsupported
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
55000000
|
@ -0,0 +1 @@
|
|||||||
|
28000
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
55000
|
@ -0,0 +1,6 @@
|
|||||||
|
DRIVER=i915
|
||||||
|
PCI_CLASS=30000
|
||||||
|
PCI_ID=8086:56A5
|
||||||
|
PCI_SUBSYS_ID=1849:6004
|
||||||
|
PCI_SLOT_NAME=0000:0b:00.0
|
||||||
|
MODALIAS=pci:v00008086d000056A5sv00001849sd00006004bc03sc00i00
|
@ -0,0 +1 @@
|
|||||||
|
0x8086
|
1
lact-daemon/src/tests/data/intel/a380-i915/card1/error
Normal file
1
lact-daemon/src/tests/data/intel/a380-i915/card1/error
Normal file
@ -0,0 +1 @@
|
|||||||
|
No error state collected
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
300
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
1400
|
@ -0,0 +1 @@
|
|||||||
|
1400
|
@ -0,0 +1 @@
|
|||||||
|
128
|
@ -0,0 +1 @@
|
|||||||
|
0.00390625
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1 @@
|
|||||||
|
6534
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
300
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
300
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
0
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
300
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
600
|
@ -0,0 +1 @@
|
|||||||
|
2450
|
@ -0,0 +1 @@
|
|||||||
|
300
|
4
lact-daemon/src/tests/data/intel/a380-i915/card1/uevent
Normal file
4
lact-daemon/src/tests/data/intel/a380-i915/card1/uevent
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
MAJOR=226
|
||||||
|
MINOR=1
|
||||||
|
DEVNAME=dri/card1
|
||||||
|
DEVTYPE=drm_minor
|
@ -0,0 +1,92 @@
|
|||||||
|
---
|
||||||
|
source: lact-daemon/src/tests/mod.rs
|
||||||
|
expression: device_info
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"clocks_info": {
|
||||||
|
"table": {
|
||||||
|
"type": "intel",
|
||||||
|
"value": {
|
||||||
|
"gt_freq": [
|
||||||
|
300,
|
||||||
|
2450
|
||||||
|
],
|
||||||
|
"rp0_freq": 2450,
|
||||||
|
"rpe_freq": 600,
|
||||||
|
"rpn_freq": 300
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"driver": "i915",
|
||||||
|
"drm_info": {
|
||||||
|
"vram_clock_ratio": 1.0
|
||||||
|
},
|
||||||
|
"link_info": {},
|
||||||
|
"pci_info": {
|
||||||
|
"device_pci_info": {
|
||||||
|
"model": "DG2 [Arc A380]",
|
||||||
|
"model_id": "56A5",
|
||||||
|
"vendor": "Intel Corporation",
|
||||||
|
"vendor_id": "8086"
|
||||||
|
},
|
||||||
|
"subsystem_pci_info": {
|
||||||
|
"model_id": "6004",
|
||||||
|
"vendor": "ASRock Incorporation",
|
||||||
|
"vendor_id": "1849"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"vulkan_info": {
|
||||||
|
"api_version": "",
|
||||||
|
"device_name": "",
|
||||||
|
"driver": {
|
||||||
|
"version": 0
|
||||||
|
},
|
||||||
|
"enabled_layers": [],
|
||||||
|
"extensions": {},
|
||||||
|
"features": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pci_info": {
|
||||||
|
"device_pci_info": {
|
||||||
|
"model": "DG2 [Arc A380]",
|
||||||
|
"model_id": "56A5",
|
||||||
|
"vendor": "Intel Corporation",
|
||||||
|
"vendor_id": "8086"
|
||||||
|
},
|
||||||
|
"subsystem_pci_info": {
|
||||||
|
"model_id": "6004",
|
||||||
|
"vendor": "ASRock Incorporation",
|
||||||
|
"vendor_id": "1849"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"power_profile_modes": null,
|
||||||
|
"stats": {
|
||||||
|
"clockspeed": {
|
||||||
|
"current_gfxclk": 600,
|
||||||
|
"gpu_clockspeed": 600
|
||||||
|
},
|
||||||
|
"fan": {
|
||||||
|
"control_enabled": false,
|
||||||
|
"pmfw_info": {}
|
||||||
|
},
|
||||||
|
"power": {
|
||||||
|
"cap_current": 55.0,
|
||||||
|
"cap_default": 55.0,
|
||||||
|
"cap_max": 110.0,
|
||||||
|
"cap_min": 0.0,
|
||||||
|
"current": 0.0
|
||||||
|
},
|
||||||
|
"temps": {
|
||||||
|
"gpu": {
|
||||||
|
"crit": null,
|
||||||
|
"crit_hyst": null,
|
||||||
|
"current": 55.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"voltage": {
|
||||||
|
"gpu": 603
|
||||||
|
},
|
||||||
|
"vram": {}
|
||||||
|
}
|
||||||
|
}
|
@ -70,7 +70,9 @@ expression: device_info
|
|||||||
"control_enabled": false,
|
"control_enabled": false,
|
||||||
"pmfw_info": {}
|
"pmfw_info": {}
|
||||||
},
|
},
|
||||||
"power": {},
|
"power": {
|
||||||
|
"cap_min": 0.0
|
||||||
|
},
|
||||||
"temps": {},
|
"temps": {},
|
||||||
"voltage": {},
|
"voltage": {},
|
||||||
"vram": {}
|
"vram": {}
|
||||||
|
@ -70,7 +70,9 @@ expression: device_info
|
|||||||
"control_enabled": false,
|
"control_enabled": false,
|
||||||
"pmfw_info": {}
|
"pmfw_info": {}
|
||||||
},
|
},
|
||||||
"power": {},
|
"power": {
|
||||||
|
"cap_min": 0.0
|
||||||
|
},
|
||||||
"temps": {},
|
"temps": {},
|
||||||
"voltage": {},
|
"voltage": {},
|
||||||
"vram": {}
|
"vram": {}
|
||||||
|
@ -169,14 +169,14 @@ fn format_clockspeed(value: Option<u64>, ratio: f64) -> String {
|
|||||||
format!("{:.3} GHz", value.unwrap_or(0) as f64 / 1000.0 * ratio)
|
format!("{:.3} GHz", value.unwrap_or(0) as f64 / 1000.0 * ratio)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_current_gfxclk(value: Option<u16>) -> String {
|
fn format_current_gfxclk(value: Option<u64>) -> String {
|
||||||
if let Some(v) = value {
|
if let Some(v) = value {
|
||||||
// if the APU/GPU dose not acually support current_gfxclk,
|
// if the APU/GPU dose not acually support current_gfxclk,
|
||||||
// the value will be `u16::MAX (65535)`
|
// the value will be `u16::MAX (65535)`
|
||||||
if v == u16::MAX {
|
if v >= u16::MAX as u64 || v == 0 {
|
||||||
"N/A".to_string()
|
"N/A".to_string()
|
||||||
} else {
|
} else {
|
||||||
format_clockspeed(Some(v as u64), 1.0)
|
format_clockspeed(Some(v), 1.0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"N/A".to_string()
|
"N/A".to_string()
|
||||||
|
@ -89,6 +89,10 @@ mod imp {
|
|||||||
let text = format!("{}/{} W", section.current_value(), section.max_value());
|
let text = format!("{}/{} W", section.current_value(), section.max_value());
|
||||||
section.set_value_text(text);
|
section.set_value_text(text);
|
||||||
});
|
});
|
||||||
|
obj.connect_max_value_notify(move |section| {
|
||||||
|
let text = format!("{}/{} W", section.current_value(), section.max_value());
|
||||||
|
section.set_value_text(text);
|
||||||
|
});
|
||||||
|
|
||||||
self.reset_button.connect_clicked(clone!(
|
self.reset_button.connect_clicked(clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
|
@ -169,13 +169,13 @@ pub struct NvidiaClocksTable {
|
|||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct IntelClocksTable {
|
pub struct IntelClocksTable {
|
||||||
pub gt_freq: Option<(u32, u32)>,
|
pub gt_freq: Option<(u64, u64)>,
|
||||||
/// - rpn_freq: The Render Performance (RP) N level, which is the minimal one.
|
/// - rpn_freq: The Render Performance (RP) N level, which is the minimal one.
|
||||||
pub rpn_freq: Option<u32>,
|
pub rpn_freq: Option<u64>,
|
||||||
/// - rpe_freq: The Render Performance (RP) E level, which is the efficient one.
|
/// - rpe_freq: The Render Performance (RP) E level, which is the efficient one.
|
||||||
pub rpe_freq: Option<u32>,
|
pub rpe_freq: Option<u64>,
|
||||||
/// - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one.
|
/// - rp0_freq: The Render Performance (RP) 0 level, which is the maximum one.
|
||||||
pub rp0_freq: Option<u32>,
|
pub rp0_freq: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
|
||||||
@ -288,7 +288,7 @@ pub struct PmfwInfo {
|
|||||||
pub struct ClockspeedStats {
|
pub struct ClockspeedStats {
|
||||||
pub gpu_clockspeed: Option<u64>,
|
pub gpu_clockspeed: Option<u64>,
|
||||||
/// Target clock
|
/// Target clock
|
||||||
pub current_gfxclk: Option<u16>,
|
pub current_gfxclk: Option<u64>,
|
||||||
pub vram_clockspeed: Option<u64>,
|
pub vram_clockspeed: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user