[] = 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