feat: hwmon monitoring on xe

This commit is contained in:
Ilya Zlobintsev 2025-01-11 22:26:04 +02:00
parent 9af6887a63
commit 204dcb47fc
136 changed files with 285 additions and 23 deletions

1
Cargo.lock generated
View File

@ -1519,7 +1519,6 @@ dependencies = [
"os-release", "os-release",
"pciid-parser", "pciid-parser",
"pretty_assertions", "pretty_assertions",
"regex",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",

View File

@ -44,7 +44,6 @@ tar = "0.4.40"
libflate = "2.0.0" libflate = "2.0.0"
os-release = "0.1.0" os-release = "0.1.0"
notify = { version = "6.1.1", default-features = false } notify = { version = "6.1.1", default-features = false }
regex = "1.11.0"
copes = { git = "https://gitlab.com/corectrl/copes" } copes = { git = "https://gitlab.com/corectrl/copes" }
libloading = "0.8.6" libloading = "0.8.6"

View File

@ -167,7 +167,7 @@ impl GpuController for IntelGpuController {
} }
if let Some(cap) = config.power_cap { if let Some(cap) = config.power_cap {
self.write_hwmon_file("power1_max", &((cap * 1_000_000.0) as u64).to_string()) self.write_hwmon_file("power", "_max", &((cap * 1_000_000.0) as u64).to_string())
.context("Could not set power cap")?; .context("Could not set power cap")?;
} }
@ -189,7 +189,7 @@ impl GpuController for IntelGpuController {
}; };
let cap_current = self let cap_current = self
.read_hwmon_file("power1_max") .read_hwmon_file("power", "_max")
.map(|value: f64| value / 1_000_000.0) .map(|value: f64| value / 1_000_000.0)
.map(|cap| if cap == 0.0 { 100.0 } else { cap }); // Placeholder max value .map(|cap| if cap == 0.0 { 100.0 } else { cap }); // Placeholder max value
@ -199,7 +199,7 @@ impl GpuController for IntelGpuController {
cap_current, cap_current,
cap_min: Some(0.0), cap_min: Some(0.0),
cap_max: self cap_max: self
.read_hwmon_file::<f64>("power1_rated_max") .read_hwmon_file::<f64>("power", "_rated_max")
.filter(|max| *max != 0.0) .filter(|max| *max != 0.0)
.map(|cap| cap / 1_000_000.0) .map(|cap| cap / 1_000_000.0)
.or_else(|| cap_current.map(|current| current * 2.0)), .or_else(|| cap_current.map(|current| current * 2.0)),
@ -207,7 +207,7 @@ impl GpuController for IntelGpuController {
}; };
let voltage = VoltageStats { let voltage = VoltageStats {
gpu: self.read_hwmon_file("in0_input"), gpu: self.read_hwmon_file("in", "_input"),
northbridge: None, northbridge: None,
}; };
@ -219,7 +219,7 @@ impl GpuController for IntelGpuController {
}; };
let fan = FanStats { let fan = FanStats {
speed_current: self.read_hwmon_file("fan1_input"), speed_current: self.read_hwmon_file("fan", "_input"),
..Default::default() ..Default::default()
}; };
@ -344,22 +344,43 @@ impl IntelGpuController {
} }
} }
fn read_hwmon_file<T>(&self, file_name: &str) -> Option<T> fn read_hwmon_file<T>(&self, file_prefix: &str, file_suffix: &str) -> Option<T>
where where
T: FromStr, T: FromStr,
T::Err: Display, T::Err: Display,
{ {
self.hwmon_path.as_ref().and_then(|hwmon_path| { self.hwmon_path.as_ref().and_then(|hwmon_path| {
let file_path = hwmon_path.join(file_name); let entries = fs::read_dir(hwmon_path).ok()?;
self.read_file(file_path) for entry in entries.flatten() {
if let Some(name) = entry.file_name().to_str() {
if name.starts_with(file_prefix) && name.ends_with(file_suffix) {
return self.read_file(entry.path());
}
}
}
None
}) })
} }
fn write_hwmon_file(&self, file_name: &str, contents: &str) -> anyhow::Result<()> { fn write_hwmon_file(
debug!("writing value '{contents}' to '{file_name}'"); &self,
file_prefix: &str,
file_suffix: &str,
contents: &str,
) -> anyhow::Result<()> {
debug!("writing value '{contents}' to '{file_prefix}*{file_suffix}'");
if let Some(hwmon_path) = &self.hwmon_path { if let Some(hwmon_path) = &self.hwmon_path {
let file_path = hwmon_path.join(file_name); let entries = fs::read_dir(hwmon_path)?;
self.write_file(file_path, contents) for entry in entries.flatten() {
if let Some(name) = entry.file_name().to_str() {
if name.starts_with(file_prefix) && name.ends_with(file_suffix) {
return self.write_file(entry.path(), contents);
}
}
}
Err(anyhow!("File not found"))
} else { } else {
Err(anyhow!("No hwmon available")) Err(anyhow!("No hwmon available"))
} }
@ -453,9 +474,9 @@ impl IntelGpuController {
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)] #[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
fn get_power_usage(&self) -> Option<f64> { fn get_power_usage(&self) -> Option<f64> {
self.read_hwmon_file::<u64>("power1_input") self.read_hwmon_file::<u64>("power", "_input")
.or_else(|| { .or_else(|| {
let energy = self.read_hwmon_file("energy1_input")?; let energy = self.read_hwmon_file("energy", "_input")?;
let timestamp = Instant::now(); let timestamp = Instant::now();
match self.last_energy_value.replace(Some((timestamp, energy))) { match self.last_energy_value.replace(Some((timestamp, energy))) {
@ -472,7 +493,7 @@ impl IntelGpuController {
} }
fn get_temperatures(&self) -> HashMap<String, Temperature> { fn get_temperatures(&self) -> HashMap<String, Temperature> {
self.read_hwmon_file::<f32>("temp1_input") self.read_hwmon_file::<f32>("temp", "_input")
.into_iter() .into_iter()
.map(|temp| { .map(|temp| {
let key = "gpu".to_owned(); let key = "gpu".to_owned();
@ -531,10 +552,10 @@ impl IntelGpuController {
} }
fn get_throttle_info(&self) -> Option<BTreeMap<String, Vec<String>>> { fn get_throttle_info(&self) -> Option<BTreeMap<String, Vec<String>>> {
match self.driver_type {
DriverType::I915 => {
let mut reasons = BTreeMap::new(); let mut reasons = BTreeMap::new();
match self.driver_type {
DriverType::I915 => {
let card_path = self let card_path = self
.common .common
.sysfs_path .sysfs_path
@ -557,12 +578,28 @@ impl IntelGpuController {
} }
} }
} }
}
DriverType::Xe => {
if let Some(tile) = self.first_tile_gt() {
let path = self.common.sysfs_path.join(tile).join("freq0/throttle");
let throttle_files = fs::read_dir(path).ok()?;
for file in throttle_files.flatten() {
if let Some(name) = file.file_name().to_str() {
if let Some(reason) = name.strip_prefix("reason_") {
if let Some(value) = self.read_file::<i32>(file.path()) {
if value != 0 {
reasons.insert(reason.to_owned(), vec![]);
}
}
}
}
}
}
}
}
Some(reasons) Some(reasons)
} }
DriverType::Xe => None,
}
}
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]

View File

@ -0,0 +1 @@
226:0

View File

@ -0,0 +1 @@
2.5 GT/s PCIe

Some files were not shown because too many files have changed in this diff Show More