use crate::helpers::syscall;
use crate::libproc::bindings::proc_pid_rusage;
use libc::c_void;
use std::{io, mem::MaybeUninit};
pub trait PIDRUsage {
fn flavor() -> PidRUsageFlavor;
fn memory_used(&self) -> u64;
fn set_memory_used(&mut self, used: u64);
}
pub enum PidRUsageFlavor {
V0 = 0,
V1 = 1,
V2 = 2,
V3 = 3,
V4 = 4,
}
#[repr(C)]
#[derive(Default)]
pub struct RUsageInfoV0 {
pub ri_uuid: [u8; 16],
pub ri_user_time: u64,
pub ri_system_time: u64,
pub ri_pkg_idle_wkups: u64,
pub ri_interrupt_wkups: u64,
pub ri_pageins: u64,
pub ri_wired_size: u64,
pub ri_resident_size: u64,
pub ri_phys_footprint: u64,
pub ri_proc_start_abstime: u64,
pub ri_proc_exit_abstime: u64,
}
impl PIDRUsage for RUsageInfoV0 {
fn flavor() -> PidRUsageFlavor {
PidRUsageFlavor::V0
}
fn memory_used(&self) -> u64 {
self.ri_resident_size
}
fn set_memory_used(&mut self, used: u64) {
self.ri_resident_size = used;
}
}
#[repr(C)]
#[derive(Default)]
pub struct RUsageInfoV1 {
pub ri_uuid: [u8; 16],
pub ri_user_time: u64,
pub ri_system_time: u64,
pub ri_pkg_idle_wkups: u64,
pub ri_interrupt_wkups: u64,
pub ri_pageins: u64,
pub ri_wired_size: u64,
pub ri_resident_size: u64,
pub ri_phys_footprint: u64,
pub ri_proc_start_abstime: u64,
pub ri_proc_exit_abstime: u64,
pub ri_child_user_time: u64,
pub ri_child_system_time: u64,
pub ri_child_pkg_idle_wkups: u64,
pub ri_child_interrupt_wkups: u64,
pub ri_child_pageins: u64,
pub ri_child_elapsed_abstime: u64,
}
impl PIDRUsage for RUsageInfoV1 {
fn flavor() -> PidRUsageFlavor {
PidRUsageFlavor::V1
}
fn memory_used(&self) -> u64 {
self.ri_resident_size
}
fn set_memory_used(&mut self, used: u64) {
self.ri_resident_size = used;
}
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct RUsageInfoV2 {
pub ri_uuid: [u8; 16],
pub ri_user_time: u64,
pub ri_system_time: u64,
pub ri_pkg_idle_wkups: u64,
pub ri_interrupt_wkups: u64,
pub ri_pageins: u64,
pub ri_wired_size: u64,
pub ri_resident_size: u64,
pub ri_phys_footprint: u64,
pub ri_proc_start_abstime: u64,
pub ri_proc_exit_abstime: u64,
pub ri_child_user_time: u64,
pub ri_child_system_time: u64,
pub ri_child_pkg_idle_wkups: u64,
pub ri_child_interrupt_wkups: u64,
pub ri_child_pageins: u64,
pub ri_child_elapsed_abstime: u64,
pub ri_diskio_bytesread: u64,
pub ri_diskio_byteswritten: u64,
}
impl PIDRUsage for RUsageInfoV2 {
fn flavor() -> PidRUsageFlavor {
PidRUsageFlavor::V2
}
fn memory_used(&self) -> u64 {
self.ri_resident_size
}
fn set_memory_used(&mut self, used: u64) {
self.ri_resident_size = used;
}
}
#[repr(C)]
#[derive(Default)]
pub struct RUsageInfoV3 {
pub ri_uuid: [u8; 16],
pub ri_user_time: u64,
pub ri_system_time: u64,
pub ri_pkg_idle_wkups: u64,
pub ri_interrupt_wkups: u64,
pub ri_pageins: u64,
pub ri_wired_size: u64,
pub ri_resident_size: u64,
pub ri_phys_footprint: u64,
pub ri_proc_start_abstime: u64,
pub ri_proc_exit_abstime: u64,
pub ri_child_user_time: u64,
pub ri_child_system_time: u64,
pub ri_child_pkg_idle_wkups: u64,
pub ri_child_interrupt_wkups: u64,
pub ri_child_pageins: u64,
pub ri_child_elapsed_abstime: u64,
pub ri_diskio_bytesread: u64,
pub ri_diskio_byteswritten: u64,
pub ri_cpu_time_qos_default: u64,
pub ri_cpu_time_qos_maintenance: u64,
pub ri_cpu_time_qos_background: u64,
pub ri_cpu_time_qos_utility: u64,
pub ri_cpu_time_qos_legacy: u64,
pub ri_cpu_time_qos_user_initiated: u64,
pub ri_cpu_time_qos_user_interactive: u64,
pub ri_billed_system_time: u64,
pub ri_serviced_system_time: u64,
}
impl PIDRUsage for RUsageInfoV3 {
fn flavor() -> PidRUsageFlavor {
PidRUsageFlavor::V3
}
fn memory_used(&self) -> u64 {
self.ri_resident_size
}
fn set_memory_used(&mut self, used: u64) {
self.ri_resident_size = used;
}
}
#[repr(C)]
#[derive(Default)]
pub struct RUsageInfoV4 {
pub ri_uuid: [u8; 16],
pub ri_user_time: u64,
pub ri_system_time: u64,
pub ri_pkg_idle_wkups: u64,
pub ri_interrupt_wkups: u64,
pub ri_pageins: u64,
pub ri_wired_size: u64,
pub ri_resident_size: u64,
pub ri_phys_footprint: u64,
pub ri_proc_start_abstime: u64,
pub ri_proc_exit_abstime: u64,
pub ri_child_user_time: u64,
pub ri_child_system_time: u64,
pub ri_child_pkg_idle_wkups: u64,
pub ri_child_interrupt_wkups: u64,
pub ri_child_pageins: u64,
pub ri_child_elapsed_abstime: u64,
pub ri_diskio_bytesread: u64,
pub ri_diskio_byteswritten: u64,
pub ri_cpu_time_qos_default: u64,
pub ri_cpu_time_qos_maintenance: u64,
pub ri_cpu_time_qos_background: u64,
pub ri_cpu_time_qos_utility: u64,
pub ri_cpu_time_qos_legacy: u64,
pub ri_cpu_time_qos_user_initiated: u64,
pub ri_cpu_time_qos_user_interactive: u64,
pub ri_billed_system_time: u64,
pub ri_serviced_system_time: u64,
pub ri_logical_writes: u64,
pub ri_lifetime_max_phys_footprint: u64,
pub ri_instructions: u64,
pub ri_cycles: u64,
pub ri_billed_energy: u64,
pub ri_serviced_energy: u64,
pub ri_interval_max_phys_footprint: u64,
pub ri_unused: [u64; 1],
}
impl PIDRUsage for RUsageInfoV4 {
fn flavor() -> PidRUsageFlavor {
PidRUsageFlavor::V4
}
fn memory_used(&self) -> u64 {
self.ri_resident_size
}
fn set_memory_used(&mut self, used: u64) {
self.ri_resident_size = used;
}
}
#[cfg(target_os = "macos")]
pub fn pidrusage<T: PIDRUsage>(pid: i32) -> Result<T, io::Error> {
let flavor = T::flavor() as i32;
let mut pidrusage = MaybeUninit::<T>::uninit();
#[allow(clippy::pedantic)]
let buffer_ptr = &mut pidrusage as *mut _ as *mut c_void;
syscall::cvt_nonnegative(unsafe { proc_pid_rusage(pid, flavor, buffer_ptr.cast()) })?;
Ok(unsafe { pidrusage.assume_init() })
}
#[cfg(test)]
#[allow(clippy::cast_possible_wrap)]
mod test {
use super::pidrusage;
use crate::libproc::pid_rusage::RUsageInfoV0;
#[test]
fn pidrusage_test() {
let usage: RUsageInfoV0 = pidrusage(std::process::id() as i32).expect("pidrusage() failed");
assert!(usage.ri_resident_size > 0, "Resident size reports 0");
}
}