pub fn parse_meminfo_available(contents: &str) -> Option<u64> {
for line in contents.lines() {
if let Some(rest) = line.strip_prefix("MemAvailable:") {
let kb: u64 = rest.split_whitespace().next()?.parse().ok()?;
return Some(kb * 1024);
}
}
None
}
pub fn parse_cgroup_v2_memory_max(contents: &str) -> Option<u64> {
let s = contents.trim();
if s.is_empty() || s == "max" {
return None;
}
s.parse().ok()
}
pub fn parse_cgroup_v1_memory_limit(contents: &str) -> Option<u64> {
const IMPLAUSIBLE: u64 = 1 << 62;
let v: u64 = contents.trim().parse().ok()?;
if v >= IMPLAUSIBLE { None } else { Some(v) }
}
pub fn parse_self_cgroup_v2_path(contents: &str) -> Option<String> {
for line in contents.lines() {
if let Some(rest) = line.strip_prefix("0::") {
let p = rest.trim();
if !p.is_empty() {
return Some(p.to_string());
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
const MIB: u64 = 1024 * 1024;
#[test]
fn meminfo_available_is_parsed_from_kilobytes() {
let s = "MemTotal: 65536000 kB\nMemAvailable: 1048576 kB\nCached: 1 kB\n";
assert_eq!(parse_meminfo_available(s), Some(1024 * MIB));
}
#[test]
fn meminfo_without_the_field_yields_none() {
assert_eq!(parse_meminfo_available("MemTotal: 100 kB\n"), None);
assert_eq!(parse_meminfo_available(""), None);
assert_eq!(
parse_meminfo_available("MemAvailable: notanumber kB\n"),
None
);
}
#[test]
fn cgroup_v2_memory_max_is_bytes_and_max_means_unlimited() {
assert_eq!(parse_cgroup_v2_memory_max("536870912\n"), Some(512 * MIB));
assert_eq!(parse_cgroup_v2_memory_max("max\n"), None);
assert_eq!(parse_cgroup_v2_memory_max("garbage"), None);
assert_eq!(parse_cgroup_v2_memory_max(""), None);
}
#[test]
fn cgroup_v1_unlimited_sentinel_yields_none() {
assert_eq!(parse_cgroup_v1_memory_limit("536870912\n"), Some(512 * MIB));
assert_eq!(parse_cgroup_v1_memory_limit("9223372036854771712\n"), None);
assert_eq!(parse_cgroup_v1_memory_limit("-1"), None);
}
#[test]
fn self_cgroup_v2_path_is_the_third_field_of_the_zero_line() {
assert_eq!(
parse_self_cgroup_v2_path("0::/user.slice/user-1000.slice/session-3.scope\n"),
Some("/user.slice/user-1000.slice/session-3.scope".to_string())
);
assert_eq!(parse_self_cgroup_v2_path("12:cpu,cpuacct:/foo\n"), None);
assert_eq!(parse_self_cgroup_v2_path(""), None);
}
}