use std::time::Instant;
use nvml_wrapper::{enum_wrappers::device::TemperatureSensor, Nvml};
use systemstat::Platform;
use super::system::{DiskInformation, SystemInformation};
#[derive(Debug, Clone, Copy)]
pub enum SystemPollerTarget {
CpuUsage,
CpuTemperature,
Gpu,
Memory,
}
#[derive(Debug, Clone)]
pub struct SystemPollResult {
pub cpu_usage: Vec<Measurement>,
pub cpu_temperature: Measurement,
pub memory_usage: Measurement,
pub gpu_info: Vec<GpuPollResult>,
}
impl Default for SystemPollResult {
fn default() -> Self {
SystemPollResult {
cpu_usage: vec![Measurement::default(); 0],
cpu_temperature: Measurement::default(),
memory_usage: Measurement::default(),
gpu_info: vec![],
}
}
}
#[derive(Clone, Debug)]
pub struct GpuPollResult {
pub name: String,
pub temp: f32,
pub usage: f32,
pub memory_total: u64,
pub memory_used: u64,
}
impl Default for GpuPollResult {
fn default() -> Self {
GpuPollResult {
name: "???".to_string(),
temp: 0f32,
usage: 0f32,
memory_total: 0u64,
memory_used: 0u64,
}
}
}
pub struct SystemPoller {
sysinfo_system: sysinfo::System,
systemstat_system: systemstat::System,
nvml: Option<Nvml>,
target_flags: Vec<SystemPollerTarget>,
}
impl Default for SystemPoller {
fn default() -> Self {
Self::new()
}
}
impl SystemPoller {
pub fn new() -> Self {
let mut sysinfo_system = sysinfo::System::new_all();
sysinfo_system.refresh_all();
SystemPoller {
sysinfo_system,
systemstat_system: systemstat::System::new(),
nvml: match Nvml::init() {
Ok(nvml) => Some(nvml),
Err(_) => None,
},
target_flags: vec![],
}
}
pub fn with_poll_targets(mut self, targets: Vec<SystemPollerTarget>) -> Self {
self.target_flags = targets;
self
}
pub fn poll(&mut self) -> SystemPollResult {
let mut res = SystemPollResult::default();
let time = TimePoint(Instant::now());
for k in self.target_flags.as_slice() {
match k {
SystemPollerTarget::CpuUsage => {
self.sysinfo_system.refresh_cpu();
for cpu in self.sysinfo_system.cpus() {
res.cpu_usage.push(Measurement {
name: cpu.name().to_owned(),
value: cpu.cpu_usage(),
time,
});
}
}
SystemPollerTarget::CpuTemperature => {
res.cpu_temperature = Measurement {
time,
name: "".into(),
value: self.systemstat_system.cpu_temp().unwrap_or(0f32),
};
}
SystemPollerTarget::Gpu => res.gpu_info = self.poll_gpus(),
SystemPollerTarget::Memory => {
self.sysinfo_system.refresh_memory();
res.memory_usage = Measurement {
time,
name: "memory".to_string(),
value: self.sysinfo_system.used_memory() as f32,
}
}
}
}
res
}
pub fn get_system_info(&mut self) -> SystemInformation {
self.poll();
SystemInformation {
os: sysinfo::System::name().unwrap_or_else(|| "".to_owned()),
kernel_version: sysinfo::System::kernel_version().unwrap_or_else(|| "".to_owned()),
os_version: sysinfo::System::os_version().unwrap_or_else(|| "".to_owned()),
host_name: sysinfo::System::host_name().unwrap_or_else(|| "".to_owned()),
logical_processors: self.sysinfo_system.cpus().len(),
physical_processors: self.sysinfo_system.physical_core_count().unwrap_or(0),
total_memory: self.sysinfo_system.total_memory(),
}
}
pub fn get_disk_info(&mut self) -> Vec<DiskInformation> {
let mut disks = Vec::<DiskInformation>::new();
for disk in &sysinfo::Disks::new_with_refreshed_list() {
disks.push(DiskInformation {
name: disk.name().to_string_lossy().to_string(),
kind: match disk.kind() {
sysinfo::DiskKind::SSD => "SSD".to_string(),
sysinfo::DiskKind::HDD => "HDD".to_string(),
sysinfo::DiskKind::Unknown(s) => format!("??? ({})", s),
},
available_space: disk.total_space() - disk.available_space(),
total_space: disk.total_space(),
});
}
disks
}
fn poll_gpus(&self) -> Vec<GpuPollResult> {
match &self.nvml {
None => vec![],
Some(nvml) => {
let mut gpus = Vec::<GpuPollResult>::new();
gpus.reserve(nvml.device_count().unwrap() as usize);
for i in 0..nvml.device_count().unwrap() {
let device = nvml.device_by_index(i).unwrap();
let memory_info = device.memory_info();
gpus.push(GpuPollResult {
name: match device.name() {
Ok(n) => n,
Err(e) => e.to_string(),
},
temp: match device.temperature(TemperatureSensor::Gpu) {
Ok(t) => t as f32,
Err(_) => 0f32,
},
usage: match device.utilization_rates() {
Ok(r) => r.gpu as f32,
Err(_) => 0f32,
},
memory_total: match &memory_info {
Ok(m) => m.total,
Err(_) => 0,
},
memory_used: match memory_info {
Ok(m) => m.used,
Err(_) => 0,
},
})
}
gpus
}
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct TimePoint(pub Instant);
#[derive(Clone, Debug)]
pub struct Measurement {
pub name: String,
pub time: TimePoint,
pub value: f32,
}
impl Default for TimePoint {
fn default() -> Self {
TimePoint(Instant::now())
}
}
impl Default for Measurement {
fn default() -> Self {
Measurement {
name: String::default(),
time: TimePoint::default(),
value: 0 as f32,
}
}
}