mirror of
https://github.com/ClementTsang/bottom.git
synced 2026-07-09 06:01:04 +00:00
bug: fix cgroup v1 memory total using sentinel max as total
This commit is contained in:
@@ -4,6 +4,9 @@ use std::num::NonZeroU64;
|
||||
|
||||
use crate::collection::{DataCollector, memory::MemData};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::collection::linux::cgroups::CgroupMemLimit;
|
||||
|
||||
#[inline]
|
||||
fn get_usage(used: u64, total: u64) -> Option<MemData> {
|
||||
NonZeroU64::new(total).map(|total_bytes| MemData {
|
||||
@@ -12,6 +15,20 @@ fn get_usage(used: u64, total: u64) -> Option<MemData> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolves the total memory to report given an optional cgroup limit and the physical total.
|
||||
///
|
||||
/// cgroup v1 reports an "unlimited" limit as a very large value, which causes problems if taken
|
||||
/// literally. This function caps it to the minimum of the cgroup total or the actual total to
|
||||
/// avoid this problem.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
fn resolve_cgroup_total(limit: Option<&CgroupMemLimit>, base_total: u64) -> u64 {
|
||||
match limit {
|
||||
Some(CgroupMemLimit::Bytes(bytes)) => (*bytes).min(base_total),
|
||||
Some(CgroupMemLimit::Max) | None => base_total,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns memory (RAM) usage using sysinfo.
|
||||
///
|
||||
/// On Linux, this will take cgroup usage/limits into account.
|
||||
@@ -20,19 +37,13 @@ pub(crate) fn get_ram_usage(collector: &DataCollector) -> Option<MemData> {
|
||||
|
||||
cfg_select! {
|
||||
target_os = "linux" => {
|
||||
use crate::collection::linux::cgroups;
|
||||
|
||||
let base_used = sys.used_memory();
|
||||
let base_total = sys.total_memory();
|
||||
|
||||
let (used, total) = match &collector.cgroup_memory_data.ram {
|
||||
Some(cgroup_data) => {
|
||||
let used = cgroup_data.used_bytes;
|
||||
let total = match cgroup_data.limit {
|
||||
Some(cgroups::CgroupMemLimit::Bytes(bytes)) => bytes,
|
||||
Some(cgroups::CgroupMemLimit::Max) => base_total,
|
||||
None => base_total,
|
||||
};
|
||||
let total = resolve_cgroup_total(cgroup_data.limit.as_ref(), base_total);
|
||||
|
||||
(used, total)
|
||||
}
|
||||
@@ -56,19 +67,13 @@ pub(crate) fn get_swap_usage(collector: &DataCollector) -> Option<MemData> {
|
||||
|
||||
cfg_select! {
|
||||
target_os = "linux" => {
|
||||
use crate::collection::linux::cgroups;
|
||||
|
||||
let base_used = sys.used_swap();
|
||||
let base_total = sys.total_swap();
|
||||
|
||||
let (used, total) = match &collector.cgroup_memory_data.swap {
|
||||
Some(cgroup_data) => {
|
||||
let used = cgroup_data.used_bytes;
|
||||
let total = match cgroup_data.limit {
|
||||
Some(cgroups::CgroupMemLimit::Bytes(bytes)) => bytes,
|
||||
Some(cgroups::CgroupMemLimit::Max) => base_total,
|
||||
None => base_total,
|
||||
};
|
||||
let total = resolve_cgroup_total(cgroup_data.limit.as_ref(), base_total);
|
||||
|
||||
(used, total)
|
||||
}
|
||||
@@ -101,3 +106,39 @@ pub(crate) fn get_cache_usage(sys: &sysinfo::System) -> Option<MemData> {
|
||||
|
||||
get_usage(mem_used, mem_total)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux_tests {
|
||||
use super::*;
|
||||
|
||||
const BASE_TOTAL: u64 = 16 * 1024 * 1024 * 1024; // 16 GiB
|
||||
|
||||
/// Regression test for <https://github.com/ClementTsang/bottom/issues/2092>.
|
||||
#[test]
|
||||
fn cap_cgroup_v1_limits() {
|
||||
let sentinel = u64::MAX;
|
||||
assert_eq!(
|
||||
resolve_cgroup_total(Some(&CgroupMemLimit::Bytes(sentinel)), BASE_TOTAL),
|
||||
BASE_TOTAL
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legit_cgroup_limit_works() {
|
||||
let limit = 4 * 1024 * 1024 * 1024; // 4 GiB
|
||||
assert_eq!(
|
||||
resolve_cgroup_total(Some(&CgroupMemLimit::Bytes(limit)), BASE_TOTAL),
|
||||
limit
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_and_missing_limit_use_physical_total() {
|
||||
assert_eq!(
|
||||
resolve_cgroup_total(Some(&CgroupMemLimit::Max), BASE_TOTAL),
|
||||
BASE_TOTAL
|
||||
);
|
||||
assert_eq!(resolve_cgroup_total(None, BASE_TOTAL), BASE_TOTAL);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user