sync memory and temperatures

This commit is contained in:
Robin Appelman 2021-03-27 23:31:56 +01:00
commit 14817cf422
4 changed files with 80 additions and 40 deletions

View file

@ -1,6 +1,6 @@
use iai::black_box; use iai::black_box;
use palantir::get_metrics; use palantir::get_metrics;
use palantir::heim::temperatures; use palantir::sensors::temperatures;
use palantir::zfs::pools; use palantir::zfs::pools;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
@ -14,8 +14,7 @@ fn iai_zfs_pool() {
} }
fn iai_temperatures() { fn iai_temperatures() {
let rt = Runtime::new().unwrap(); black_box(temperatures()).unwrap();
rt.block_on(async { black_box(temperatures().await).unwrap() });
} }
iai::main!(iai_get_metrics, iai_zfs_pool, iai_temperatures); iai::main!(iai_get_metrics, iai_zfs_pool, iai_temperatures);

View file

@ -1,7 +1,8 @@
pub mod heim; pub mod sensors;
pub mod zfs; pub mod zfs;
use crate::heim::*; use crate::sensors::temperatures;
use crate::sensors::*;
use crate::zfs::pools; use crate::zfs::pools;
use color_eyre::Result; use color_eyre::Result;
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
@ -10,15 +11,15 @@ use std::collections::HashSet;
use std::fmt::Write; use std::fmt::Write;
pub async fn get_metrics() -> Result<String> { pub async fn get_metrics() -> Result<String> {
let (hostname, cpu, memory, network, temperatures, disks, disk_usage) = try_join! { let (hostname, cpu, network, disks, disk_usage) = try_join! {
hostname(), hostname(),
cpu_time(), cpu_time(),
memory(),
network_stats(), network_stats(),
temperatures(),
disk_stats(), disk_stats(),
disk_usage(), disk_usage(),
}?; }?;
let memory = memory()?;
let temperatures = temperatures()?;
let pools = pools(); let pools = pools();
pin_mut!(network); pin_mut!(network);
pin_mut!(disks); pin_mut!(disks);

View file

@ -1,15 +1,16 @@
use color_eyre::eyre::WrapErr;
use color_eyre::Result; use color_eyre::Result;
use futures_util::future; use futures_util::future;
use futures_util::stream::{Stream, StreamExt}; use futures_util::stream::{Stream, StreamExt};
use heim::cpu::time; use heim::cpu::time;
use heim::disk::{FileSystem, Partition}; use heim::disk::{FileSystem, Partition};
use heim::sensors::TemperatureSensor; use heim::units::{information, time};
use heim::units::{information, thermodynamic_temperature, time};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use parse_display::Display; use parse_display::Display;
use regex::Regex; use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::{read, read_dir, read_to_string, DirEntry, File};
use std::io::{BufRead, BufReader};
use std::os::unix::ffi::OsStrExt;
#[derive(Debug, Clone, Hash, Eq, PartialEq, Display)] #[derive(Debug, Clone, Hash, Eq, PartialEq, Display)]
#[display(style = "lowercase")] #[display(style = "lowercase")]
@ -17,7 +18,7 @@ pub enum TemperatureLabel {
CPU, CPU,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Default)]
pub struct Memory { pub struct Memory {
pub total: u64, pub total: u64,
pub free: u64, pub free: u64,
@ -38,36 +39,75 @@ pub struct DiskUsage {
pub free: u64, pub free: u64,
} }
pub async fn temperatures() -> Result<HashMap<TemperatureLabel, f32>> { pub fn temperatures() -> Result<HashMap<TemperatureLabel, f32>> {
// ugly workaround problems between async-fs and tokio Ok(read_dir("/sys/class/hwmon")?
let results = tokio::task::spawn_blocking(|| { .filter_map(Result::ok)
futures_lite::future::block_on( .filter_map(|dir: DirEntry| {
heim::sensors::temperatures().collect::<Vec<Result<TemperatureSensor, heim::Error>>>(), let name = read(dir.path().join("name")).ok()?;
) match name.as_slice() {
}) b"k10temp\n" => Some((name, dir)),
.await
.wrap_err("Failed to resolve future")?
.into_iter()
.filter_map(|result| result.ok())
.filter_map(|sensor| match (sensor.unit(), sensor.label()) {
("k10temp", Some("Tdie")) => Some((
TemperatureLabel::CPU,
sensor
.current()
.get::<thermodynamic_temperature::degree_celsius>(),
)),
_ => None, _ => None,
}); }
Ok(results.collect()) })
.flat_map(|(name, dir)| {
read_dir(dir.path())
.into_iter()
.flat_map(|dir| dir)
.filter_map(Result::ok)
.filter_map(move |item: DirEntry| {
let file_name = item.file_name();
let bytes = file_name.as_bytes();
if bytes.starts_with(b"temp") && bytes.ends_with(b"_label") {
let label = read(item.path()).ok()?;
Some((name.clone(), label, item))
} else {
None
}
})
})
.filter_map(
|(name, label, item)| match (name.as_slice(), label.as_slice()) {
(b"k10temp\n", b"Tdie\n") => Some((TemperatureLabel::CPU, item)),
_ => None,
},
)
.filter_map(|(label, item)| {
let path = item.path().into_os_string();
Some((label, path.into_string().ok()?))
})
.filter_map(|(label, mut path)| {
path.truncate(path.len() - "label".len());
path.push_str("input");
let value = read_to_string(path).ok()?;
let parsed: u32 = value.trim().parse().ok()?;
Some((label, parsed as f32 / 1000.0))
})
.collect())
} }
pub async fn memory() -> Result<Memory> { pub fn memory() -> Result<Memory> {
let memory = heim::memory::memory().await?; let mut meminfo = BufReader::new(File::open("/proc/meminfo")?);
Ok(Memory { let mut mem = Memory::default();
total: memory.total().get::<information::byte>(), let mut line = String::new();
free: memory.free().get::<information::byte>(), loop {
available: memory.available().get::<information::byte>(), line.clear();
}) meminfo.read_line(&mut line)?;
if line.is_empty() {
break;
}
if let Some(line) = line.strip_suffix(" kB") {
if let Some(line_total) = line.strip_prefix("MemTotal: ") {
mem.total = line_total.trim().parse()?;
}
if let Some(line_free) = line.strip_prefix("MemFree: ") {
mem.free = line_free.trim().parse()?;
}
if let Some(line_available) = line.strip_prefix("MemAvailable: ") {
mem.available = line_available.trim().parse()?;
}
}
}
Ok(mem)
} }
pub async fn cpu_time() -> Result<f64> { pub async fn cpu_time() -> Result<f64> {

View file

@ -1,4 +1,4 @@
use crate::heim::DiskUsage; use crate::sensors::DiskUsage;
use color_eyre::Result; use color_eyre::Result;
use std::process::Command; use std::process::Command;