Skip to main content

resource_sampler/
memory.rs

1// RSS, PSS, swap from smaps_rollup and status. Plan: optional PSS/swap for ProcessInfo.
2
3/// Memory snapshot: RSS (from smaps_rollup), PSS, and swap in KB.
4/// Returns None if files are missing or unreadable (e.g. no permission).
5#[cfg(target_os = "linux")]
6pub fn sample_memory(pid: i32) -> Option<(u64, u64, u64)> {
7    let rss_kb = read_smaps_rollup_field(pid, "Rss")?;
8    let pss_kb = read_smaps_rollup_field(pid, "Pss")?;
9    let swap_kb = read_vmswap_kb(pid).unwrap_or(0);
10    Some((rss_kb, pss_kb, swap_kb))
11}
12
13#[cfg(not(target_os = "linux"))]
14pub fn sample_memory(_pid: i32) -> Option<(u64, u64, u64)> {
15    None
16}
17
18#[cfg(target_os = "linux")]
19fn read_smaps_rollup_field(pid: i32, name: &str) -> Option<u64> {
20    let path = format!("/proc/{}/smaps_rollup", pid);
21    let raw = std::fs::read_to_string(path).ok()?;
22    for line in raw.lines() {
23        let line = line.trim_start();
24        if line.starts_with(name) {
25            // "Pss:  1234 kB" or "Rss:  5678 kB"
26            let rest = line.strip_prefix(name)?.trim_start();
27            let rest = rest.strip_prefix(':')?.trim_start();
28            let num: u64 = rest.split_whitespace().next()?.parse().ok()?;
29            return Some(num);
30        }
31    }
32    None
33}
34
35#[cfg(target_os = "linux")]
36fn read_vmswap_kb(pid: i32) -> Option<u64> {
37    let path = format!("/proc/{}/status", pid);
38    let raw = std::fs::read_to_string(path).ok()?;
39    for line in raw.lines() {
40        if line.starts_with("VmSwap:") {
41            let rest = line.strip_prefix("VmSwap:")?.trim_start();
42            let num: u64 = rest
43                .split_whitespace()
44                .next()?
45                .replace(',', "")
46                .parse()
47                .ok()?;
48            return Some(num);
49        }
50    }
51    Some(0)
52}