Add support for newer process table format
This commit is contained in:
parent
f657ac5816
commit
9404c87519
@ -73,6 +73,37 @@
|
|||||||
/* empty - used to show sections for manually triggered OOMs */
|
/* empty - used to show sections for manually triggered OOMs */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.js-pstable_sort_col0 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col1 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col2 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col3 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col4 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col5 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col6 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col7 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col8 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
.js-pstable_sort_col9 {
|
||||||
|
/* empty - used to sort process table */
|
||||||
|
}
|
||||||
|
|
||||||
.js-swap-active--show {
|
.js-swap-active--show {
|
||||||
/* empty - used to show if the swap space is activated */
|
/* empty - used to show if the swap space is activated */
|
||||||
}
|
}
|
||||||
@ -144,6 +175,9 @@
|
|||||||
.pstable__row-oom-score-adj--width {
|
.pstable__row-oom-score-adj--width {
|
||||||
width: 16ch;
|
width: 16ch;
|
||||||
}
|
}
|
||||||
|
.pstable__row-notes--width {
|
||||||
|
width: 20ch;
|
||||||
|
}
|
||||||
.pstable__row-sort--width {
|
.pstable__row-sort--width {
|
||||||
padding-left: unset;
|
padding-left: unset;
|
||||||
padding-right: unset;
|
padding-right: unset;
|
||||||
@ -749,51 +783,51 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td class="terminal " colspan="2">
|
<td class="terminal " colspan="2">
|
||||||
<table class="pstable__table--noborder">
|
<table class="pstable__table--noborder">
|
||||||
<thead>
|
<thead id="pstable_header">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="pstable__row-numeric--width">pid
|
<td class="pstable__row-numeric--width"><span>pid</span>
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_pid" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('pid')"></a>
|
id="js-pstable_sort_col0" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(0)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-numeric--width">uid
|
<td class="pstable__row-numeric--width">uid
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_uid" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('uid')"></a>
|
id="js-pstable_sort_col1" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(1)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-numeric--width">tgid
|
<td class="pstable__row-numeric--width">tgid
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_tgid" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('tgid')"></a>
|
id="js-pstable_sort_col2" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(2)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-pages--width">total_vm
|
<td class="pstable__row-pages--width">total_vm
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_total_vm_pages" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('total_vm_pages')"></a>
|
id="js-pstable_sort_col3" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(3)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-pages--width">rss
|
<td class="pstable__row-pages--width">rss
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_rss_pages" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('rss_pages')"></a>
|
id="js-pstable_sort_col4" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(4)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-pages--width">nr_ptes
|
<td class="pstable__row-pages--width">nr_ptes
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_nr_ptes_pages" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('nr_ptes_pages')"></a>
|
id="js-pstable_sort_col5" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(5)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-pages--width">swapents
|
<td class="pstable__row-pages--width">swapents
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_swapents_pages" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('swapents_pages')"></a>
|
id="js-pstable_sort_col6" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(6)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="pstable__row-oom-score-adj--width">oom_score_adj
|
<td class="pstable__row-oom-score-adj--width">oom_score_adj
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_oom_score_adj" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('oom_score_adj')"></a>
|
id="js-pstable_sort_col7" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(7)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td>name
|
<td class="pstable__row-notes--width">name
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_name" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('name')"></a>
|
id="js-pstable_sort_col8" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(8)"></a>
|
||||||
</td>
|
</td>
|
||||||
<td>notes
|
<td class="pstable__row-notes--width">notes
|
||||||
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
<a class="pstable__row-sort--width" href="javascript:void(0);"
|
||||||
id="pstable_sort_notes" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable('notes')"></a>
|
id="js-pstable_sort_col9" onclick="OOMAnalyser.OOMDisplayInstance.sort_pstable(9)"></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="process_table">
|
<tbody id="pstable_content">
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
@ -898,6 +932,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
|
|||||||
<li>Add support for systems w/o swap (suggested by Mikko Rantalainen)</li>
|
<li>Add support for systems w/o swap (suggested by Mikko Rantalainen)</li>
|
||||||
<li>Add support for newer kernels (suggested by Mikko Rantalainen)</li>
|
<li>Add support for newer kernels (suggested by Mikko Rantalainen)</li>
|
||||||
<li>Add support for journalctl output (suggested by Mikko Rantalainen)</li>
|
<li>Add support for journalctl output (suggested by Mikko Rantalainen)</li>
|
||||||
|
<li>Add support for newer process table format</li>
|
||||||
<li>...</li>
|
<li>...</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
227
OOMAnalyser.py
227
OOMAnalyser.py
@ -347,15 +347,31 @@ class BaseKernelConfig:
|
|||||||
(see https://github.com/torvalds/linux/commit/e67d4ca79aaf9d13a00d229b1b1c96b86828e8ba#diff-020720d0699e3ae1afb6fcd815ca8500)
|
(see https://github.com/torvalds/linux/commit/e67d4ca79aaf9d13a00d229b1b1c96b86828e8ba#diff-020720d0699e3ae1afb6fcd815ca8500)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ps_table_items = ['pid', 'uid', 'tgid', 'total_vm_pages', 'rss_pages', 'nr_ptes_pages', 'swapents_pages',
|
pstable_items = ['pid', 'uid', 'tgid', 'total_vm_pages', 'rss_pages', 'nr_ptes_pages', 'swapents_pages',
|
||||||
'oom_score_adj']
|
'oom_score_adj', 'name', 'notes']
|
||||||
"""Elements of the process table"""
|
"""Elements of the process table"""
|
||||||
|
|
||||||
|
pstable_html = ['PID', 'UID', 'TGID', 'Total VM', 'RSS', 'Page Table Entries', 'Swap Entries', 'OOM Adjustment',
|
||||||
|
'Name', 'Notes']
|
||||||
|
"""
|
||||||
|
Headings of the process table columns
|
||||||
|
"""
|
||||||
|
|
||||||
|
pstable_non_ints = ['pid', 'name', 'notes']
|
||||||
|
"""Columns that are not converted to an integer"""
|
||||||
|
|
||||||
REC_PROCESS_LINE = re.compile(
|
REC_PROCESS_LINE = re.compile(
|
||||||
r'^\[(?P<pid>[ \d]+)\]\s+(?P<uid>\d+)\s+(?P<tgid>\d+)\s+(?P<total_vm_pages>\d+)\s+(?P<rss_pages>\d+)\s+'
|
r'^\[(?P<pid>[ \d]+)\]\s+(?P<uid>\d+)\s+(?P<tgid>\d+)\s+(?P<total_vm_pages>\d+)\s+(?P<rss_pages>\d+)\s+'
|
||||||
r'(?P<nr_ptes_pages>\d+)\s+(?P<swapents_pages>\d+)\s+(?P<oom_score_adj>-?\d+)\s+(?P<name>.+)\s*')
|
r'(?P<nr_ptes_pages>\d+)\s+(?P<swapents_pages>\d+)\s+(?P<oom_score_adj>-?\d+)\s+(?P<name>.+)\s*')
|
||||||
"""Match content of process table"""
|
"""Match content of process table"""
|
||||||
|
|
||||||
|
pstable_start = '[ pid ]'
|
||||||
|
"""
|
||||||
|
Pattern to find the start of the process table
|
||||||
|
|
||||||
|
:type: str
|
||||||
|
"""
|
||||||
|
|
||||||
rec_version4kconfig = re.compile('.+')
|
rec_version4kconfig = re.compile('.+')
|
||||||
"""RE to match kernel version to kernel configuration"""
|
"""RE to match kernel version to kernel configuration"""
|
||||||
|
|
||||||
@ -416,7 +432,32 @@ class KernelConfig_4_9(KernelConfig_4_6):
|
|||||||
self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_OVERLAY_49)
|
self.EXTRACT_PATTERN.update(self.EXTRACT_PATTERN_OVERLAY_49)
|
||||||
|
|
||||||
|
|
||||||
class KernelConfig_5_0(KernelConfig_4_9):
|
class KernelConfig_4_15(KernelConfig_4_9):
|
||||||
|
# Support changes:
|
||||||
|
# * mm: consolidate page table accounting (af5b0f6a09e42c9f4fa87735f2a366748767b686)
|
||||||
|
|
||||||
|
# nr_ptes -> pgtables_bytes
|
||||||
|
# pr_info("[ pid ] uid tgid total_vm rss nr_ptes nr_pmds nr_puds swapents oom_score_adj name\n");
|
||||||
|
# pr_info("[ pid ] uid tgid total_vm rss pgtables_bytes swapents oom_score_adj name\n");
|
||||||
|
REC_PROCESS_LINE = re.compile(
|
||||||
|
r'^\[(?P<pid>[ \d]+)\]\s+(?P<uid>\d+)\s+(?P<tgid>\d+)\s+(?P<total_vm_pages>\d+)\s+(?P<rss_pages>\d+)\s+'
|
||||||
|
r'(?P<pgtables_bytes>\d+)\s+(?P<swapents_pages>\d+)\s+(?P<oom_score_adj>-?\d+)\s+(?P<name>.+)\s*')
|
||||||
|
|
||||||
|
pstable_items = ['pid', 'uid', 'tgid', 'total_vm_pages', 'rss_pages', 'pgtables_bytes', 'swapents_pages',
|
||||||
|
'oom_score_adj', 'name', 'notes']
|
||||||
|
|
||||||
|
pstable_html = ['PID', 'UID', 'TGID', 'Total VM', 'RSS', 'Page Table Bytes', 'Swap Entries Pages',
|
||||||
|
'OOM Adjustment', 'Name', 'Notes']
|
||||||
|
|
||||||
|
|
||||||
|
class KernelConfig_4_19(KernelConfig_4_15):
|
||||||
|
# Support changes:
|
||||||
|
# * mm, oom: describe task memory unit, larger PID pad (c3b78b11efbb2865433abf9d22c004ffe4a73f5c)
|
||||||
|
|
||||||
|
pstable_start = '[ pid ]'
|
||||||
|
|
||||||
|
|
||||||
|
class KernelConfig_5_0(KernelConfig_4_19):
|
||||||
# Support changes:
|
# Support changes:
|
||||||
# * "mm, oom: reorganize the oom report in dump_header" (ef8444ea01d7442652f8e1b8a8b94278cb57eafd)
|
# * "mm, oom: reorganize the oom report in dump_header" (ef8444ea01d7442652f8e1b8a8b94278cb57eafd)
|
||||||
|
|
||||||
@ -488,6 +529,8 @@ class KernelConfigRhel7(BaseKernelConfig):
|
|||||||
AllKernelConfigs = [
|
AllKernelConfigs = [
|
||||||
KernelConfig_5_8(),
|
KernelConfig_5_8(),
|
||||||
KernelConfig_5_0(),
|
KernelConfig_5_0(),
|
||||||
|
KernelConfig_4_15(),
|
||||||
|
KernelConfig_4_19(),
|
||||||
KernelConfig_4_9(),
|
KernelConfig_4_9(),
|
||||||
KernelConfig_4_6(),
|
KernelConfig_4_6(),
|
||||||
KernelConfigRhel7(),
|
KernelConfigRhel7(),
|
||||||
@ -931,21 +974,24 @@ 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
|
||||||
|
|
||||||
# extract process table
|
self._extract_pstable()
|
||||||
self.oom_result.details['_ps'] = {}
|
|
||||||
self.oom_entity.find_text('[ pid ]')
|
def _extract_pstable(self):
|
||||||
|
"""Extract process table"""
|
||||||
|
self.oom_result.details['_pstable'] = {}
|
||||||
|
self.oom_entity.find_text(self.oom_result.kconfig.pstable_start)
|
||||||
for line in self.oom_entity:
|
for line in self.oom_entity:
|
||||||
if not line.startswith('['):
|
if not line.startswith('['):
|
||||||
break
|
break
|
||||||
if line.startswith('[ pid ]'):
|
if line.startswith(self.oom_result.kconfig.pstable_start):
|
||||||
continue
|
continue
|
||||||
match = self.oom_result.kconfig.REC_PROCESS_LINE.match(line)
|
match = self.oom_result.kconfig.REC_PROCESS_LINE.match(line)
|
||||||
if match:
|
if match:
|
||||||
details = match.groupdict()
|
details = match.groupdict()
|
||||||
details['notes'] = ''
|
details['notes'] = ''
|
||||||
pid = details.pop('pid')
|
pid = details.pop('pid')
|
||||||
self.oom_result.details['_ps'][pid] = {}
|
self.oom_result.details['_pstable'][pid] = {}
|
||||||
self.oom_result.details['_ps'][pid].update(details)
|
self.oom_result.details['_pstable'][pid].update(details)
|
||||||
|
|
||||||
def _hex2flags(self, hexvalue, flag_definition):
|
def _hex2flags(self, hexvalue, flag_definition):
|
||||||
"""\
|
"""\
|
||||||
@ -1025,7 +1071,7 @@ class OOMAnalyser:
|
|||||||
if self.oom_result.details[item] is None:
|
if self.oom_result.details[item] is None:
|
||||||
self.oom_result.details[item] = '<not found>'
|
self.oom_result.details[item] = '<not found>'
|
||||||
continue
|
continue
|
||||||
if item.endswith('_kb') or item.endswith('_pages') or item.endswith('_pid') or \
|
if item.endswith('_bytes') or item.endswith('_kb') or item.endswith('_pages') or item.endswith('_pid') or \
|
||||||
item in ['killed_proc_score', 'trigger_proc_order', 'trigger_proc_oomscore']:
|
item in ['killed_proc_score', 'trigger_proc_order', 'trigger_proc_oomscore']:
|
||||||
try:
|
try:
|
||||||
self.oom_result.details[item] = int(self.oom_result.details[item])
|
self.oom_result.details[item] = int(self.oom_result.details[item])
|
||||||
@ -1034,9 +1080,9 @@ class OOMAnalyser:
|
|||||||
|
|
||||||
# __pragma__ ('nojsiter')
|
# __pragma__ ('nojsiter')
|
||||||
|
|
||||||
def _convert_numeric_process_values_to_integer(self):
|
def _convert_pstable_values_to_integer(self):
|
||||||
"""Convert numeric values in process table to integer values"""
|
"""Convert numeric values in process table to integer values"""
|
||||||
ps = self.oom_result.details['_ps']
|
ps = self.oom_result.details['_pstable']
|
||||||
ps_index = []
|
ps_index = []
|
||||||
# TODO Check if transcrypt issue: pragma jsiter for the whole block "for pid_str in ps: ..."
|
# TODO Check if transcrypt issue: pragma jsiter for the whole block "for pid_str in ps: ..."
|
||||||
# sets item in "for item in ['uid',..." to 0 instead of 'uid'
|
# sets item in "for item in ['uid',..." to 0 instead of 'uid'
|
||||||
@ -1044,13 +1090,17 @@ class OOMAnalyser:
|
|||||||
for pid_str in ps.keys():
|
for pid_str in ps.keys():
|
||||||
converted = {}
|
converted = {}
|
||||||
process = ps[pid_str]
|
process = ps[pid_str]
|
||||||
for item in self.oom_result.kconfig.ps_table_items:
|
for item in self.oom_result.kconfig.pstable_items:
|
||||||
if item == 'pid':
|
if item in self.oom_result.kconfig.pstable_non_ints:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
converted[item] = int(process[item])
|
converted[item] = int(process[item])
|
||||||
except:
|
except:
|
||||||
error('Converting process parameter "{}={}" to integer failed'.format(item, process[item]))
|
if item not in process:
|
||||||
|
pitem = '<not in process table>'
|
||||||
|
else:
|
||||||
|
pitem = process[item]
|
||||||
|
error('Converting process parameter "{}={}" to integer failed'.format(item, pitem))
|
||||||
|
|
||||||
converted['name'] = process['name']
|
converted['name'] = process['name']
|
||||||
converted['notes'] = process['notes']
|
converted['notes'] = process['notes']
|
||||||
@ -1060,7 +1110,7 @@ class OOMAnalyser:
|
|||||||
ps_index.append(pid_int)
|
ps_index.append(pid_int)
|
||||||
|
|
||||||
ps_index.sort(key=int)
|
ps_index.sort(key=int)
|
||||||
self.oom_result.details['_ps_index'] = ps_index
|
self.oom_result.details['_pstable_index'] = ps_index
|
||||||
|
|
||||||
def _calc_pstable_values(self):
|
def _calc_pstable_values(self):
|
||||||
"""Set additional notes to processes listed in the process table"""
|
"""Set additional notes to processes listed in the process table"""
|
||||||
@ -1068,12 +1118,12 @@ class OOMAnalyser:
|
|||||||
kpid = self.oom_result.details['killed_proc_pid']
|
kpid = self.oom_result.details['killed_proc_pid']
|
||||||
|
|
||||||
# sometimes the trigger process isn't part of the process table
|
# sometimes the trigger process isn't part of the process table
|
||||||
if tpid in self.oom_result.details['_ps']:
|
if tpid in self.oom_result.details['_pstable']:
|
||||||
self.oom_result.details['_ps'][tpid]['notes'] = 'trigger process'
|
self.oom_result.details['_pstable'][tpid]['notes'] = 'trigger process'
|
||||||
|
|
||||||
# assume the killed process may also not part of the process table
|
# assume the killed process may also not part of the process table
|
||||||
if kpid in self.oom_result.details['_ps']:
|
if kpid in self.oom_result.details['_pstable']:
|
||||||
self.oom_result.details['_ps'][kpid]['notes'] = 'killed process'
|
self.oom_result.details['_pstable'][kpid]['notes'] = 'killed process'
|
||||||
|
|
||||||
def _calc_trigger_process_values(self):
|
def _calc_trigger_process_values(self):
|
||||||
"""Calculate all values related with the trigger process"""
|
"""Calculate all values related with the trigger process"""
|
||||||
@ -1138,8 +1188,8 @@ class OOMAnalyser:
|
|||||||
else:
|
else:
|
||||||
self.oom_result.details['system_total_ramswap_kb'] = self.oom_result.details['system_total_ram_kb']
|
self.oom_result.details['system_total_ramswap_kb'] = self.oom_result.details['system_total_ram_kb']
|
||||||
total_rss_pages = 0
|
total_rss_pages = 0
|
||||||
for pid in self.oom_result.details['_ps'].keys():
|
for pid in self.oom_result.details['_pstable'].keys():
|
||||||
total_rss_pages += self.oom_result.details['_ps'][pid]['rss_pages']
|
total_rss_pages += self.oom_result.details['_pstable'][pid]['rss_pages']
|
||||||
self.oom_result.details['system_total_ram_used_kb'] = total_rss_pages * self.oom_result.details['page_size_kb']
|
self.oom_result.details['system_total_ram_used_kb'] = total_rss_pages * self.oom_result.details['page_size_kb']
|
||||||
|
|
||||||
self.oom_result.details['system_total_used_percent'] = int(100 *
|
self.oom_result.details['system_total_used_percent'] = int(100 *
|
||||||
@ -1176,7 +1226,7 @@ class OOMAnalyser:
|
|||||||
@see: self.details
|
@see: self.details
|
||||||
"""
|
"""
|
||||||
self._convert_numeric_results_to_integer()
|
self._convert_numeric_results_to_integer()
|
||||||
self._convert_numeric_process_values_to_integer()
|
self._convert_pstable_values_to_integer()
|
||||||
self._calc_pstable_values()
|
self._calc_pstable_values()
|
||||||
|
|
||||||
self._determinate_platform_and_distribution()
|
self._determinate_platform_and_distribution()
|
||||||
@ -1442,8 +1492,12 @@ oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,glob
|
|||||||
Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:8380kB, file-rss:12548kB, shmem-rss:0kB, UID:0 pgtables:104kB oom_score_adj:0
|
Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:8380kB, file-rss:12548kB, shmem-rss:0kB, UID:0 pgtables:104kB oom_score_adj:0
|
||||||
'''
|
'''
|
||||||
|
|
||||||
sorted_column = None
|
sorted_column_number = None
|
||||||
"""Processes will sort by values in this column"""
|
"""
|
||||||
|
Processes will sort by values in this column
|
||||||
|
|
||||||
|
@type: int
|
||||||
|
"""
|
||||||
|
|
||||||
sort_order = None
|
sort_order = None
|
||||||
"""Sort order for process values"""
|
"""Sort order for process values"""
|
||||||
@ -1534,6 +1588,12 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
else:
|
else:
|
||||||
content = "{} pages".format(content)
|
content = "{} pages".format(content)
|
||||||
|
|
||||||
|
if item.endswith('_bytes') and isinstance(content, int):
|
||||||
|
if content == 1:
|
||||||
|
content = "{} Byte".format(content)
|
||||||
|
else:
|
||||||
|
content = "{} Bytes".format(content)
|
||||||
|
|
||||||
if item.endswith('_kb') and isinstance(content, int):
|
if item.endswith('_kb') and isinstance(content, int):
|
||||||
if content == 1:
|
if content == 1:
|
||||||
content = "{} kByte".format(content)
|
content = "{} kByte".format(content)
|
||||||
@ -1568,21 +1628,41 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
|
|
||||||
toc_content.innerHTML = new_toc
|
toc_content.innerHTML = new_toc
|
||||||
|
|
||||||
def update_process_table(self):
|
def pstable_fill_HTML(self):
|
||||||
"""
|
"""
|
||||||
Re-create the process table with additional information
|
Create the process table with additional information
|
||||||
"""
|
"""
|
||||||
new_table = ''
|
# update table heading
|
||||||
table_content = document.getElementById('process_table')
|
for i, element in enumerate(document.querySelectorAll('#pstable_header > tr > td')):
|
||||||
|
element.classList.remove('pstable__row-pages--width', 'pstable__row-numeric--width',
|
||||||
|
'pstable__row-oom-score-adj--width')
|
||||||
|
|
||||||
for pid in self.oom_result.details['_ps_index']:
|
key = self.oom_result.kconfig.pstable_items[i]
|
||||||
|
if key in ['notes', 'names']:
|
||||||
|
klass = 'pstable__row-notes--width'
|
||||||
|
elif key == 'oom_score_adj':
|
||||||
|
klass = 'pstable__row-oom-score-adj--width'
|
||||||
|
elif key.endswith('_bytes') or key.endswith('_kb') or key.endswith('_pages'):
|
||||||
|
klass = 'pstable__row-pages--width'
|
||||||
|
else:
|
||||||
|
klass = "pstable__row-numeric--width"
|
||||||
|
element.firstChild.textContent = self.oom_result.kconfig.pstable_html[i]
|
||||||
|
element.classList.add(klass)
|
||||||
|
|
||||||
|
# create new table
|
||||||
|
new_table = ''
|
||||||
|
table_content = document.getElementById('pstable_content')
|
||||||
|
for pid in self.oom_result.details['_pstable_index']:
|
||||||
if pid == self.oom_result.details['trigger_proc_pid']:
|
if pid == self.oom_result.details['trigger_proc_pid']:
|
||||||
css_class = 'class="js-pstable__triggerproc--bgcolor"'
|
css_class = 'class="js-pstable__triggerproc--bgcolor"'
|
||||||
elif pid == self.oom_result.details['killed_proc_pid']:
|
elif pid == self.oom_result.details['killed_proc_pid']:
|
||||||
css_class = 'class="js-pstable__killedproc--bgcolor"'
|
css_class = 'class="js-pstable__killedproc--bgcolor"'
|
||||||
else:
|
else:
|
||||||
css_class = ''
|
css_class = ''
|
||||||
process = self.oom_result.details['_ps'][pid]
|
process = self.oom_result.details['_pstable'][pid]
|
||||||
|
fmt_list = [process[i] for i in self.oom_result.kconfig.pstable_items if not i == 'pid']
|
||||||
|
fmt_list.insert(0, css_class)
|
||||||
|
fmt_list.insert(1, pid)
|
||||||
line = """
|
line = """
|
||||||
<tr {}>
|
<tr {}>
|
||||||
<td>{}</td>
|
<td>{}</td>
|
||||||
@ -1596,32 +1676,22 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
<td>{}</td>
|
<td>{}</td>
|
||||||
<td>{}</td>
|
<td>{}</td>
|
||||||
</tr>
|
</tr>
|
||||||
""".format(css_class, pid, process['uid'], process['tgid'], process['total_vm_pages'], process['rss_pages'],
|
""".format(*fmt_list)
|
||||||
process['nr_ptes_pages'], process['swapents_pages'], process['oom_score_adj'], process['name'],
|
|
||||||
process['notes'])
|
|
||||||
new_table += line
|
new_table += line
|
||||||
|
|
||||||
table_content.innerHTML = new_table
|
table_content.innerHTML = new_table
|
||||||
|
|
||||||
self.set_sort_triangle()
|
def pstable_set_sort_triangle(self):
|
||||||
|
|
||||||
def set_sort_triangle(self):
|
|
||||||
"""Set the sorting symbols for all columns in the process table"""
|
"""Set the sorting symbols for all columns in the process table"""
|
||||||
# TODO Check operator overloading
|
for column_name in self.oom_result.kconfig.pstable_items:
|
||||||
# Operator overloading (Pragma opov) does not work in this context.
|
column_number = self.oom_result.kconfig.pstable_items.index(column_name)
|
||||||
# self.oom_result.kconfig.ps_table_items + ['notes'] will compile to a string
|
element_id = "js-pstable_sort_col{}".format(column_number)
|
||||||
# "pid,uid,tgid,total_vm_pages,rss_pages,nr_ptes_pages,swapents_pages,oom_score_adjNotes" and not to an
|
|
||||||
# array
|
|
||||||
ps_table_and_notes = self.oom_result.kconfig.ps_table_items[:]
|
|
||||||
ps_table_and_notes.append('notes')
|
|
||||||
for column_name in ps_table_and_notes:
|
|
||||||
element_id = "pstable_sort_{}".format(column_name)
|
|
||||||
element = document.getElementById(element_id)
|
element = document.getElementById(element_id)
|
||||||
if not element:
|
if not element:
|
||||||
internal_error('Missing id "{}" in process table.'.format(element_id))
|
internal_error('Missing id "{}" in process table.'.format(element_id))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if column_name == self.sorted_column:
|
if column_number == self.sorted_column_number:
|
||||||
if self.sort_order == 'descending':
|
if self.sort_order == 'descending':
|
||||||
element.innerHTML = self.svg_array_down
|
element.innerHTML = self.svg_array_down
|
||||||
else:
|
else:
|
||||||
@ -1645,22 +1715,31 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
while element.firstChild:
|
while element.firstChild:
|
||||||
element.removeChild(element.firstChild)
|
element.removeChild(element.firstChild)
|
||||||
|
|
||||||
# clear process table
|
|
||||||
element = document.getElementById('process_table')
|
|
||||||
while element.firstChild:
|
|
||||||
element.removeChild(element.firstChild)
|
|
||||||
|
|
||||||
# reset sort triangles
|
|
||||||
self.sorted_column = None
|
|
||||||
self.sort_order = None
|
|
||||||
self.set_sort_triangle()
|
|
||||||
|
|
||||||
# remove svg charts
|
# remove svg charts
|
||||||
for element_id in ('svg_swap', 'svg_ram'):
|
for element_id in ('svg_swap', 'svg_ram'):
|
||||||
element = document.getElementById(element_id)
|
element = document.getElementById(element_id)
|
||||||
while element.firstChild:
|
while element.firstChild:
|
||||||
element.removeChild(element.firstChild)
|
element.removeChild(element.firstChild)
|
||||||
|
|
||||||
|
self._clear_pstable()
|
||||||
|
|
||||||
|
def _clear_pstable(self):
|
||||||
|
"""Clear process table"""
|
||||||
|
element = document.getElementById('pstable_content')
|
||||||
|
while element.firstChild:
|
||||||
|
element.removeChild(element.firstChild)
|
||||||
|
|
||||||
|
# reset sort triangles
|
||||||
|
self.sorted_column_number = None
|
||||||
|
self.sort_order = None
|
||||||
|
self.pstable_set_sort_triangle()
|
||||||
|
|
||||||
|
# reset table heading
|
||||||
|
for i, element in enumerate(document.querySelectorAll('#pstable_header > tr > td')):
|
||||||
|
element.classList.remove('pstable__row-pages--width', 'pstable__row-numeric--width',
|
||||||
|
'pstable__row-oom-score-adj--width')
|
||||||
|
element.firstChild.textContent = "col {}".format(i + 1)
|
||||||
|
|
||||||
def svg_create_element(self, height, width, css_class):
|
def svg_create_element(self, height, width, css_class):
|
||||||
"""Return an empty SVG element"""
|
"""Return an empty SVG element"""
|
||||||
svg = document.createElementNS(self.svg_namespace, 'svg')
|
svg = document.createElementNS(self.svg_namespace, 'svg')
|
||||||
@ -1832,7 +1911,8 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
hide_elements('.js-killed-proc-score--show')
|
hide_elements('.js-killed-proc-score--show')
|
||||||
|
|
||||||
# generate process table
|
# generate process table
|
||||||
self.update_process_table()
|
self.pstable_fill_HTML()
|
||||||
|
self.pstable_set_sort_triangle()
|
||||||
|
|
||||||
# show/hide swap space
|
# show/hide swap space
|
||||||
if self.oom_result.swap_active:
|
if self.oom_result.swap_active:
|
||||||
@ -1883,23 +1963,28 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
element.textContent = self.oom_result.oom_text
|
element.textContent = self.oom_result.oom_text
|
||||||
self.toggle_oom(show=False)
|
self.toggle_oom(show=False)
|
||||||
|
|
||||||
def sort_pstable(self, column_name):
|
def sort_pstable(self, column_number):
|
||||||
"""Sort process table by the values in the given column"""
|
"""
|
||||||
|
Sort process table by values
|
||||||
|
|
||||||
|
:param int column_number: Number of column to sort
|
||||||
|
"""
|
||||||
# TODO Check operator overloading
|
# TODO Check operator overloading
|
||||||
# Operator overloading (Pragma opov) does not work in this context.
|
# Operator overloading (Pragma opov) does not work in this context.
|
||||||
# self.oom_result.kconfig.ps_table_items + ['notes'] will compile to a string
|
# self.oom_result.kconfig.pstable_items + ['notes'] will compile to a string
|
||||||
# "pid,uid,tgid,total_vm_pages,rss_pages,nr_ptes_pages,swapents_pages,oom_score_adjNotes" and not to an
|
# "pid,uid,tgid,total_vm_pages,rss_pages,nr_ptes_pages,swapents_pages,oom_score_adjNotes" and not to an
|
||||||
# array
|
# array
|
||||||
ps_table_and_notes = self.oom_result.kconfig.ps_table_items[:]
|
ps_table_and_notes = self.oom_result.kconfig.pstable_items[:]
|
||||||
ps_table_and_notes.append('notes')
|
ps_table_and_notes.append('notes')
|
||||||
|
column_name = ps_table_and_notes[column_number]
|
||||||
if column_name not in ps_table_and_notes:
|
if column_name not in ps_table_and_notes:
|
||||||
internal_error('Can not sort process table with an unknown column name "{}"'.format(column_name))
|
internal_error('Can not sort process table with an unknown column name "{}"'.format(column_name))
|
||||||
return
|
return
|
||||||
|
|
||||||
# reset sort order if the column has changes
|
# reset sort order if the column has changes
|
||||||
if column_name != self.sorted_column:
|
if column_number != self.sorted_column_number:
|
||||||
self.sort_order = None
|
self.sort_order = None
|
||||||
self.sorted_column = column_name
|
self.sorted_column_number = column_number
|
||||||
|
|
||||||
if not self.sort_order or self.sort_order == 'descending':
|
if not self.sort_order or self.sort_order == 'descending':
|
||||||
self.sort_order = 'ascending'
|
self.sort_order = 'ascending'
|
||||||
@ -1908,19 +1993,17 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
self.sort_order = 'descending'
|
self.sort_order = 'descending'
|
||||||
self.sort_psindex_by_column(column_name, True)
|
self.sort_psindex_by_column(column_name, True)
|
||||||
|
|
||||||
self.sorted_column = column_name
|
self.pstable_fill_HTML()
|
||||||
|
self.pstable_set_sort_triangle()
|
||||||
self.update_process_table()
|
|
||||||
|
|
||||||
def sort_psindex_by_column(self, column_name, reverse=False):
|
def sort_psindex_by_column(self, column_name, reverse=False):
|
||||||
"""
|
"""
|
||||||
Sort the pid list '_ps_index' based on the values in the process dict '_ps'.
|
Sort the pid list '_pstable_index' based on the values in the process dict '_pstable'.
|
||||||
|
|
||||||
Is uses bubble sort with all disadvantages but just a few lines of code
|
Is uses bubble sort with all disadvantages but just a few lines of code
|
||||||
"""
|
"""
|
||||||
|
ps = self.oom_result.details['_pstable']
|
||||||
ps = self.oom_result.details['_ps']
|
ps_index = self.oom_result.details['_pstable_index']
|
||||||
ps_index = self.oom_result.details['_ps_index']
|
|
||||||
|
|
||||||
def getvalue(column, pos):
|
def getvalue(column, pos):
|
||||||
if column == 'pid':
|
if column == 'pid':
|
||||||
@ -1928,7 +2011,7 @@ Out of memory: Killed process 651 (unattended-upgr) total-vm:108020kB, anon-rss:
|
|||||||
else:
|
else:
|
||||||
value = ps[ps_index[pos]][column]
|
value = ps[ps_index[pos]][column]
|
||||||
# JS sorts alphanumeric by default, convert values explicit to integers to sort numerically
|
# JS sorts alphanumeric by default, convert values explicit to integers to sort numerically
|
||||||
if column not in ['name', 'notes'] and value is not js_undefined:
|
if column not in self.oom_result.kconfig.pstable_non_ints and value is not js_undefined:
|
||||||
value = int(value)
|
value = int(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
6
test.py
6
test.py
@ -199,6 +199,9 @@ class TestInBrowser(TestBase):
|
|||||||
self.assertTrue('OOM killer was automatically triggered' in explanation.text,
|
self.assertTrue('OOM killer was automatically triggered' in explanation.text,
|
||||||
'Missing text "OOM killer was automatically triggered"')
|
'Missing text "OOM killer was automatically triggered"')
|
||||||
|
|
||||||
|
head = self.driver.find_element_by_id('pstable_header')
|
||||||
|
self.assertTrue('Page Table Entries' in head.text, 'Missing column head line "Page Table Entries"')
|
||||||
|
|
||||||
self.check_swap_active()
|
self.check_swap_active()
|
||||||
|
|
||||||
def check_results_ubuntu2110(self):
|
def check_results_ubuntu2110(self):
|
||||||
@ -216,6 +219,9 @@ class TestInBrowser(TestBase):
|
|||||||
self.assertFalse('with an OOM score of' in explanation.text,
|
self.assertFalse('with an OOM score of' in explanation.text,
|
||||||
'No OOM score but text "with an OOM score of"')
|
'No OOM score but text "with an OOM score of"')
|
||||||
|
|
||||||
|
head = self.driver.find_element_by_id('pstable_header')
|
||||||
|
self.assertTrue('Page Table Bytes' in head.text, 'Missing column head line "Page Table Bytes"')
|
||||||
|
|
||||||
self.check_swap_inactive()
|
self.check_swap_inactive()
|
||||||
|
|
||||||
def check_swap_inactive(self):
|
def check_swap_inactive(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user