use std::time::Duration;
use cpu_time::ProcessTime;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(crate) struct OwnReading {
pub(crate) cpu_permille: u64,
pub(crate) private_bytes: u64,
pub(crate) working_set_bytes: u64,
pub(crate) read_bytes: u64,
pub(crate) written_bytes: u64,
}
pub(crate) struct OwnProcess {
previous: Option<Duration>,
}
impl OwnProcess {
pub(crate) fn new() -> Self {
Self { previous: None }
}
pub(crate) fn read(&mut self, elapsed: Duration) -> OwnReading {
let cpu = ProcessTime::try_now().ok().map(|time| time.as_duration());
let cpu_permille = match (cpu, self.previous) {
(Some(spent), Some(spent_before)) => {
permille(spent.saturating_sub(spent_before), elapsed)
}
(Some(_) | None, None) | (None, Some(_)) => 0,
};
self.previous = cpu;
let memory = memory_stats::memory_stats();
let storage = storage_bytes();
OwnReading {
cpu_permille,
private_bytes: memory.map_or(0, |stats| widen(stats.virtual_mem)),
working_set_bytes: memory.map_or(0, |stats| widen(stats.physical_mem)),
read_bytes: storage.read,
written_bytes: storage.written,
}
}
}
#[derive(Default)]
struct StorageBytes {
read: u64,
written: u64,
}
#[cfg(target_os = "linux")]
fn storage_bytes() -> StorageBytes {
let Ok(io) = std::fs::read_to_string("/proc/self/io") else {
return StorageBytes::default();
};
let field = |name: &str| {
io.lines()
.find_map(|line| line.strip_prefix(name))
.and_then(|value| value.trim().parse().ok())
.unwrap_or(0)
};
StorageBytes {
read: field("read_bytes:"),
written: field("write_bytes:"),
}
}
#[cfg(not(target_os = "linux"))]
fn storage_bytes() -> StorageBytes {
StorageBytes::default()
}
fn permille(spent: Duration, elapsed: Duration) -> u64 {
let cores = std::thread::available_parallelism().map_or(1, std::num::NonZero::get);
let capacity = elapsed
.as_nanos()
.saturating_mul(u128::try_from(cores).unwrap_or(u128::MAX));
spent
.as_nanos()
.saturating_mul(1000)
.checked_div(capacity)
.map_or(0, |share| u64::try_from(share.min(1000)).unwrap_or(1000))
}
fn widen(bytes: usize) -> u64 {
u64::try_from(bytes).unwrap_or(u64::MAX)
}
#[cfg(test)]
#[path = "own_process/tests.rs"]
mod tests;