From 483b6520876844886449ce91dadc81273f34a907 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 8 May 2020 22:06:26 -0700 Subject: [PATCH] Report memory stats using the same logic that docker uses for stats output; avoid extreme differences in output --- server/environment_docker.go | 3 +-- server/resources.go | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/server/environment_docker.go b/server/environment_docker.go index d4cf295..e6fee97 100644 --- a/server/environment_docker.go +++ b/server/environment_docker.go @@ -501,7 +501,7 @@ func (d *DockerEnvironment) EnableResourcePolling() error { } s.Resources.CpuAbsolute = s.Resources.CalculateAbsoluteCpu(&v.PreCPUStats, &v.CPUStats) - s.Resources.Memory = v.MemoryStats.Usage + s.Resources.Memory = s.Resources.CalculateDockerMemory(v.MemoryStats) s.Resources.MemoryLimit = v.MemoryStats.Limit // Why you ask? This already has the logic for caching disk space in use and then @@ -827,7 +827,6 @@ func (d *DockerEnvironment) exposedPorts() nat.PortSet { return out } - // Formats the resources available to a server instance in such as way that Docker will // generate a matching environment in the container. // diff --git a/server/resources.go b/server/resources.go index 5cf480a..55f5cd1 100644 --- a/server/resources.go +++ b/server/resources.go @@ -9,7 +9,10 @@ import ( // should obviously expect memory and CPU usage to be 0. However, disk will always be returned // since that is not dependent on the server being running to collect that data. type ResourceUsage struct { - // The total amount of memory, in bytes, that this server instance is consuming. + // The total amount of memory, in bytes, that this server instance is consuming. This is + // calculated slightly differently than just using the raw Memory field that the stats + // return from the container, so please check the code setting this value for how that + // is calculated. Memory uint64 `json:"memory_bytes"` // The total amount of memory this container or resource can use. Inside Docker this is // going to be higher than you'd expect because we're automatically allocating overhead @@ -28,6 +31,27 @@ type ResourceUsage struct { } `json:"network"` } +// The "docker stats" CLI call does not return the same value as the types.MemoryStats.Usage +// value which can be rather confusing to people trying to compare panel usage to +// their stats output. +// +// This math is straight up lifted from their CLI repository in order to show the same +// values to avoid people bothering me about it. It should also reflect a slightly more +// correct memory value anyways. +// +// @see https://github.com/docker/cli/blob/96e1d1d6/cli/command/container/stats_helpers.go#L227-L249 +func (ru *ResourceUsage) CalculateDockerMemory(stats types.MemoryStats) uint64 { + if v, ok := stats.Stats["total_inactive_file"]; ok && v < stats.Usage { + return stats.Usage - v + } + + if v := stats.Stats["inactive_file"]; v < stats.Usage { + return stats.Usage - v + } + + return stats.Usage +} + // Calculates the absolute CPU usage used by the server process on the system, not constrained // by the defined CPU limits on the container. // @@ -51,4 +75,4 @@ func (ru *ResourceUsage) CalculateAbsoluteCpu(pStats *types.CPUStats, stats *typ } return math.Round(percent*1000) / 1000 -} \ No newline at end of file +}