Merge branch '2637-docker-memory-usage-is-incorrect' of github.com:nicolargo/glances into 2637-docker-memory-usage-is-incorrect

pull/2745/head
nicolargo 2024-04-30 10:44:20 +02:00
commit cb543cd53d
6 changed files with 38 additions and 20 deletions

View File

@ -23,6 +23,7 @@ Under development: https://github.com/nicolargo/glances/issues?q=is%3Aopen+is%3A
alias=sda1:InternalDisk,sdb1:ExternalDisk alias=sda1:InternalDisk,sdb1:ExternalDisk
* Alert data model change from a list of list to a list of dict #2633 * Alert data model change from a list of list to a list of dict #2633
* Docker memory usage uses the same algorithm than docker stats #2637
=============== ===============
Version 3.4.0.5 Version 3.4.0.5

View File

@ -14,6 +14,8 @@ You can install this dependency using:
.. image:: ../_static/containers.png .. image:: ../_static/containers.png
Note: Memory usage is compute as following "display memory usage = memory usage - inactive_file"
It is possible to define limits and actions from the configuration file It is possible to define limits and actions from the configuration file
under the ``[containers]`` section: under the ``[containers]`` section:

View File

@ -112,14 +112,21 @@ export default {
const { sorter } = this; const { sorter } = this;
const containers = (this.stats || []).map( const containers = (this.stats || []).map(
(containerData) => { (containerData) => {
// prettier-ignore let memory_usage_no_cache = '?'
if (containerData.memory.usage != undefined) {
memory_usage_no_cache = containerData.memory.usage;
if (containerData.memory.inactive_file != undefined) {
memory_usage_no_cache = memory_usage_no_cache - containerData.memory.inactive_file;
}
}
return { return {
'id': containerData.id, 'id': containerData.id,
'name': containerData.name, 'name': containerData.name,
'status': containerData.status, 'status': containerData.status,
'uptime': containerData.uptime, 'uptime': containerData.uptime,
'cpu_percent': containerData.cpu.total, 'cpu_percent': containerData.cpu.total,
'memory_usage': containerData.memory.usage != undefined ? containerData.memory.usage : '?', 'memory_usage': memory_usage_no_cache,
'limit': containerData.memory.limit != undefined ? containerData.memory.limit : '?', 'limit': containerData.memory.limit != undefined ? containerData.memory.limit : '?',
'io_rx': containerData.io_rx != undefined ? containerData.io_rx : '?', 'io_rx': containerData.io_rx != undefined ? containerData.io_rx : '?',
'io_wx': containerData.io_wx != undefined ? containerData.io_wx : '?', 'io_wx': containerData.io_wx != undefined ? containerData.io_wx : '?',

View File

@ -256,6 +256,11 @@ class PluginModel(GlancesPluginModel):
"""Return the user ticks by reading the environment variable.""" """Return the user ticks by reading the environment variable."""
return os.sysconf(os.sysconf_names['SC_CLK_TCK']) return os.sysconf(os.sysconf_names['SC_CLK_TCK'])
def memory_usage_no_cache(self, mem):
"""Return the 'real' memory usage by removing inactive_file to usage"""
# Ref: https://github.com/docker/docker-py/issues/3210
return mem['usage'] - (mem['inactive_file'] if 'inactive_file' in mem else 0)
def update_views(self): def update_views(self):
"""Update stats views.""" """Update stats views."""
# Call the father's method # Call the father's method
@ -281,11 +286,17 @@ class PluginModel(GlancesPluginModel):
if 'memory' in i and 'usage' in i['memory']: if 'memory' in i and 'usage' in i['memory']:
# Looking for specific MEM container threshold in the conf file # Looking for specific MEM container threshold in the conf file
alert = self.get_alert( alert = self.get_alert(
i['memory']['usage'], maximum=i['memory']['limit'], header=i['name'] + '_mem', action_key=i['name'] self.memory_usage_no_cache(i['memory']),
maximum=i['memory']['limit'],
header=i['name'] + '_mem', action_key=i['name']
) )
if alert == 'DEFAULT': if alert == 'DEFAULT':
# Not found ? Get back to default MEM threshold value # Not found ? Get back to default MEM threshold value
alert = self.get_alert(i['memory']['usage'], maximum=i['memory']['limit'], header='mem') alert = self.get_alert(
self.memory_usage_no_cache(i['memory']),
maximum=i['memory']['limit'],
header='mem'
)
self.views[i[self.get_key()]]['mem']['decoration'] = alert self.views[i[self.get_key()]]['mem']['decoration'] = alert
# Display Engine and Pod name ? # Display Engine and Pod name ?
@ -383,8 +394,8 @@ class PluginModel(GlancesPluginModel):
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='cpu', option='decoration'))) ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='cpu', option='decoration')))
# MEM # MEM
try: try:
msg = '{:>7}'.format(self.auto_unit(container['memory']['usage'])) msg = '{:>7}'.format(self.auto_unit(self.memory_usage_no_cache(container['memory'])))
except (KeyError, TypeError): except KeyError:
msg = '{:>7}'.format('_') msg = '{:>7}'.format('_')
ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='mem', option='decoration'))) ret.append(self.curse_add_line(msg, self.get_views(item=container['name'], key='mem', option='decoration')))
try: try:

