mirror of
https://github.com/ClementTsang/bottom.git
synced 2026-08-23 03:46:29 +00:00
bug: fix cgroups v1 swap collection around sentinel max value (#2195)
Problem was that with cgroups v1, if the swap had an unlimited value set, it would be done by just setting a huge integer, which would break things.
This commit is contained in:
+2
-1
@@ -20,11 +20,12 @@ That said, these are more guidelines rather than hard rules, though the project
|
||||
|
||||
---
|
||||
|
||||
## 0.14.8/0.15.0 - Unreleased
|
||||
## 0.14.8 - 2026-08-13
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [2191](https://github.com/ClementTsang/bottom/pull/2191): Fix close logic when pressing enter in sort menu.
|
||||
- [2195](https://github.com/ClementTsang/bottom/pull/2195): Fix cgroups v1 swap collection around sentinel max value.
|
||||
|
||||
## 0.14.7 - 2026-07-27
|
||||
|
||||
|
||||
+5
-1
@@ -381,7 +381,11 @@ impl DataCollector {
|
||||
self.refresh_sysinfo_data();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
self.cgroup_memory_data.refresh();
|
||||
{
|
||||
let total_memory = self.sys.system.total_memory();
|
||||
let total_swap = self.sys.system.total_swap();
|
||||
self.cgroup_memory_data.refresh(total_memory, total_swap);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
self.cgroup_cpu_data.refresh();
|
||||
|
||||
@@ -44,19 +44,32 @@ pub(crate) struct CgroupMemCollector {
|
||||
pub swap: Option<CgroupMemData>,
|
||||
}
|
||||
|
||||
/// Computes the cgroup v1 swap limit. Calculated by getting memsw and subtracting the memory limits.
|
||||
#[inline]
|
||||
fn cgroup_v1_swap_limit(
|
||||
memsw_limit: u64, mem_limit: Option<u64>, total_memory: u64, total_swap: u64,
|
||||
) -> u64 {
|
||||
let effective_memsw_limit = memsw_limit.min(total_memory + total_swap);
|
||||
let effective_mem_limit = mem_limit.map_or(0, |mem_limit| mem_limit.min(total_memory));
|
||||
|
||||
effective_memsw_limit.saturating_sub(effective_mem_limit)
|
||||
}
|
||||
|
||||
impl CgroupMemCollector {
|
||||
/// Refresh the cgroup memory data.
|
||||
///
|
||||
/// Based on [docker's CLI](https://github.com/docker/cli/blob/master/cli/command/container/stats_helpers.go#L254).
|
||||
pub(crate) fn refresh(&mut self) {
|
||||
if !self.try_update_memory_cgroup_v1() && !self.try_update_memory_cgroup_v2() {
|
||||
pub(crate) fn refresh(&mut self, total_memory: u64, total_swap: u64) {
|
||||
if !self.try_update_memory_cgroup_v1(total_memory, total_swap)
|
||||
&& !self.try_update_memory_cgroup_v2()
|
||||
{
|
||||
self.ram = None;
|
||||
self.swap = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Try and update the memory using cgroup v1 semantics. If successful, returns `true`.
|
||||
fn try_update_memory_cgroup_v1(&mut self) -> bool {
|
||||
fn try_update_memory_cgroup_v1(&mut self, total_memory: u64, total_swap: u64) -> bool {
|
||||
if let Some(mem_usage) = read_u64("/sys/fs/cgroup/memory/memory.usage_in_bytes") {
|
||||
// --- Memory ---
|
||||
let inactive =
|
||||
@@ -66,8 +79,8 @@ impl CgroupMemCollector {
|
||||
_ => mem_usage,
|
||||
};
|
||||
|
||||
// Technically if it's like, some insanely high value (https://unix.stackexchange.com/a/421182)
|
||||
// then it's "unlimited" but we can just make it so we take the max of the main and this anyway.
|
||||
// Technically if it's some insanely high value (https://unix.stackexchange.com/a/421182),
|
||||
// then it's "unlimited", but we can just make it so we take the max of the main and this anyway.
|
||||
let mem_limit_raw = read_u64("/sys/fs/cgroup/memory/memory.limit_in_bytes");
|
||||
let mem_limit = mem_limit_raw.map(CgroupMemLimit::Bytes);
|
||||
|
||||
@@ -78,12 +91,15 @@ impl CgroupMemCollector {
|
||||
|
||||
// --- Swap ---
|
||||
// Since swap is dependent on the normal memory usage, we couple it together.
|
||||
if let Some(memsw) = read_u64("/sys/fs/cgroup/memory/memory.memsw.usage_in_bytes") {
|
||||
let used_bytes = memsw.saturating_sub(mem_usage);
|
||||
if let Some(memsw_usage) = read_u64("/sys/fs/cgroup/memory/memory.memsw.usage_in_bytes")
|
||||
{
|
||||
let used_bytes = memsw_usage.saturating_sub(mem_usage);
|
||||
|
||||
// Same idea for here.
|
||||
let swap_limit = read_u64("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes")
|
||||
.map(|memsw_limit| memsw_limit.saturating_sub(mem_limit_raw.unwrap_or(0)))
|
||||
.map(|memsw_limit| {
|
||||
cgroup_v1_swap_limit(memsw_limit, mem_limit_raw, total_memory, total_swap)
|
||||
})
|
||||
.map(CgroupMemLimit::Bytes);
|
||||
|
||||
self.swap = Some(CgroupMemData {
|
||||
|
||||
Reference in New Issue
Block a user