diff --git a/cli/command/container/stats_helpers.go b/cli/command/container/stats_helpers.go index 75218f882a..37b1964fd5 100644 --- a/cli/command/container/stats_helpers.go +++ b/cli/command/container/stats_helpers.go @@ -50,15 +50,10 @@ func (s *stats) isKnownContainer(cid string) (int, bool) { } func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, streamStats bool, waitFirst *sync.WaitGroup) { //nolint:gocyclo - var ( - getFirst bool - previousCPU uint64 - previousSystem uint64 - u = make(chan error, 1) - ) + var getFirst bool defer func() { - // if error happens and we get nothing of stats, release wait group whatever + // if error happens, and we get nothing of stats, release wait group whatever if !getFirst { getFirst = true waitFirst.Done() @@ -71,6 +66,7 @@ func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, strea return } + u := make(chan error, 1) go func() { defer response.Body.Close() dec := json.NewDecoder(response.Body) @@ -78,14 +74,7 @@ func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, strea if ctx.Err() != nil { return } - var ( - v *container.StatsResponse - memPercent, cpuPercent float64 - blkRead, blkWrite uint64 // Only used on Linux - mem, memLimit float64 - pidsStatsCurrent uint64 - ) - + var v container.StatsResponse if err := dec.Decode(&v); err != nil { dec = json.NewDecoder(io.MultiReader(dec.Buffered(), response.Body)) u <- err @@ -96,35 +85,36 @@ func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, strea continue } - if daemonOSType != "windows" { - previousCPU = v.PreCPUStats.CPUUsage.TotalUsage - previousSystem = v.PreCPUStats.SystemUsage - cpuPercent = calculateCPUPercentUnix(previousCPU, previousSystem, v) - blkRead, blkWrite = calculateBlockIO(v.BlkioStats) - mem = calculateMemUsageUnixNoCache(v.MemoryStats) - memLimit = float64(v.MemoryStats.Limit) - memPercent = calculateMemPercentUnixNoCache(memLimit, mem) - pidsStatsCurrent = v.PidsStats.Current + if daemonOSType == "windows" { + netRx, netTx := calculateNetwork(v.Networks) + s.SetStatistics(StatsEntry{ + Name: v.Name, + ID: v.ID, + CPUPercentage: calculateCPUPercentWindows(&v), + Memory: float64(v.MemoryStats.PrivateWorkingSet), + NetworkRx: netRx, + NetworkTx: netTx, + BlockRead: float64(v.StorageStats.ReadSizeBytes), + BlockWrite: float64(v.StorageStats.WriteSizeBytes), + }) } else { - cpuPercent = calculateCPUPercentWindows(v) - blkRead = v.StorageStats.ReadSizeBytes - blkWrite = v.StorageStats.WriteSizeBytes - mem = float64(v.MemoryStats.PrivateWorkingSet) + memUsage := calculateMemUsageUnixNoCache(v.MemoryStats) + netRx, netTx := calculateNetwork(v.Networks) + blkRead, blkWrite := calculateBlockIO(v.BlkioStats) + s.SetStatistics(StatsEntry{ + Name: v.Name, + ID: v.ID, + CPUPercentage: calculateCPUPercentUnix(v.PreCPUStats, v.CPUStats), + Memory: memUsage, + MemoryPercentage: calculateMemPercentUnixNoCache(float64(v.MemoryStats.Limit), memUsage), + MemoryLimit: float64(v.MemoryStats.Limit), + NetworkRx: netRx, + NetworkTx: netTx, + BlockRead: float64(blkRead), + BlockWrite: float64(blkWrite), + PidsCurrent: v.PidsStats.Current, + }) } - netRx, netTx := calculateNetwork(v.Networks) - s.SetStatistics(StatsEntry{ - Name: v.Name, - ID: v.ID, - CPUPercentage: cpuPercent, - Memory: mem, - MemoryPercentage: memPercent, - MemoryLimit: memLimit, - NetworkRx: netRx, - NetworkTx: netTx, - BlockRead: float64(blkRead), - BlockWrite: float64(blkWrite), - PidsCurrent: pidsStatsCurrent, - }) u <- nil if !streamStats { return @@ -165,18 +155,18 @@ func collect(ctx context.Context, s *Stats, cli client.ContainerAPIClient, strea } } -func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *container.StatsResponse) float64 { +func calculateCPUPercentUnix(previousCPU container.CPUStats, curCPUStats container.CPUStats) 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) + cpuDelta = float64(curCPUStats.CPUUsage.TotalUsage) - float64(previousCPU.CPUUsage.TotalUsage) // calculate the change for the entire system between readings - systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem) - onlineCPUs = float64(v.CPUStats.OnlineCPUs) + systemDelta = float64(curCPUStats.SystemUsage) - float64(previousCPU.SystemUsage) + onlineCPUs = float64(curCPUStats.OnlineCPUs) ) if onlineCPUs == 0.0 { - onlineCPUs = float64(len(v.CPUStats.CPUUsage.PercpuUsage)) + onlineCPUs = float64(len(curCPUStats.CPUUsage.PercpuUsage)) } if systemDelta > 0.0 && cpuDelta > 0.0 { cpuPercent = (cpuDelta / systemDelta) * onlineCPUs * 100.0 @@ -188,13 +178,11 @@ func calculateCPUPercentWindows(v *container.StatsResponse) float64 { // Max number of 100ns intervals between the previous time read and now possIntervals := uint64(v.Read.Sub(v.PreRead).Nanoseconds()) // Start with number of ns intervals possIntervals /= 100 // Convert to number of 100ns intervals - possIntervals *= uint64(v.NumProcs) // Multiple by the number of processors - - // Intervals used - intervalsUsed := v.CPUStats.CPUUsage.TotalUsage - v.PreCPUStats.CPUUsage.TotalUsage + possIntervals *= uint64(v.NumProcs) // Multiply by the number of processors // Percentage avoiding divide-by-zero if possIntervals > 0 { + intervalsUsed := v.CPUStats.CPUUsage.TotalUsage - v.PreCPUStats.CPUUsage.TotalUsage return float64(intervalsUsed) / float64(possIntervals) * 100.0 } return 0.00