Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions cgroupv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,59 @@ func (s cgroupV2Statter) memoryMaxBytes() (*float64, error) {
return ptr.To(float64(maxUsageBytes)), nil
}

func (s cgroupV2Statter) memory(p Prefix) (*Result, error) {
func (s cgroupV2Statter) memoryCurrentBytes() (int64, error) {
memoryUsagePath := filepath.Join(s.path, cgroupV2MemoryUsageBytes)

currUsageBytes, err := readInt64(s.fs, memoryUsagePath)
if err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return 0, xerrors.Errorf("read memory current: %w", err)
}

// If the memory current file does not exist, and we have a parent,
// we shall call the parent to find its current memory value.
if s.parent != nil {
result, err := s.parent.memoryCurrentBytes()
if err != nil {
return 0, xerrors.Errorf("read parent memory current: %w", err)
}
return result, nil
}

// We have no parent, and no memory current file, so return the error.
return 0, xerrors.Errorf("read memory current: %w", err)
}

return currUsageBytes, nil
}

func (s cgroupV2Statter) memoryInactiveFileBytes() (int64, error) {
memoryStatPath := filepath.Join(s.path, cgroupV2MemoryStat)

inactiveFileBytes, err := readInt64Prefix(s.fs, memoryStatPath, "inactive_file")
if err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return 0, xerrors.Errorf("read memory stat inactive_file: %w", err)
}

// If the memory stat file does not exist, and we have a parent,
// we shall call the parent to find its inactive_file value.
if s.parent != nil {
result, err := s.parent.memoryInactiveFileBytes()
if err != nil {
return 0, xerrors.Errorf("read parent memory stat inactive_file: %w", err)
}
return result, nil
}

// We have no parent, and no memory stat file, so return the error.
return 0, xerrors.Errorf("read memory stat inactive_file: %w", err)
}

return inactiveFileBytes, nil
}

func (s cgroupV2Statter) memory(p Prefix) (*Result, error) {
// https://docs.kernel.org/6.17/admin-guide/cgroup-v2.html#memory-interface-files
r := &Result{
Unit: "B",
Expand All @@ -194,12 +243,12 @@ func (s cgroupV2Statter) memory(p Prefix) (*Result, error) {
r.Total = total
}

currUsageBytes, err := readInt64(s.fs, memoryUsagePath)
currUsageBytes, err := s.memoryCurrentBytes()
if err != nil {
return nil, xerrors.Errorf("read memory usage: %w", err)
}

inactiveFileBytes, err := readInt64Prefix(s.fs, memoryStatPath, "inactive_file")
inactiveFileBytes, err := s.memoryInactiveFileBytes()
if err != nil {
return nil, xerrors.Errorf("read memory stats: %w", err)
}
Expand Down
60 changes: 60 additions & 0 deletions stat_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,36 @@ func TestStatter(t *testing.T) {
assert.Nil(t, mem.Total)
assert.Equal(t, "B", mem.Unit)
})

t.Run("Memory/CurrentInParent", func(t *testing.T) {
t.Parallel()

fs := initFS(t, fsContainerCgroupV2KubernetesMissingMemoryCurrent)
s, err := New(WithFS(fs), withNoWait, withIsCgroupV2(true))
require.NoError(t, err)

mem, err := s.ContainerMemory(PrefixDefault)
require.NoError(t, err)

require.NotNil(t, mem)
assert.Equal(t, 268435456.0, mem.Used)
assert.Equal(t, "B", mem.Unit)
})

t.Run("Memory/StatInParent", func(t *testing.T) {
t.Parallel()

fs := initFS(t, fsContainerCgroupV2KubernetesMissingMemoryStat)
s, err := New(WithFS(fs), withNoWait, withIsCgroupV2(true))
require.NoError(t, err)

mem, err := s.ContainerMemory(PrefixDefault)
require.NoError(t, err)

require.NotNil(t, mem)
assert.Equal(t, 268435456.0, mem.Used)
assert.Equal(t, "B", mem.Unit)
})
})
})
}
Expand Down Expand Up @@ -805,6 +835,36 @@ sysboxfs /proc/sys sysboxfs rw,nosuid,nodev,noexec,relatime 0 0`,
filepath.Join(cgroupRootPath, "init.scope", cgroupV2MemoryStat): "inactive_file 268435456",
filepath.Join(cgroupRootPath, "init.scope", cgroupV2MemoryUsageBytes): "536870912",
}
// Variant where child has memory.stat but NOT memory.current (should inherit from root)
fsContainerCgroupV2KubernetesMissingMemoryCurrent = map[string]string{
procOneCgroup: "0::/",
procSelfCgroup: fmt.Sprintf("0::%s", fsContainerCgroupV2KubernetesPath),
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
sysCgroupType: "domain",

filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2CPUMax): "max 100000",
filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2CPUStat): "usage_usec 0",
filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2MemoryMaxBytes): "max",
filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2MemoryStat): "inactive_file 268435456",
// memory.current purposefully missing at child - should inherit from root
filepath.Join(cgroupRootPath, cgroupV2MemoryUsageBytes): "536870912",
}
// Variant where child has memory.current but NOT memory.stat (should inherit from root)
fsContainerCgroupV2KubernetesMissingMemoryStat = map[string]string{
procOneCgroup: "0::/",
procSelfCgroup: fmt.Sprintf("0::%s", fsContainerCgroupV2KubernetesPath),
procMounts: `overlay / overlay rw,relatime,lowerdir=/some/path:/some/path,upperdir=/some/path:/some/path,workdir=/some/path:/some/path 0 0
proc /proc/sys proc ro,nosuid,nodev,noexec,relatime 0 0`,
sysCgroupType: "domain",

filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2CPUMax): "max 100000",
filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2CPUStat): "usage_usec 0",
filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2MemoryMaxBytes): "max",
filepath.Join(cgroupRootPath, fsContainerCgroupV2KubernetesPath, cgroupV2MemoryUsageBytes): "536870912",
// memory.stat purposefully missing at child - should inherit from root
filepath.Join(cgroupRootPath, cgroupV2MemoryStat): "inactive_file 268435456",
}
fsContainerCgroupV1 = map[string]string{
procOneCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
procSelfCgroup: "0::/docker/aa86ac98959eeedeae0ecb6e0c9ddd8ae8b97a9d0fdccccf7ea7a474f4e0bb1f",
Expand Down
Loading