11
runccgroup "github.com/opencontainers/runc/libcontainer/cgroups"
13
"github.com/containers/common/pkg/cgroups"
14
"github.com/containers/podman/v5/libpod/define"
15
"golang.org/x/sys/unix"
22
func (c *Container) getPlatformContainerStats(stats *define.ContainerStats, previousStats *define.ContainerStats) error {
23
if c.config.NoCgroups {
24
return fmt.Errorf("cannot run top on container %s as it did not create a cgroup: %w", c.ID(), define.ErrNoCgroups)
27
cgroupPath, err := c.cGroupPath()
31
cgroup, err := cgroups.Load(cgroupPath)
33
return fmt.Errorf("unable to load cgroup at %s: %w", cgroupPath, err)
37
cgroupStats, err := cgroup.Stat()
39
return fmt.Errorf("unable to obtain cgroup stats: %w", err)
41
conState := c.state.State
45
if previousStats.Duration > cgroupStats.CpuStats.CpuUsage.TotalUsage {
46
previousStats = &define.ContainerStats{}
49
previousCPU := previousStats.CPUNano
50
now := uint64(time.Now().UnixNano())
51
stats.Duration = cgroupStats.CpuStats.CpuUsage.TotalUsage
52
stats.UpTime = time.Duration(stats.Duration)
53
stats.CPU = calculateCPUPercent(cgroupStats, previousCPU, now, previousStats.SystemNano)
55
stats.AvgCPU = calculateCPUPercent(cgroupStats, 0, now, uint64(c.state.StartedTime.UnixNano()))
56
stats.MemUsage = cgroupStats.MemoryStats.Usage.Usage
57
stats.MemLimit = c.getMemLimit(cgroupStats.MemoryStats.Usage.Limit)
58
stats.MemPerc = (float64(stats.MemUsage) / float64(stats.MemLimit)) * 100
60
if conState == define.ContainerStateRunning || conState == define.ContainerStatePaused {
61
stats.PIDs = cgroupStats.PidsStats.Current
63
stats.BlockInput, stats.BlockOutput = calculateBlockIO(cgroupStats)
64
stats.CPUNano = cgroupStats.CpuStats.CpuUsage.TotalUsage
65
stats.CPUSystemNano = cgroupStats.CpuStats.CpuUsage.UsageInKernelmode
66
stats.SystemNano = now
67
stats.PerCPU = cgroupStats.CpuStats.CpuUsage.PercpuUsage
73
func (c *Container) getMemLimit(memLimit uint64) uint64 {
74
si := &syscall.Sysinfo_t{}
75
err := syscall.Sysinfo(si)
81
physicalLimit := uint64(si.Totalram)
83
if memLimit <= 0 || memLimit > physicalLimit {
96
func calculateCPUPercent(stats *runccgroup.Stats, previousCPU, now, previousSystem uint64) float64 {
99
cpuDelta = float64(stats.CpuStats.CpuUsage.TotalUsage - previousCPU)
100
systemDelta = float64(now - previousSystem)
102
if systemDelta > 0.0 && cpuDelta > 0.0 {
104
cpuPercent = (cpuDelta / systemDelta) * 100
109
func calculateBlockIO(stats *runccgroup.Stats) (read uint64, write uint64) {
110
for _, blkIOEntry := range stats.BlkioStats.IoServiceBytesRecursive {
111
switch strings.ToLower(blkIOEntry.Op) {
113
read += blkIOEntry.Value
115
write += blkIOEntry.Value
121
func getOnlineCPUs(container *Container) (int, error) {
122
ctrPID, err := container.PID()
124
return -1, fmt.Errorf("failed to obtain Container %s PID: %w", container.Name(), err)
127
return ctrPID, define.ErrCtrStopped
129
var cpuSet unix.CPUSet
130
if err := unix.SchedGetaffinity(ctrPID, &cpuSet); err != nil {
131
return -1, fmt.Errorf("failed to obtain Container %s online cpus: %w", container.Name(), err)
133
return cpuSet.Count(), nil