diff --git a/libpod/stats_common.go b/libpod/stats_common.go index 122160bdaf..402bff4336 100644 --- a/libpod/stats_common.go +++ b/libpod/stats_common.go @@ -47,3 +47,8 @@ func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*de } return stats, nil } + +// GetOnlineCPUs returns the number of online CPUs as set in the container cpu-set using sched_getaffinity +func GetOnlineCPUs(container *Container) (int, error) { + return getOnlineCPUs(container) +} diff --git a/libpod/stats_freebsd.go b/libpod/stats_freebsd.go index e2ec9516cf..4ddd8098fd 100644 --- a/libpod/stats_freebsd.go +++ b/libpod/stats_freebsd.go @@ -147,3 +147,7 @@ func calculateBlockIO(stats *cgroups.Metrics) (read uint64, write uint64) { } return } + +func getOnlineCPUs(container *Container) (int, error) { + return 0, nil +} diff --git a/libpod/stats_linux.go b/libpod/stats_linux.go index e84d85c33f..5d09c3524e 100644 --- a/libpod/stats_linux.go +++ b/libpod/stats_linux.go @@ -13,6 +13,7 @@ import ( "github.com/containers/common/pkg/cgroups" "github.com/containers/podman/v4/libpod/define" + "golang.org/x/sys/unix" ) // getPlatformContainerStats gets the platform-specific running stats @@ -129,3 +130,18 @@ func calculateBlockIO(stats *runccgroup.Stats) (read uint64, write uint64) { } return } + +func getOnlineCPUs(container *Container) (int, error) { + ctrPID, err := container.PID() + if err != nil { + return -1, fmt.Errorf("failed to obtain Container %s PID: %w", container.Name(), err) + } + if ctrPID == 0 { + return ctrPID, define.ErrCtrStopped + } + var cpuSet unix.CPUSet + if err := unix.SchedGetaffinity(ctrPID, &cpuSet); err != nil { + return -1, fmt.Errorf("failed to obtain Container %s online cpus: %w", container.Name(), err) + } + return cpuSet.Count(), nil +} diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go index 223f8f2ac8..f997464331 100644 --- a/pkg/api/handlers/compat/containers_stats.go +++ b/pkg/api/handlers/compat/containers_stats.go @@ -80,6 +80,11 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) { ThrottlingData: docker.ThrottlingData{}, } } + onlineCPUs, err := libpod.GetOnlineCPUs(ctnr) + if err != nil { + utils.InternalServerError(w, err) + return + } streamLabel: // A label to flatten the scope select { @@ -178,7 +183,7 @@ streamLabel: // A label to flatten the scope }, CPU: stats.CPU, SystemUsage: systemUsage, - OnlineCPUs: uint32(len(cgroupStat.CpuStats.CpuUsage.PercpuUsage)), + OnlineCPUs: uint32(onlineCPUs), ThrottlingData: docker.ThrottlingData{ Periods: 0, ThrottledPeriods: 0, diff --git a/test/apiv2/19-stats.at b/test/apiv2/19-stats.at new file mode 100644 index 0000000000..8d8a9ef590 --- /dev/null +++ b/test/apiv2/19-stats.at @@ -0,0 +1,11 @@ +# -*- sh -*- +# +# test 'stats' endpoints +# + +if root; then + podman run -dt --name container1 --cpuset-cpus=0 $IMAGE top &>/dev/null + + # regression for https://github.com/containers/podman/issues/15754 + t GET libpod/containers/container1/stats?stream=false 200 .cpu_stats.online_cpus=1 +fi