use errno::Errno;
use thiserror::Error;
#[derive(Error, Debug)]
#[error("ProcessMemoryInfoError({code}):{msg}")]
pub struct ProcessMemoryInfoError {
pub code: i32,
pub msg: String,
}
impl From<Errno> for ProcessMemoryInfoError {
fn from(e: Errno) -> Self {
Self {
code: e.into(),
msg: e.to_string(),
}
}
}
#[derive(Clone, Default)]
pub struct ProcessMemoryInfo {
pub resident_set_size: u64,
pub resident_set_size_peak: u64,
pub virtual_memory_size: u64,
#[cfg(target_os = "macos")]
pub phys_footprint: u64,
#[cfg(target_os = "macos")]
pub compressed: u64,
}
#[cfg(target_os = "windows")]
fn get_process_memory_info_impl() -> Result<ProcessMemoryInfo, ProcessMemoryInfoError> {
use winapi::um::{
processthreadsapi::GetCurrentProcess,
psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
};
let mut process_memory_counters = PROCESS_MEMORY_COUNTERS {
cb: 0,
PageFaultCount: 0,
PeakWorkingSetSize: 0,
WorkingSetSize: 0,
QuotaPeakPagedPoolUsage: 0,
QuotaPagedPoolUsage: 0,
QuotaPeakNonPagedPoolUsage: 0,
QuotaNonPagedPoolUsage: 0,
PagefileUsage: 0,
PeakPagefileUsage: 0,
};
let ret = unsafe {
GetProcessMemoryInfo(
GetCurrentProcess(),
&mut process_memory_counters,
std::mem::size_of::<PROCESS_MEMORY_COUNTERS>() as u32,
)
};
if ret != 0 {
Ok(ProcessMemoryInfo {
resident_set_size: process_memory_counters.WorkingSetSize as u64,
resident_set_size_peak: process_memory_counters.PeakWorkingSetSize as u64,
virtual_memory_size: process_memory_counters.PagefileUsage as u64,
})
} else {
Err(errno::errno().into())
}
}
#[cfg(target_os = "macos")]
fn get_process_memory_info_impl() -> Result<ProcessMemoryInfo, ProcessMemoryInfoError> {
use mach::{
kern_return::KERN_SUCCESS, message::mach_msg_type_number_t, task_info::TASK_VM_INFO,
vm_types::natural_t,
};
use crate::bindings::task_vm_info as TaskVMInfo;
use mach::{task::task_info, traps::mach_task_self};
let mut task_vm_info = TaskVMInfo::default();
let task_vm_info_ptr = (&mut task_vm_info) as *mut TaskVMInfo;
let mut task_info_cnt: mach_msg_type_number_t = (std::mem::size_of::<TaskVMInfo>()
/ std::mem::size_of::<natural_t>())
as mach_msg_type_number_t;
let kern_ret = unsafe {
task_info(
mach_task_self(),
TASK_VM_INFO,
task_vm_info_ptr.cast::<i32>(),
&mut task_info_cnt,
)
};
if kern_ret == KERN_SUCCESS {
Ok(ProcessMemoryInfo {
resident_set_size: task_vm_info.resident_size,
resident_set_size_peak: task_vm_info.resident_size_peak,
virtual_memory_size: task_vm_info.virtual_size,
phys_footprint: task_vm_info.phys_footprint,
compressed: task_vm_info.compressed,
})
} else {
Err(ProcessMemoryInfoError {
code: kern_ret,
msg: format!("DARWIN_KERN_RET_CODE:{}", kern_ret),
})
}
}
pub fn get_process_memory_info() -> Result<ProcessMemoryInfo, ProcessMemoryInfoError> {
get_process_memory_info_impl()
}