您的问题的答案不在于 cgroups。请参考以下几点:
func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
var (
cpuPercent = 0.0
// calculate the change for the cpu usage of the container in between readings
cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)
// calculate the change for the entire system between readings
systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)
)
if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
}
return cpuPercent
}
- Docker stats API 的“system_cpu_usage”是指主机的 CPU 使用率。
- Docker stats API 的“cpu_usage”>“total_usage”指的是容器的每个 CPU 的使用情况。
- 因此,在计算 (cpuDelta/systemDelta) 之后,我们得到每个系统 CPU 的每个 CPU 使用率。
- 现在我们需要将第 3 步的结果与分配给 docker 容器的 CPU 总数相乘,得到每个系统 CPU 的总 CPU 使用率。
- 第 4 步的结果乘以 100 后得出的 CPU 利用率百分比。
回到问题:
docker是如何计算系统CPU的?
要计算系统 CPU 使用率,docker 使用 POSIX 定义的“/proc/stat”。它查找 CPU 统计信息行,然后总结提供的前七个字段。下面提到了为执行所需步骤而编写的 golang 代码。
https://github.com/rancher/docker/blob/3f1b16e236ad4626e02f3da4643023454d7dbb3f/daemon/stats_collector_unix.go#L137
// getSystemCPUUsage returns the host system's cpu usage in
// nanoseconds. An error is returned if the format of the underlying
// file does not match.
//
// Uses /proc/stat defined by POSIX. Looks for the cpu
// statistics line and then sums up the first seven fields
// provided. See `man 5 proc` for details on specific field
// information.
func (s *statsCollector) getSystemCPUUsage() (uint64, error) {
var line string
f, err := os.Open("/proc/stat")
if err != nil {
return 0, err
}
defer func() {
s.bufReader.Reset(nil)
f.Close()
}()
s.bufReader.Reset(f)
err = nil
for err == nil {
line, err = s.bufReader.ReadString('\n')
if err != nil {
break
}
parts := strings.Fields(line)
switch parts[0] {
case "cpu":
if len(parts) < 8 {
return 0, derr.ErrorCodeBadCPUFields
}
var totalClockTicks uint64
for _, i := range parts[1:8] {
v, err := strconv.ParseUint(i, 10, 64)
if err != nil {
return 0, derr.ErrorCodeBadCPUInt.WithArgs(i, err)
}
totalClockTicks += v
}
return (totalClockTicks * nanoSecondsPerSecond) /
s.clockTicksPerSecond, nil
}
}
return 0, derr.ErrorCodeBadStatFormat
}
请将 docker stats API 的“system_cpu_usage”与以下命令的输出相匹配以确认:
cat /proc/stat|grep -w cpu|awk '{split($0,a,\" \"); sum=0; for(i=2;i<8;i++)(sum+=a[i])} END{print sum }'