diff options
author | Will Chandler <wchandler@gitlab.com> | 2023-11-09 23:03:07 +0300 |
---|---|---|
committer | Will Chandler <wchandler@gitlab.com> | 2023-11-11 00:30:52 +0300 |
commit | da3e644d31df21ca28654499a4927f280c93ce86 (patch) | |
tree | ab35867d3141bacc4c068e98d1e24c25515c219c | |
parent | 8539b2d10ff41ac9256b8f8c8610d59d6d9fb155 (diff) |
cgroups: Add stats method
Add the `stats()` method to `genericHandler`. We use reflection here as
the stats collected vary significantly between v1 and v2.
-rw-r--r-- | internal/cgroups/handler_linux.go | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/internal/cgroups/handler_linux.go b/internal/cgroups/handler_linux.go index 6af06d332..5f1784377 100644 --- a/internal/cgroups/handler_linux.go +++ b/internal/cgroups/handler_linux.go @@ -3,9 +3,11 @@ package cgroups import ( + "errors" "fmt" "path/filepath" "strings" + "time" "github.com/containerd/cgroups/v3/cgroup1" "github.com/containerd/cgroups/v3/cgroup2" @@ -166,3 +168,59 @@ func (cvh *genericHandler[T, H]) repoPath(groupID int) string { func (cvh *genericHandler[T, H]) supportsCloneIntoCgroup() bool { return cvh.supportsClone } + +func (cvh *genericHandler[T, H]) stats() (Stats, error) { + processCgroupPath := cvh.currentProcessCgroup() + + control, err := cvh.loadFunc(cvh.hierarchy, processCgroupPath) + if err != nil { + return Stats{}, err + } + + switch c := any(control).(type) { + case cgroup1.Cgroup: + return v1Stats(c, processCgroupPath) + case *cgroup2.Manager: + return v2stats(c, processCgroupPath) + default: + return Stats{}, errors.New("unknown cgroup type") + } +} + +func v1Stats(control cgroup1.Cgroup, processCgroupPath string) (Stats, error) { + metrics, err := control.Stat() + if err != nil { + return Stats{}, fmt.Errorf("failed to fetch metrics %s: %w", processCgroupPath, err) + } + + return Stats{ + ParentStats: CgroupStats{ + CPUThrottledCount: metrics.CPU.Throttling.ThrottledPeriods, + CPUThrottledDuration: float64(metrics.CPU.Throttling.ThrottledTime) / float64(time.Second), + MemoryUsage: metrics.Memory.Usage.Usage, + MemoryLimit: metrics.Memory.Usage.Limit, + OOMKills: metrics.MemoryOomControl.OomKill, + UnderOOM: metrics.MemoryOomControl.UnderOom != 0, + }, + }, nil +} + +func v2stats(control *cgroup2.Manager, processCgroupPath string) (Stats, error) { + metrics, err := control.Stat() + if err != nil { + return Stats{}, fmt.Errorf("failed to fetch metrics %s: %w", processCgroupPath, err) + } + + stats := Stats{ + ParentStats: CgroupStats{ + CPUThrottledCount: metrics.CPU.NrThrottled, + CPUThrottledDuration: float64(metrics.CPU.ThrottledUsec) / float64(time.Second), + MemoryUsage: metrics.Memory.Usage, + MemoryLimit: metrics.Memory.UsageLimit, + }, + } + if metrics.MemoryEvents != nil { + stats.ParentStats.OOMKills = metrics.MemoryEvents.OomKill + } + return stats, nil +} |