Refactoring to determine the page size

This commit is contained in:
Carsten Grohmann 2023-03-15 23:09:01 +01:00
parent 2c09e21ae5
commit 8a1083cf4b
3 changed files with 66 additions and 13 deletions

View File

@ -104,6 +104,13 @@ THIS PROGRAM COMES WITH NO WARRANTY
/* empty - used to show sections for manually triggered OOMs */ /* 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 { .js-pstable_sort_col0 {
/* empty - used to sort process table */ /* empty - used to sort process table */
} }
@ -871,7 +878,14 @@ window.onerror = function (msg, url, lineNo, columnNo, errorObj) {
<tr> <tr>
<td>Page size</td> <td>Page size</td>
<td class="page_size_kb text--align-right"></td> <td class="page_size_kb text--align-right"></td>
<td>Guessed</td> <td>
<span class="js-text--default-hide js-pagesize-determined--show">
Extracted from DMA zone buddyinfo
</span>
<span class="js-text--default-hide js-pagesize-guessed--show">
Guessed
</span>
</td>
</tr> </tr>

View File

@ -2799,6 +2799,9 @@ class OOMAnalyser:
) )
"""RE to extract free memory chunks of a memor zone""" """RE to extract free memory chunks of a memor zone"""
REC_PAGE_SIZE = re.compile("Node 0 DMA: \d+\*(?P<page_size>\d+)kB")
"""RE to extract the page size from buddyinfo DMA zone"""
REC_WATERMARK = re.compile( REC_WATERMARK = re.compile(
"Node (?P<node>\d+) (?P<zone>DMA|DMA32|Normal) " "Node (?P<node>\d+) (?P<zone>DMA|DMA32|Normal) "
"free:(?P<free>\d+)kB " "free:(?P<free>\d+)kB "
@ -3018,11 +3021,23 @@ class OOMAnalyser:
call_trace += "{}\n".format(line.strip()) call_trace += "{}\n".format(line.strip())
self.oom_result.details["call_trace"] = call_trace self.oom_result.details["call_trace"] = call_trace
self._extract_page_size()
self._extract_pstable() self._extract_pstable()
self._extract_gpf_mask() self._extract_gpf_mask()
self._extract_buddyinfo() self._extract_buddyinfo()
self._extract_watermarks() 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): def _extract_pstable(self):
"""Extract process table""" """Extract process table"""
self.oom_result.details["_pstable"] = {} self.oom_result.details["_pstable"] = {}
@ -3049,10 +3064,8 @@ class OOMAnalyser:
This function fills: This function fills:
* OOMResult.buddyinfo with [<zone>][<order>][<node>] = <number of free chunks> * OOMResult.buddyinfo with [<zone>][<order>][<node>] = <number of free chunks>
* OOMResult.buddyinfo with [zone]["total_free_kb_per_node"][node] = int(total_free_kb_per_node) * 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.buddyinfo = {}
self.oom_result.details["_buddyinfo_pagesize_kb"] = None
buddy_info = self.oom_result.buddyinfo buddy_info = self.oom_result.buddyinfo
self.oom_entity.find_text(self.oom_result.kconfig.zoneinfo_start) self.oom_entity.find_text(self.oom_result.kconfig.zoneinfo_start)
@ -3095,11 +3108,6 @@ class OOMAnalyser:
node 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, # 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. # a value of 11 means that the largest free memory block is 2^10 pages.
# __pragma__ ('jsiter') # __pragma__ ('jsiter')
@ -3352,7 +3360,6 @@ class OOMAnalyser:
highest_zoneidx = self.oom_result.kconfig.ZONE_TYPES.index(zone) highest_zoneidx = self.oom_result.kconfig.ZONE_TYPES.index(zone)
lowmem_reserve = watermark_info[zone][node]["lowmem_reserve"] lowmem_reserve = watermark_info[zone][node]["lowmem_reserve"]
min_kb = watermark_info[zone][node]["low"] min_kb = watermark_info[zone][node]["low"]
page_size = self.oom_result.details["_buddyinfo_pagesize_kb"]
# reduce minimum watermark for high priority calls # reduce minimum watermark for high priority calls
# ALLOC_HIGH == __GFP_HIGH # ALLOC_HIGH == __GFP_HIGH
@ -3363,7 +3370,13 @@ class OOMAnalyser:
# check watermarks, if these are not met, then a high-order request also # 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. # 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 = ( self.oom_result.mem_alloc_failure = (
OOMMemoryAllocFailureType.failed_below_low_watermark OOMMemoryAllocFailureType.failed_below_low_watermark
) )
@ -3515,9 +3528,6 @@ class OOMAnalyser:
dist = "Ubuntu" dist = "Ubuntu"
self.oom_result.details["dist"] = dist self.oom_result.details["dist"] = dist
# educated guess
self.oom_result.details["page_size_kb"] = 4
def _calc_from_oom_details(self): def _calc_from_oom_details(self):
""" """
Calculate values from already extracted details 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_ram_usage()
self._show_alloc_failure() self._show_alloc_failure()
self._show_memory_fragmentation() self._show_memory_fragmentation()
self._show_page_size()
# generate process table # generate process table
self._show_pstable() self._show_pstable()
@ -4446,6 +4457,15 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
else: else:
show_elements(".js-memory-no-heavy-fragmentation--show") 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): def _show_ram_usage(self):
"""Generate RAM usage diagram""" """Generate RAM usage diagram"""
ram_title_attr = ( ram_title_attr = (

19
test.py
View File

@ -1049,6 +1049,25 @@ Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012
% (node, zone), % (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__": if __name__ == "__main__":
unittest.main(verbosity=2) unittest.main(verbosity=2)