From 8a1083cf4bfa8f4b22c5274d7db62317f0655fd2 Mon Sep 17 00:00:00 2001 From: Carsten Grohmann Date: Wed, 15 Mar 2023 23:09:01 +0100 Subject: [PATCH] Refactoring to determine the page size --- OOMAnalyser.html | 16 +++++++++++++++- OOMAnalyser.py | 44 ++++++++++++++++++++++++++++++++------------ test.py | 19 +++++++++++++++++++ 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/OOMAnalyser.html b/OOMAnalyser.html index 10a82ff..a3cb1eb 100644 --- a/OOMAnalyser.html +++ b/OOMAnalyser.html @@ -104,6 +104,13 @@ THIS PROGRAM COMES WITH NO WARRANTY /* empty - used to show sections for manually triggered OOMs */ } + .js-pagesize-guessed--show { + /* empty - used to show if the page size is guessed */ + } + .js-pagesize-determined--show { + /* empty - used to show if the page size is determined */ + } + .js-pstable_sort_col0 { /* empty - used to sort process table */ } @@ -871,7 +878,14 @@ window.onerror = function (msg, url, lineNo, columnNo, errorObj) { Page size - Guessed + + + Extracted from DMA zone buddyinfo + + + Guessed + + diff --git a/OOMAnalyser.py b/OOMAnalyser.py index ce90677..721e46a 100644 --- a/OOMAnalyser.py +++ b/OOMAnalyser.py @@ -2799,6 +2799,9 @@ class OOMAnalyser: ) """RE to extract free memory chunks of a memor zone""" + REC_PAGE_SIZE = re.compile("Node 0 DMA: \d+\*(?P\d+)kB") + """RE to extract the page size from buddyinfo DMA zone""" + REC_WATERMARK = re.compile( "Node (?P\d+) (?PDMA|DMA32|Normal) " "free:(?P\d+)kB " @@ -3018,11 +3021,23 @@ class OOMAnalyser: call_trace += "{}\n".format(line.strip()) self.oom_result.details["call_trace"] = call_trace + self._extract_page_size() self._extract_pstable() self._extract_gpf_mask() self._extract_buddyinfo() self._extract_watermarks() + def _extract_page_size(self): + """Extract page size from buddyinfo DMZ zone""" + match = self.REC_PAGE_SIZE.search(self.oom_entity.text) + if match: + self.oom_result.details["page_size_kb"] = int(match.group("page_size")) + self.oom_result.details["_page_size_guessed"] = False + else: + # educated guess + self.oom_result.details["page_size_kb"] = 4 + self.oom_result.details["_page_size_guessed"] = True + def _extract_pstable(self): """Extract process table""" self.oom_result.details["_pstable"] = {} @@ -3049,10 +3064,8 @@ class OOMAnalyser: This function fills: * OOMResult.buddyinfo with [][][] = * OOMResult.buddyinfo with [zone]["total_free_kb_per_node"][node] = int(total_free_kb_per_node) - * OOMResult.details["_buddyinfo_pagesize_kb"] with the extracted page size """ self.oom_result.buddyinfo = {} - self.oom_result.details["_buddyinfo_pagesize_kb"] = None buddy_info = self.oom_result.buddyinfo self.oom_entity.find_text(self.oom_result.kconfig.zoneinfo_start) @@ -3095,11 +3108,6 @@ class OOMAnalyser: node ] - if not self.oom_result.details["_buddyinfo_pagesize_kb"] and order == 0: - size = element.split("*")[1] - size = size[:-2] # strip "kB" - self.oom_result.details["_buddyinfo_pagesize_kb"] = int(size) - # MAX_ORDER is actually maximum order plus one. For example, # a value of 11 means that the largest free memory block is 2^10 pages. # __pragma__ ('jsiter') @@ -3352,7 +3360,6 @@ class OOMAnalyser: highest_zoneidx = self.oom_result.kconfig.ZONE_TYPES.index(zone) lowmem_reserve = watermark_info[zone][node]["lowmem_reserve"] min_kb = watermark_info[zone][node]["low"] - page_size = self.oom_result.details["_buddyinfo_pagesize_kb"] # reduce minimum watermark for high priority calls # ALLOC_HIGH == __GFP_HIGH @@ -3363,7 +3370,13 @@ class OOMAnalyser: # check watermarks, if these are not met, then a high-order request also # cannot go ahead even if a suitable page happened to be free. - if free_kb <= (min_kb + (lowmem_reserve[highest_zoneidx] * page_size)): + if free_kb <= ( + min_kb + + ( + lowmem_reserve[highest_zoneidx] + * self.oom_result.details["page_size_kb"] + ) + ): self.oom_result.mem_alloc_failure = ( OOMMemoryAllocFailureType.failed_below_low_watermark ) @@ -3515,9 +3528,6 @@ class OOMAnalyser: dist = "Ubuntu" self.oom_result.details["dist"] = dist - # educated guess - self.oom_result.details["page_size_kb"] = 4 - def _calc_from_oom_details(self): """ Calculate values from already extracted details @@ -4404,6 +4414,7 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss: self._show_ram_usage() self._show_alloc_failure() self._show_memory_fragmentation() + self._show_page_size() # generate process table self._show_pstable() @@ -4446,6 +4457,15 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss: else: show_elements(".js-memory-no-heavy-fragmentation--show") + def _show_page_size(self): + """Show page size""" + if self.oom_result.details.get("_page_size_guessed", True): + hide_elements(".js-pagesize-determined--show") + show_elements(".js-pagesize-guessed--show") + else: + show_elements(".js-pagesize-determined--show") + hide_elements(".js-pagesize-guessed--show") + def _show_ram_usage(self): """Generate RAM usage diagram""" ram_title_attr = ( diff --git a/test.py b/test.py index dc130ca..a6a46c5 100755 --- a/test.py +++ b/test.py @@ -1049,6 +1049,25 @@ Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012 % (node, zone), ) + def test_013_page_size(self): + """Test determination of the page size""" + oom = OOMAnalyser.OOMEntity(OOMAnalyser.OOMDisplay.example_rhel7) + analyser = OOMAnalyser.OOMAnalyser(oom) + success = analyser.analyse() + self.assertTrue(success, "OOM analysis failed") + + page_size_kb = analyser.oom_result.details["page_size_kb"] + self.assertEqual( + page_size_kb, + 4, + "Unexpected page size (got %s, expect: 4)" % page_size_kb, + ) + self.assertEqual( + analyser.oom_result.details["_page_size_guessed"], + False, + "Page size guessed and not determinated", + ) + if __name__ == "__main__": unittest.main(verbosity=2)