From 9b76f17a70f68d047e000a60c08f6400c12c0cac Mon Sep 17 00:00:00 2001 From: Maxime Mouial Date: Fri, 9 Mar 2018 14:54:38 -0500 Subject: [PATCH] Adding 'slab' info to virtual_memory on linux --- docs/index.rst | 3 ++- psutil/_pslinux.py | 9 +++++++-- psutil/tests/test_linux.py | 26 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 4f77b2e49..0f55a2e1a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -266,6 +266,7 @@ Memory - **active** *(UNIX)*: memory currently in use or very recently used, and so it is in RAM. - **inactive** *(UNIX)*: memory that is marked as not used. + - **slab** *(Linux)*: in-kernel data structures cache. - **buffers** *(Linux, BSD)*: cache for things like file system metadata. - **cached** *(Linux, BSD)*: cache for various things. - **shared** *(Linux, BSD)*: memory that may be simultaneously accessed by @@ -284,7 +285,7 @@ Memory >>> import psutil >>> mem = psutil.virtual_memory() >>> mem - svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304) + svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304, slab=199348224) >>> >>> THRESHOLD = 100 * 1024 * 1024 # 100MB >>> if mem.available <= THRESHOLD: diff --git a/psutil/_pslinux.py b/psutil/_pslinux.py index b57adb34e..1f4be9c07 100644 --- a/psutil/_pslinux.py +++ b/psutil/_pslinux.py @@ -149,7 +149,7 @@ class IOPriority(enum.IntEnum): # psutil.virtual_memory() svmem = namedtuple( 'svmem', ['total', 'available', 'percent', 'used', 'free', - 'active', 'inactive', 'buffers', 'cached', 'shared']) + 'active', 'inactive', 'buffers', 'cached', 'shared', 'slab']) # psutil.disk_io_counters() sdiskio = namedtuple( 'sdiskio', ['read_count', 'write_count', @@ -441,6 +441,11 @@ def virtual_memory(): inactive = 0 missing_fields.append('inactive') + try: + slab = mems[b"Slab:"] + except KeyError: + slab = 0 + used = total - free - cached - buffers if used < 0: # May be symptomatic of running within a LCX container where such @@ -481,7 +486,7 @@ def virtual_memory(): warnings.warn(msg, RuntimeWarning) return svmem(total, avail, percent, used, free, - active, inactive, buffers, cached, shared) + active, inactive, buffers, cached, shared, slab) def swap_memory(): diff --git a/psutil/tests/test_linux.py b/psutil/tests/test_linux.py index 6ba17b254..24e667b49 100755 --- a/psutil/tests/test_linux.py +++ b/psutil/tests/test_linux.py @@ -237,6 +237,31 @@ def test_available(self): free_value, psutil_value, delta=MEMORY_TOLERANCE, msg='%s %s \n%s' % (free_value, psutil_value, out)) + def test_slab(self): + # Emulate /proc/meminfo because neither vmstat nor free return slab. + def open_mock(name, *args, **kwargs): + if name == '/proc/meminfo': + return io.BytesIO(textwrap.dedent("""\ + Active(anon): 6145416 kB + Active(file): 2950064 kB + Inactive(anon): 574764 kB + Inactive(file): 1567648 kB + MemAvailable: -1 kB + MemFree: 2057400 kB + MemTotal: 16325648 kB + SReclaimable: 346648 kB + Slab: 186836 kB + """).encode()) + else: + return orig_open(name, *args, **kwargs) + + orig_open = open + patch_point = 'builtins.open' if PY3 else '__builtin__.open' + with mock.patch(patch_point, create=True, side_effect=open_mock) as m: + ret = psutil.virtual_memory() + assert m.called + self.assertEqual(ret.slab, 191320064) + def test_warnings_on_misses(self): # Emulate a case where /proc/meminfo provides few info. # psutil is supposed to set the missing fields to 0 and @@ -280,6 +305,7 @@ def open_mock(name, *args, **kwargs): self.assertEqual(ret.shared, 0) self.assertEqual(ret.buffers, 0) self.assertEqual(ret.available, 0) + self.assertEqual(ret.slab, 0) def test_avail_old_percent(self): # Make sure that our calculation of avail mem for old kernels