From 27f8f69195369e5b9e1200c8dfa57335ec3d83e8 Mon Sep 17 00:00:00 2001 From: Alex Man Date: Mon, 9 Sep 2024 16:33:35 -0700 Subject: [PATCH] shim: Fix memory usage reporting for cgroup v2 kata-shim was not reporting `inactive_file` in memory stat. This memory is deducted by containerd when calculating the size of container working set, as it can be paged out by the operating system under memory pressure. Without reporting `inactive_file`, containerd will over report container memory usage. [Here](https://github.com/containerd/containerd/blob/v1.7.22/pkg/cri/server/container_stats_list_linux.go#L117) is where containerd deducts `inactive_file` from memory usage. Note that kata-shim correctly reports `total_inactive_file` for cgroup v1, but this was not implemented for cgroup v2. This commit: - Adds code in kata-shim to report "inactive_file" memory for cgroup v2 - Implements reporting of all available cgroup v2 memory stats to containerd - Uses defensive coding to avoid assuming existence of any memory.stat fields The list of available cgroup v2 memory stats defined by containerd can be found [here](https://pkg.go.dev/github.com/containerd/cgroups/v2/stats#MemoryStat). Fixes #10280 Signed-off-by: Alex Man --- src/runtime/pkg/containerd-shim-v2/metrics.go | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/runtime/pkg/containerd-shim-v2/metrics.go b/src/runtime/pkg/containerd-shim-v2/metrics.go index eeac8fd30..509360167 100644 --- a/src/runtime/pkg/containerd-shim-v2/metrics.go +++ b/src/runtime/pkg/containerd-shim-v2/metrics.go @@ -209,6 +209,7 @@ func setMemoryStatsV1(vcMemory vc.MemoryStats) *cgroupsv1.MemoryStat { return memoryStats } +// nolint: gocyclo func setMemoryStatsV2(vcMemory vc.MemoryStats) *cgroupsv2.MemoryStat { memoryStats := &cgroupsv2.MemoryStat{ Usage: vcMemory.Usage.Usage, @@ -217,6 +218,112 @@ func setMemoryStatsV2(vcMemory vc.MemoryStats) *cgroupsv2.MemoryStat { SwapLimit: vcMemory.SwapUsage.Limit, } + if v, ok := vcMemory.Stats["anon"]; ok { + memoryStats.Anon = v + } + if v, ok := vcMemory.Stats["file"]; ok { + memoryStats.File = v + } + if v, ok := vcMemory.Stats["kernel_stack"]; ok { + memoryStats.KernelStack = v + } + if v, ok := vcMemory.Stats["slab"]; ok { + memoryStats.Slab = v + } + if v, ok := vcMemory.Stats["sock"]; ok { + memoryStats.Sock = v + } + if v, ok := vcMemory.Stats["shmem"]; ok { + memoryStats.Shmem = v + } + if v, ok := vcMemory.Stats["file_mapped"]; ok { + memoryStats.FileMapped = v + } + if v, ok := vcMemory.Stats["file_dirty"]; ok { + memoryStats.FileDirty = v + } + if v, ok := vcMemory.Stats["file_writeback"]; ok { + memoryStats.FileWriteback = v + } + if v, ok := vcMemory.Stats["anon_thp"]; ok { + memoryStats.AnonThp = v + } + if v, ok := vcMemory.Stats["inactive_anon"]; ok { + memoryStats.InactiveAnon = v + } + if v, ok := vcMemory.Stats["active_anon"]; ok { + memoryStats.ActiveAnon = v + } + if v, ok := vcMemory.Stats["inactive_file"]; ok { + memoryStats.InactiveFile = v + } + if v, ok := vcMemory.Stats["active_file"]; ok { + memoryStats.ActiveFile = v + } + if v, ok := vcMemory.Stats["unevictable"]; ok { + memoryStats.Unevictable = v + } + if v, ok := vcMemory.Stats["slab_reclaimable"]; ok { + memoryStats.SlabReclaimable = v + } + if v, ok := vcMemory.Stats["slab_unreclaimable"]; ok { + memoryStats.SlabUnreclaimable = v + } + if v, ok := vcMemory.Stats["pgfault"]; ok { + memoryStats.Pgfault = v + } + if v, ok := vcMemory.Stats["pgmajfault"]; ok { + memoryStats.Pgmajfault = v + } + if v, ok := vcMemory.Stats["workingset_refault"]; ok { + memoryStats.WorkingsetRefault = v + } + if v, ok := vcMemory.Stats["workingset_activate"]; ok { + memoryStats.WorkingsetActivate = v + } + if v, ok := vcMemory.Stats["workingset_nodereclaim"]; ok { + memoryStats.WorkingsetNodereclaim = v + } + if v, ok := vcMemory.Stats["pgrefill"]; ok { + memoryStats.Pgrefill = v + } + if v, ok := vcMemory.Stats["pgscan"]; ok { + memoryStats.Pgscan = v + } + if v, ok := vcMemory.Stats["pgsteal"]; ok { + memoryStats.Pgsteal = v + } + if v, ok := vcMemory.Stats["pgactivate"]; ok { + memoryStats.Pgactivate = v + } + if v, ok := vcMemory.Stats["pgdeactivate"]; ok { + memoryStats.Pgdeactivate = v + } + if v, ok := vcMemory.Stats["pglazyfree"]; ok { + memoryStats.Pglazyfree = v + } + if v, ok := vcMemory.Stats["pglazyfreed"]; ok { + memoryStats.Pglazyfreed = v + } + if v, ok := vcMemory.Stats["thp_fault_alloc"]; ok { + memoryStats.ThpFaultAlloc = v + } + if v, ok := vcMemory.Stats["thp_collapse_alloc"]; ok { + memoryStats.ThpCollapseAlloc = v + } + if v, ok := vcMemory.Stats["usage"]; ok { + memoryStats.Usage = v + } + if v, ok := vcMemory.Stats["usage_limit"]; ok { + memoryStats.UsageLimit = v + } + if v, ok := vcMemory.Stats["swap_usage"]; ok { + memoryStats.SwapUsage = v + } + if v, ok := vcMemory.Stats["swap_limit"]; ok { + memoryStats.SwapLimit = v + } + return memoryStats }