#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct RssSample {
pub current_bytes: Option<u64>,
pub peak_bytes: Option<u64>,
}
pub fn sample() -> RssSample {
RssSample {
current_bytes: current_rss(),
peak_bytes: peak_rss(),
}
}
#[cfg(target_os = "macos")]
fn current_rss() -> Option<u64> {
use std::mem;
use mach2::kern_return::KERN_SUCCESS;
use mach2::message::mach_msg_type_number_t;
use mach2::task::task_info;
use mach2::task_info::{MACH_TASK_BASIC_INFO, mach_task_basic_info, task_info_t};
use mach2::traps::mach_task_self;
unsafe {
let mut info = mem::zeroed::<mach_task_basic_info>();
let mut count = (mem::size_of::<mach_task_basic_info>() / mem::size_of::<u32>()) as mach_msg_type_number_t;
let kr = task_info(
mach_task_self(),
MACH_TASK_BASIC_INFO,
(&mut info as *mut mach_task_basic_info).cast::<i32>() as task_info_t,
&mut count,
);
if kr == KERN_SUCCESS {
Some(info.resident_size)
} else {
None
}
}
}
#[cfg(target_os = "linux")]
fn current_rss() -> Option<u64> {
let statm = std::fs::read_to_string("/proc/self/statm").ok()?;
let resident_pages: u64 = statm.split_whitespace().nth(1)?.parse().ok()?;
let page = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
let page = if page > 0 { page as u64 } else { 4096 };
Some(resident_pages.saturating_mul(page))
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
fn current_rss() -> Option<u64> {
None
}
#[cfg(unix)]
fn peak_rss() -> Option<u64> {
use std::mem;
unsafe {
let mut usage: libc::rusage = mem::zeroed();
if libc::getrusage(libc::RUSAGE_SELF, &mut usage) != 0 {
return None;
}
let maxrss = usage.ru_maxrss.max(0) as u64;
#[cfg(target_os = "macos")]
let bytes = maxrss;
#[cfg(not(target_os = "macos"))]
let bytes = maxrss.saturating_mul(1024);
Some(bytes)
}
}
#[cfg(not(unix))]
fn peak_rss() -> Option<u64> {
None
}
#[cfg(all(test, unix))]
mod tests {
use super::*;
#[test]
fn sample_reports_nonzero_rss_on_unix() {
let s = sample();
let current = s.current_bytes.expect("current RSS should be readable on unix");
assert!(current > 0, "current RSS must be positive, got {current}");
let peak = s.peak_bytes.expect("peak RSS should be readable on unix");
assert!(
peak >= current,
"peak RSS ({peak}) should be >= current RSS ({current})"
);
}
}