Merge pull request #5172 from giuseppe/api-fix-cpu-stats

api: fix the CPU stats reported
This commit is contained in:
OpenShift Merge Robot
2020-02-13 15:42:53 +01:00
committed by GitHub
5 changed files with 75 additions and 24 deletions

View File

@ -66,7 +66,9 @@ func (c *Container) GetContainerStats(previousStats *ContainerStats) (*Container
} }
stats.BlockInput, stats.BlockOutput = calculateBlockIO(cgroupStats) stats.BlockInput, stats.BlockOutput = calculateBlockIO(cgroupStats)
stats.CPUNano = cgroupStats.CPU.Usage.Total stats.CPUNano = cgroupStats.CPU.Usage.Total
stats.CPUSystemNano = cgroupStats.CPU.Usage.Kernel
stats.SystemNano = now stats.SystemNano = now
stats.PerCPU = cgroupStats.CPU.Usage.PerCPU
// Handle case where the container is not in a network namespace // Handle case where the container is not in a network namespace
if netStats != nil { if netStats != nil {
stats.NetInput = netStats.TxBytes stats.NetInput = netStats.TxBytes

View File

@ -4,8 +4,10 @@ package libpod
type ContainerStats struct { type ContainerStats struct {
ContainerID string ContainerID string
Name string Name string
PerCPU []uint64
CPU float64 CPU float64
CPUNano uint64 CPUNano uint64
CPUSystemNano uint64
SystemNano uint64 SystemNano uint64
MemUsage uint64 MemUsage uint64
MemLimit uint64 MemLimit uint64

View File

@ -61,14 +61,15 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
var preCPUStats docker.CPUStats var preCPUStats docker.CPUStats
if query.Stream { if query.Stream {
preRead = time.Now() preRead = time.Now()
systemUsage, _ := cgroups.GetSystemCPUUsage()
preCPUStats = docker.CPUStats{ preCPUStats = docker.CPUStats{
CPUUsage: docker.CPUUsage{ CPUUsage: docker.CPUUsage{
TotalUsage: stats.CPUNano, TotalUsage: stats.CPUNano,
PercpuUsage: []uint64{uint64(stats.CPU)}, PercpuUsage: stats.PerCPU,
UsageInKernelmode: 0, UsageInKernelmode: stats.CPUSystemNano,
UsageInUsermode: 0, UsageInUsermode: stats.CPUNano - stats.CPUSystemNano,
}, },
SystemUsage: 0, SystemUsage: systemUsage,
OnlineCPUs: 0, OnlineCPUs: 0,
ThrottlingData: docker.ThrottlingData{}, ThrottlingData: docker.ThrottlingData{},
} }
@ -122,6 +123,8 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
InstanceID: "", InstanceID: "",
} }
systemUsage, _ := cgroups.GetSystemCPUUsage()
s := handlers.Stats{StatsJSON: docker.StatsJSON{ s := handlers.Stats{StatsJSON: docker.StatsJSON{
Stats: docker.Stats{ Stats: docker.Stats{
Read: time.Now(), Read: time.Now(),
@ -143,11 +146,11 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
CPUStats: docker.CPUStats{ CPUStats: docker.CPUStats{
CPUUsage: docker.CPUUsage{ CPUUsage: docker.CPUUsage{
TotalUsage: cgroupStat.CPU.Usage.Total, TotalUsage: cgroupStat.CPU.Usage.Total,
PercpuUsage: []uint64{uint64(stats.CPU)}, PercpuUsage: cgroupStat.CPU.Usage.PerCPU,
UsageInKernelmode: cgroupStat.CPU.Usage.Kernel, UsageInKernelmode: cgroupStat.CPU.Usage.Kernel,
UsageInUsermode: cgroupStat.CPU.Usage.Total - cgroupStat.CPU.Usage.Kernel, UsageInUsermode: cgroupStat.CPU.Usage.Total - cgroupStat.CPU.Usage.Kernel,
}, },
SystemUsage: 0, SystemUsage: systemUsage,
OnlineCPUs: uint32(len(cgroupStat.CPU.Usage.PerCPU)), OnlineCPUs: uint32(len(cgroupStat.CPU.Usage.PerCPU)),
ThrottlingData: docker.ThrottlingData{ ThrottlingData: docker.ThrottlingData{
Periods: 0, Periods: 0,

View File

@ -536,15 +536,14 @@ func (c *CgroupControl) Stat() (*Metrics, error) {
return &m, nil return &m, nil
} }
func readCgroup2MapFile(ctr *CgroupControl, name string) (map[string][]string, error) { func readCgroup2MapPath(path string) (map[string][]string, error) {
ret := map[string][]string{} ret := map[string][]string{}
p := filepath.Join(cgroupRoot, ctr.path, name) f, err := os.Open(path)
f, err := os.Open(p)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return ret, nil return ret, nil
} }
return nil, errors.Wrapf(err, "open file %s", p) return nil, errors.Wrapf(err, "open file %s", path)
} }
defer f.Close() defer f.Close()
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
@ -557,7 +556,13 @@ func readCgroup2MapFile(ctr *CgroupControl, name string) (map[string][]string, e
ret[parts[0]] = parts[1:] ret[parts[0]] = parts[1:]
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
return nil, errors.Wrapf(err, "parsing file %s", p) return nil, errors.Wrapf(err, "parsing file %s", path)
} }
return ret, nil return ret, nil
} }
func readCgroup2MapFile(ctr *CgroupControl, name string) (map[string][]string, error) {
p := filepath.Join(cgroupRoot, ctr.path, name)
return readCgroup2MapPath(p)
}

View File

@ -121,3 +121,42 @@ func (c *cpuHandler) Stat(ctr *CgroupControl, m *Metrics) error {
m.CPU = CPUMetrics{Usage: usage} m.CPU = CPUMetrics{Usage: usage}
return nil return nil
} }
// GetSystemCPUUsage returns the system usage for all the cgroups
func GetSystemCPUUsage() (uint64, error) {
cgroupv2, err := IsCgroup2UnifiedMode()
if err != nil {
return 0, err
}
if !cgroupv2 {
p := filepath.Join(cgroupRoot, CPUAcct, "cpuacct.usage")
return readFileAsUint64(p)
}
files, err := ioutil.ReadDir(cgroupRoot)
if err != nil {
return 0, errors.Wrapf(err, "read directory %q", cgroupRoot)
}
var total uint64
for _, file := range files {
if !file.IsDir() {
continue
}
p := filepath.Join(cgroupRoot, file.Name(), "cpu.stat")
values, err := readCgroup2MapPath(p)
if err != nil {
return 0, err
}
if val, found := values["usage_usec"]; found {
v, err := strconv.ParseUint(cleanString(val[0]), 10, 0)
if err != nil {
return 0, err
}
total += v * 1000
}
}
return total, nil
}