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.CPUNano = cgroupStats.CPU.Usage.Total
stats.CPUSystemNano = cgroupStats.CPU.Usage.Kernel
stats.SystemNano = now
stats.PerCPU = cgroupStats.CPU.Usage.PerCPU
// Handle case where the container is not in a network namespace
if netStats != nil {
stats.NetInput = netStats.TxBytes

View File

@ -2,17 +2,19 @@ package libpod
// ContainerStats contains the statistics information for a running container
type ContainerStats struct {
ContainerID string
Name string
CPU float64
CPUNano uint64
SystemNano uint64
MemUsage uint64
MemLimit uint64
MemPerc float64
NetInput uint64
NetOutput uint64
BlockInput uint64
BlockOutput uint64
PIDs uint64
ContainerID string
Name string
PerCPU []uint64
CPU float64
CPUNano uint64
CPUSystemNano uint64
SystemNano uint64
MemUsage uint64
MemLimit uint64
MemPerc float64
NetInput uint64
NetOutput uint64
BlockInput uint64
BlockOutput uint64
PIDs uint64
}

View File

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

View File

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