View File

@ -2,7 +2,7 @@
# #
# This file is part of Glances. # This file is part of Glances.
# #
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <nicolas@nicolargo.com> # SPDX-FileCopyrightText: 2023 Nicolas Hennion <nicolas@nicolargo.com>
# #
# SPDX-License-Identifier: LGPL-3.0-only # SPDX-License-Identifier: LGPL-3.0-only
# #
@ -29,7 +29,7 @@ else:
class DockerStatsFetcher: class DockerStatsFetcher:
MANDATORY_MEMORY_FIELDS = ["usage", 'limit'] MANDATORY_MEMORY_FIELDS = ['usage', 'limit']
def __init__(self, container): def __init__(self, container):
self._container = container self._container = container
@ -120,7 +120,9 @@ class DockerStatsFetcher:
def _get_memory_stats(self): def _get_memory_stats(self):
"""Return the container MEMORY. """Return the container MEMORY.
Output: a dict {'rss': 1015808, 'cache': 356352, 'usage': ..., 'max_usage': ...} Output: a dict {'usage': ..., 'limit': ..., 'inactive_file': ...}
Note:the displayed memory usage is 'usage - inactive_file'
""" """
memory_stats = self._streamer.stats.get('memory_stats') memory_stats = self._streamer.stats.get('memory_stats')
@ -130,15 +132,10 @@ class DockerStatsFetcher:
return None return None
stats = {field: memory_stats[field] for field in self.MANDATORY_MEMORY_FIELDS} stats = {field: memory_stats[field] for field in self.MANDATORY_MEMORY_FIELDS}
try:
# Issue #1857 - Some stats are not always available in ['memory_stats']['stats'] # Optional field stats: inactive_file
detailed_stats = memory_stats['stats'] if memory_stats.get('stats', {}).get('inactive_file') is not None:
stats['rss'] = detailed_stats.get('rss') or detailed_stats.get('total_rss') stats['inactive_file'] = memory_stats['stats']['inactive_file']
stats['max_usage'] = detailed_stats.get('max_usage')
stats['cache'] = detailed_stats.get('cache')
except (KeyError, TypeError) as e:
self._log_debug("Can't grab MEM usage", e) # stats do not have MEM information
return None
# Return the stats # Return the stats
return stats return stats

View File

@ -139,7 +139,7 @@ class PodmanPodStatsFetcher:
def _get_memory_stats(self, stats): def _get_memory_stats(self, stats):
"""Return the container MEMORY. """Return the container MEMORY.
Output: a dict {'rss': 1015808, 'cache': 356352, 'usage': ..., 'max_usage': ...} Output: a dict {'usage': ..., 'limit': ...}
""" """
if "MemUsage" not in stats or "/" not in stats["MemUsage"]: if "MemUsage" not in stats or "/" not in stats["MemUsage"]:
self._log_debug("Missing MEM usage fields") self._log_debug("Missing MEM usage fields")
@ -155,7 +155,7 @@ class PodmanPodStatsFetcher:
self._log_debug("Compute MEM usage failed", e) self._log_debug("Compute MEM usage failed", e)
return None return None
return {"usage": usage, "limit": limit} return {'usage': usage, 'limit': limit, 'inactive_file': 0}
def _get_network_stats(self, stats): def _get_network_stats(self, stats):
"""Return the container network usage using the Docker API (v1.0 or higher). """Return the container network usage using the Docker API (v1.0 or higher).