mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
fix: Docker container memory now subtracts inactive_file on cgroup v2 systems. Fixes container memory reporting to match 'docker stats' output by excluding reclaimable filesystem cache. Related to #435
This commit is contained in:
@@ -324,7 +324,7 @@ func TestCalculateMemoryUsage(t *testing.T) {
|
||||
wantPercent: 25.0,
|
||||
},
|
||||
{
|
||||
name: "cache larger than usage falls back to raw usage",
|
||||
name: "cache larger than usage keeps raw usage",
|
||||
stats: containertypes.StatsResponse{
|
||||
MemoryStats: containertypes.MemoryStats{
|
||||
Usage: 1000000,
|
||||
@@ -332,10 +332,23 @@ func TestCalculateMemoryUsage(t *testing.T) {
|
||||
Stats: map[string]uint64{"cache": 2000000}, // more than usage
|
||||
},
|
||||
},
|
||||
wantUsage: 1000000, // falls back to raw usage
|
||||
wantUsage: 1000000, // keeps raw usage when cache > usage
|
||||
wantLimit: 4000000,
|
||||
wantPercent: 25.0,
|
||||
},
|
||||
{
|
||||
name: "cgroup v2 uses inactive_file when no cache",
|
||||
stats: containertypes.StatsResponse{
|
||||
MemoryStats: containertypes.MemoryStats{
|
||||
Usage: 1000000,
|
||||
Limit: 4000000,
|
||||
Stats: map[string]uint64{"inactive_file": 300000}, // cgroup v2 style
|
||||
},
|
||||
},
|
||||
wantUsage: 700000, // 1000000 - 300000
|
||||
wantLimit: 4000000,
|
||||
wantPercent: 17.5,
|
||||
},
|
||||
{
|
||||
name: "zero limit returns zero percent",
|
||||
stats: containertypes.StatsResponse{
|
||||
|
||||
@@ -715,11 +715,25 @@ func calculateCPUPercent(stats containertypes.StatsResponse, hostCPUs int) float
|
||||
|
||||
func calculateMemoryUsage(stats containertypes.StatsResponse) (usage int64, limit int64, percent float64) {
|
||||
usage = int64(stats.MemoryStats.Usage)
|
||||
|
||||
// Subtract reclaimable cache from usage to match `docker stats` behavior.
|
||||
// Docker subtracts cache/file to show "actual" memory usage rather than
|
||||
// memory.current which includes reclaimable filesystem cache.
|
||||
//
|
||||
// cgroup v1: "cache" stat contains the reclaimable cache
|
||||
// cgroup v2: "cache" doesn't exist, use "inactive_file" (preferred) or "file"
|
||||
var cacheBytes uint64
|
||||
if cache, ok := stats.MemoryStats.Stats["cache"]; ok {
|
||||
usage -= int64(cache)
|
||||
// cgroup v1
|
||||
cacheBytes = cache
|
||||
} else if inactiveFile, ok := stats.MemoryStats.Stats["inactive_file"]; ok {
|
||||
// cgroup v2: inactive_file is the reclaimable portion of file cache
|
||||
// This matches what docker CLI does internally
|
||||
cacheBytes = inactiveFile
|
||||
}
|
||||
if usage < 0 {
|
||||
usage = int64(stats.MemoryStats.Usage)
|
||||
|
||||
if cacheBytes > 0 && int64(cacheBytes) < usage {
|
||||
usage -= int64(cacheBytes)
|
||||
}
|
||||
|
||||
limit = int64(stats.MemoryStats.Limit)
|
||||
|
||||
Reference in New Issue
Block a user