From 17536301d65df52b603040094a8bc71f27d2462a Mon Sep 17 00:00:00 2001 From: Carsten Grohmann Date: Sat, 14 Jan 2023 22:14:03 +0100 Subject: [PATCH] Extract and store memory watermark information --- OOMAnalyser.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- test.py | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/OOMAnalyser.py b/OOMAnalyser.py index 71134d5..1b92fe4 100644 --- a/OOMAnalyser.py +++ b/OOMAnalyser.py @@ -520,6 +520,13 @@ class BaseKernelConfig: rec_oom_end = re.compile(r"^Killed process \d+", re.MULTILINE) """RE to match the last line of an OOM block""" + watermark_start = "Node 0 DMA free:" + """ + Pattern to find the start of the memory watermark information + + :type: str + """ + zoneinfo_start = "Node 0 DMA: " """ Pattern to find the start of the memory chunk information (buddyinfo) @@ -2702,7 +2709,17 @@ class OOMAnalyser: REC_FREE_MEMORY_CHUNKS = re.compile( "Node (?P\d+) (?PDMA|DMA32|Normal): (?P.*) = (?P\d+)kB" ) - """RE to extract free memory chunks in a zone""" + """RE to extract free memory chunks of a memor zone""" + + REC_WATERMARK = re.compile( + "Node (?P\d+) (?PDMA|DMA32|Normal) " + "free:(?P\d+)kB " + "min:(?P\d+)kB " + "low:(?P\d+)kB " + "high:(?P\d+)kB " + ".*" + ) + """RE to extract watermark information in a memory zone""" def __init__(self, oom): self.oom_entity = oom @@ -2913,6 +2930,7 @@ class OOMAnalyser: self._extract_pstable() self._extract_gpf_mask() self._extract_buddyinfo() + self._extract_watermarks() def _extract_pstable(self): """Extract process table""" @@ -2991,6 +3009,37 @@ class OOMAnalyser: size = size[:-2] # strip "kB" self.oom_result.details["_buddyinfo_pagesize_kb"] = int(size) + def _extract_watermarks(self): + """ + Extract memory watermark information from all zones + + This function fills: + * OOMResult.details["_watermarks"] with [][][(free|min|low|high)] = + """ + self.oom_result.details["_watermarks"] = {} + watermark_info = self.oom_result.details["_watermarks"] + self.oom_entity.find_text(self.oom_result.kconfig.watermark_start) + + # Currently omm_entity point to the first line of the watermark information. + # The iterator protocol uses the next() call. However, this will cause the + # current line to be skipped. + # Therefore, we reset the counter by one line. + self.oom_entity.back() + + for line in self.oom_entity: + match = self.REC_WATERMARK.match(line) + if not match: + continue + + node = int(match.group("node")) + zone = match.group("zone") + if zone not in watermark_info: + watermark_info[zone] = {} + if node not in watermark_info[zone]: + watermark_info[zone][node] = {} + for i in ["free", "min", "low", "high"]: + watermark_info[zone][node][i] = int(match.group(i)) + def _gfp_hex2flags(self, hexvalue): """\ Convert the hexadecimal value into flags specified by definition diff --git a/test.py b/test.py index dcea9ca..35ae1bd 100755 --- a/test.py +++ b/test.py @@ -896,6 +896,48 @@ Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012 % (order, zone, node, count, except_count), ) + def test_010_extract_zoneinfo(self): + """Test extracting watermark information""" + oom = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example_rhel7) + analyser = OOMAnalyser.OOMAnalyser(oom) + success = analyser.analyse() + self.assertTrue(success, "OOM analysis failed") + + self.assertEqual( + analyser.oom_result.kconfig.release, + (3, 10, ".el7."), + "Wrong KernelConfig release", + ) + watermarks = analyser.oom_result.details["_watermarks"] + for zone, node, level, except_level in [ + ("Normal", 0, "free", 36692), + ("Normal", 0, "min", 36784), + ("Normal", 1, "low", 56804), + ("Normal", 1, "high", 68164), + ("DMA", 0, "free", 15872), + ("DMA", 0, "high", 60), + ("DMA32", 0, "free", 59728), + ("DMA32", 0, "low", 9788), + ]: + self.assertTrue( + zone in watermarks, + "Missing details for zone %s in memory watermarks" % zone, + ) + self.assertTrue( + node in watermarks[zone], + 'Missing details for node "%s" in memory watermarks' % node, + ) + self.assertTrue( + level in watermarks[zone][node], + 'Missing details for level "%s" in memory watermarks' % level, + ) + level = watermarks[zone][node][level] + self.assertTrue( + level == except_level, + 'Wrong watermark level for node %s in zone "%s" (got: %d, expect %d)' + % (node, zone, level, except_level), + ) + if __name__ == "__main__": unittest.main(verbosity=2)