From e1d38a358254d415e14ad397d2276eb65f02e6fb Mon Sep 17 00:00:00 2001 From: Amir Raminfar Date: Tue, 9 Jan 2024 13:03:30 -0800 Subject: [PATCH] fix: fixes stats on windows (#2675) --- assets/components/LogViewer/ContainerStat.vue | 4 +- assets/pages/index.vue | 2 +- internal/docker/calculation.go | 44 +++++++++++++++++++ internal/docker/client.go | 33 +++++++++----- internal/docker/types.go | 8 ++-- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/assets/components/LogViewer/ContainerStat.vue b/assets/components/LogViewer/ContainerStat.vue index 95d1b76f..f4a97989 100644 --- a/assets/components/LogViewer/ContainerStat.vue +++ b/assets/components/LogViewer/ContainerStat.vue @@ -1,7 +1,7 @@ @@ -15,7 +15,7 @@ const cpuData = computedWithControl( const points: Point[] = history.map((stat, i) => ({ x: i, y: Math.max(0, stat.snapshot.cpu), - value: Math.max(0, stat.snapshot.cpu) + "%", + value: Math.max(0, stat.snapshot.cpu).toFixed(2) + "%", })); return points; }, diff --git a/assets/pages/index.vue b/assets/pages/index.vue index 08e57af2..23d0e8e9 100644 --- a/assets/pages/index.vue +++ b/assets/pages/index.vue @@ -7,7 +7,7 @@
{{ $t("label.running") }} / {{ $t("label.total-containers") }}
-
{{ totalCpu }}%
+
{{ totalCpu.toFixed(0) }}%
{{ $t("label.total-cpu-usage") }}
diff --git a/internal/docker/calculation.go b/internal/docker/calculation.go index 5ad417da..2c675572 100644 --- a/internal/docker/calculation.go +++ b/internal/docker/calculation.go @@ -15,3 +15,47 @@ func calculateMemUsageUnixNoCache(mem types.MemoryStats) float64 { } return float64(mem.Usage) } + +func calculateCPUPercentWindows(v *types.StatsJSON) 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 + + // Percentage avoiding divide-by-zero + if possIntervals > 0 { + return float64(intervalsUsed) / float64(possIntervals) * 100.0 + } + return 0.00 +} + +func calculateMemPercentUnixNoCache(limit float64, usedNoCache float64) float64 { + // MemoryStats.Limit will never be 0 unless the container is not running and we haven't + // got any data from cgroup + if limit != 0 { + return usedNoCache / limit * 100.0 + } + return 0 +} + +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) + onlineCPUs = float64(v.CPUStats.OnlineCPUs) + ) + + if onlineCPUs == 0.0 { + onlineCPUs = float64(len(v.CPUStats.CPUUsage.PercpuUsage)) + } + if systemDelta > 0.0 && cpuDelta > 0.0 { + cpuPercent = (cpuDelta / systemDelta) * onlineCPUs * 100.0 + } + return cpuPercent +} diff --git a/internal/docker/client.go b/internal/docker/client.go index 913fb5aa..9dd217b0 100644 --- a/internal/docker/client.go +++ b/internal/docker/client.go @@ -223,20 +223,29 @@ func (d *Client) ContainerStats(ctx context.Context, id string, stats chan<- Con log.Errorf("decoder for stats api returned an unknown error %v", err) } - ncpus := uint8(v.CPUStats.OnlineCPUs) - if ncpus == 0 { - ncpus = uint8(len(v.CPUStats.CPUUsage.PercpuUsage)) + var ( + memPercent, cpuPercent float64 + mem, memLimit float64 + previousCPU uint64 + previousSystem uint64 + ) + daemonOSType := response.OSType + + if daemonOSType != "windows" { + previousCPU = v.PreCPUStats.CPUUsage.TotalUsage + previousSystem = v.PreCPUStats.SystemUsage + cpuPercent = calculateCPUPercentUnix(previousCPU, previousSystem, v) + mem = calculateMemUsageUnixNoCache(v.MemoryStats) + memLimit = float64(v.MemoryStats.Limit) + memPercent = calculateMemPercentUnixNoCache(memLimit, mem) + } else { + cpuPercent = calculateCPUPercentWindows(v) + mem = float64(v.MemoryStats.PrivateWorkingSet) } - var ( - cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(v.PreCPUStats.CPUUsage.TotalUsage) - systemDelta = float64(v.CPUStats.SystemUsage) - float64(v.PreCPUStats.SystemUsage) - cpuPercent = int64((cpuDelta / systemDelta) * float64(ncpus) * 100) - memUsage = int64(calculateMemUsageUnixNoCache(v.MemoryStats)) - memPercent = int64(float64(memUsage) / float64(v.MemoryStats.Limit) * 100) - ) + log.Tracef("containerId = %s, cpuPercent = %f, memPercent = %f, memUsage = %f, daemonOSType = %s", id, cpuPercent, memPercent, mem, daemonOSType) - if cpuPercent > 0 || memUsage > 0 { + if cpuPercent > 0 || mem > 0 { select { case <-ctx.Done(): return @@ -244,7 +253,7 @@ func (d *Client) ContainerStats(ctx context.Context, id string, stats chan<- Con ID: id, CPUPercent: cpuPercent, MemoryPercent: memPercent, - MemoryUsage: memUsage, + MemoryUsage: mem, }: } } diff --git a/internal/docker/types.go b/internal/docker/types.go index 1efc8da2..be49a1d3 100644 --- a/internal/docker/types.go +++ b/internal/docker/types.go @@ -23,10 +23,10 @@ type Container struct { // ContainerStat represent stats instant for a container type ContainerStat struct { - ID string `json:"id"` - CPUPercent int64 `json:"cpu"` - MemoryPercent int64 `json:"memory"` - MemoryUsage int64 `json:"memoryUsage"` + ID string `json:"id"` + CPUPercent float64 `json:"cpu"` + MemoryPercent float64 `json:"memory"` + MemoryUsage float64 `json:"memoryUsage"` } // ContainerEvent represents events that are triggered