Separate analysis and visualisation

Extract code to display details from code to analyse/split the OOM.
This should simplify later extensions as well as later written unit
tests.
This commit is contained in:
Carsten Grohmann 2018-09-11 19:49:39 +02:00
parent ffd77573d6
commit 85a82a4770
2 changed files with 437 additions and 408 deletions

View File

@ -117,9 +117,9 @@ function goBack() {
<h2>Step 1 - Enter your OOM message</h2>
<textarea id="textarea_oom" cols="100" rows="20" autocomplete="off" title="OOM input field">Add your OOMhere</textarea>
<br/>
<button onclick="OOMAnalyser.oomAnalyser.analyse()" title="Analyse the OOM from the input area">Analyse</button>
<button onclick="OOMAnalyser.oomAnalyser.reset()" title="Clean the input area">Reset</button>
<button onclick="OOMAnalyser.oomAnalyser.copy_example()" title="Copy an example OOM into the input area">Insert example</button>
<button onclick="OOMAnalyser.OOMDisplayInstance.analyse_and_show()" title="Analyse the OOM from the input area and show it">Analyse</button>
<button onclick="OOMAnalyser.OOMDisplayInstance.reset_form()" title="Clean the input area">Reset</button>
<button onclick="OOMAnalyser.OOMDisplayInstance.copy_example_to_form()" title="Copy an example OOM into the input area">Insert example</button>
</div>
<p>
@ -131,7 +131,7 @@ function goBack() {
<h2>Step 2 - Results</h2>
<p>
Go back to
<a href="javascript:void(0);" onclick="OOMAnalyser.oomAnalyser.reset()" title="Run a new analysis">&quot;Step 1 - Enter your OOM message&quot;</a>
<a href="javascript:void(0);" onclick="OOMAnalyser.OOMDisplayInstance.reset_form()" title="Run a new analysis">&quot;Step 1 - Enter your OOM message&quot;</a>
to run a new analysis.
</p>
<p>
@ -550,7 +550,7 @@ function goBack() {
<tr>
<th scope="row" colspan="3">Entire OOM Message
<span class="click_msg_in_th">
<a href="javascript:void(0);" id="oom_toogle_msg" onclick="OOMAnalyser.oomAnalyser.toggle_oom()" title="Click to show/hide full OOM message">(click to hide)</a>
<a href="javascript:void(0);" id="oom_toogle_msg" onclick="OOMAnalyser.OOMDisplayInstance.toggle_oom()" title="Click to show/hide full OOM message">(click to hide)</a>
</span>
</th>
</tr>
@ -565,7 +565,7 @@ function goBack() {
<p>
Go back to
<a href="javascript:void(0);" onclick="OOMAnalyser.oomAnalyser.reset()" title="Run a new analysis">&quot;Step 1 - Enter your OOM message&quot;</a>
<a href="javascript:void(0);" onclick="OOMAnalyser.OOMDisplayInstance.reset()" title="Run a new analysis">&quot;Step 1 - Enter your OOM message&quot;</a>
to run a new analysis.
</p>

View File

@ -160,153 +160,7 @@ class OOM(object):
class OOMAnalyser(object):
example = u'''\
sed invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
sed cpuset=/ mems_allowed=0-1
CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-514.6.1.el7.x86_64 #1
Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012
ffff880182272f10 00000000021dcb0a ffff880418207938 ffffffff816861ac
ffff8804182079c8 ffffffff81681157 ffffffff810eab9c ffff8804182fe910
ffff8804182fe928 0000000000000202 ffff880182272f10 ffff8804182079b8
Call Trace:
[<ffffffff816861ac>] dump_stack+0x19/0x1b
[<ffffffff81681157>] dump_header+0x8e/0x225
[<ffffffff810eab9c>] ? ktime_get_ts64+0x4c/0xf0
[<ffffffff8113ccaf>] ? delayacct_end+0x8f/0xb0
[<ffffffff8118475e>] oom_kill_process+0x24e/0x3c0
[<ffffffff811841fd>] ? oom_unkillable_task+0xcd/0x120
[<ffffffff811842a6>] ? find_lock_task_mm+0x56/0xc0
[<ffffffff810937ee>] ? has_capability_noaudit+0x1e/0x30
[<ffffffff81184f96>] out_of_memory+0x4b6/0x4f0
[<ffffffff81681c60>] __alloc_pages_slowpath+0x5d7/0x725
[<ffffffff8118b0a5>] __alloc_pages_nodemask+0x405/0x420
[<ffffffff811cf25a>] alloc_pages_current+0xaa/0x170
[<ffffffff81180667>] __page_cache_alloc+0x97/0xb0
[<ffffffff811831b0>] filemap_fault+0x170/0x410
[<ffffffffa018f016>] ext4_filemap_fault+0x36/0x50 [ext4]
[<ffffffff811ac2ec>] __do_fault+0x4c/0xc0
[<ffffffff811ac783>] do_read_fault.isra.42+0x43/0x130
[<ffffffff811b0f11>] handle_mm_fault+0x6b1/0xfe0
[<ffffffff811b7825>] ? do_mmap_pgoff+0x305/0x3c0
[<ffffffff81691c94>] __do_page_fault+0x154/0x450
[<ffffffff81691fc5>] do_page_fault+0x35/0x90
[<ffffffff8168e288>] page_fault+0x28/0x30
Mem-Info:
active_anon:7355653 inactive_anon:660960 isolated_anon:0
active_file:1263 inactive_file:1167 isolated_file:32
unevictable:0 dirty:4 writeback:0 unstable:0
slab_reclaimable:27412 slab_unreclaimable:13708
mapped:4818 shmem:87896 pagetables:25222 bounce:0
free:39513 free_pcp:2958 free_cma:0
Node 0 DMA free:15872kB min:40kB low:48kB high:60kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes lowmem_reserve[]: 0 2780 15835 15835
Node 0 DMA32 free:59728kB min:7832kB low:9788kB high:11748kB active_anon:2154380kB inactive_anon:604748kB active_file:500kB inactive_file:112kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3094644kB managed:2848912kB mlocked:0kB dirty:0kB writeback:0kB mapped:4016kB shmem:5140kB slab_reclaimable:6448kB slab_unreclaimable:2796kB kernel_stack:1040kB pagetables:6876kB unstable:0kB bounce:0kB free_pcp:3788kB local_pcp:228kB free_cma:0kB writeback_tmp:0kB pages_scanned:28 all_unreclaimable? no lowmem_reserve[]: 0 0 13055 13055
Node 0 Normal free:36692kB min:36784kB low:45980kB high:55176kB active_anon:12301636kB inactive_anon:793132kB active_file:604kB inactive_file:176kB unevictable:0kB isolated(anon):0kB isolated(file):128kB present:13631488kB managed:13368348kB mlocked:0kB dirty:0kB writeback:0kB mapped:4108kB shmem:207940kB slab_reclaimable:47900kB slab_unreclaimable:28884kB kernel_stack:6624kB pagetables:43340kB unstable:0kB bounce:0kB free_pcp:4204kB local_pcp:640kB free_cma:0kB writeback_tmp:0kB pages_scanned:128 all_unreclaimable? no lowmem_reserve[]: 0 0 0 0
Node 1 Normal free:49436kB min:45444kB low:56804kB high:68164kB active_anon:14967844kB inactive_anon:1244560kB active_file:1552kB inactive_file:1992kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:16777212kB managed:16514220kB mlocked:0kB dirty:16kB writeback:0kB mapped:10760kB shmem:138504kB slab_reclaimable:55300kB slab_unreclaimable:23152kB kernel_stack:6176kB pagetables:50672kB unstable:0kB bounce:0kB free_pcp:3360kB local_pcp:248kB free_cma:0kB writeback_tmp:0kB pages_scanned:125777 all_unreclaimable? yes lowmem_reserve[]: 0 0 0 0
Node 0 DMA: 0*4kB 0*8kB 0*16kB 0*32kB 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15872kB
Node 0 DMA32: 203*4kB (UEM) 231*8kB (UEM) 259*16kB (UEM) 231*32kB (UEM) 157*64kB (UEM) 90*128kB (UEM) 49*256kB (UEM) 20*512kB (UE) 3*1024kB (UEM) 1*2048kB (M) 0*4096kB = 63668kB
Node 0 Normal: 1231*4kB (UEM) 391*8kB (UEM) 456*16kB (UEM) 342*32kB (UEM) 141*64kB (UEM) 23*128kB (UEM) 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 38260kB
Node 1 Normal: 2245*4kB (UEM) 732*8kB (UEM) 594*16kB (UEM) 396*32kB (UEM) 160*64kB (UEM) 16*128kB (UEM) 2*256kB (UM) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 50836kB
Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
Node 1 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
Node 1 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
100155 total pagecache pages
11342 pages in swap cache
Swap cache stats: add 31260615, delete 31249273, find 295999950/297583545
Free swap = 0kB
Total swap = 8388604kB
8379834 pages RAM
0 pages HighMem/MovableOnly
192987 pages reserved
[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[ 390] 0 390 39012 6739 78 51 0 systemd-journal
[ 433] 0 433 11104 2 22 360 -1000 systemd-udevd
[ 530] 0 530 13854 28 27 83 -1000 auditd
[ 559] 0 559 7692 65 19 87 0 systemd-logind
[ 563] 0 563 4817 41 14 36 0 irqbalance
[ 569] 87 569 7684 52 20 48 -900 dbus-daemon
[ 587] 32 587 16240 17 34 116 0 rpcbind
[ 647] 0 647 50303 11 36 113 0 gssproxy
[ 796] 0 796 193856 2897 207 112 0 rsyslogd
[ 818] 0 818 13177 0 27 146 0 vsftpd
[ 840] 0 840 62892 9 36 103 0 ypbind
[ 868] 0 868 21663 28 43 191 -1000 sshd
[ 871] 29 871 11126 2 25 222 0 rpc.statd
[ 907] 0 907 8044 4 21 53 0 atd
[ 916] 0 916 27509 2 10 30 0 agetty
[ 934] 0 934 27509 2 10 31 0 agetty
[ 1255] 0 1255 45716 1 39 337 0 rscd
[ 1268] 0 1268 45746 28 38 353 0 rscd
[ 1269] 0 1269 45716 29 38 311 0 rscd
[ 1285] 0 1285 23290 25 45 235 0 master
[ 1287] 89 1287 23379 52 47 242 0 qmgr
[ 1830] 0 1830 446643 959 68 1234 0 ovcd
[ 2062] 0 2062 144894 511 37 309 0 ovbbccb
[ 2121] 0 2121 33138 26 19 138 0 crond
[ 2136] 38 2136 7846 40 19 88 0 ntpd
[ 2451] 0 2451 177827 0 36 816 0 ovconfd
[ 8145] 0 8145 300303 1616 58 692 0 hpsensor
[ 8204] 0 8204 31508 119 31 328 0 opcmsgi
[ 8405] 0 8405 201479 1289 49 244 0 opcmsga
[ 8472] 0 8472 134080 236 46 514 0 opcmona
[ 8596] 0 8596 31377 172 29 301 0 opcle
[ 8658] 0 8658 81199 124 34 336 0 opcacta
[ 8685] 0 8685 137169 23313 97 3256 0 oacore
[ 6330] 12345 6330 7520 15 18 61 0 rotatelogs
[ 6331] 12345 6331 28318 0 12 83 0 run.sh
[ 6576] 12345 6576 8478546 5157063 15483 1527848 0 java
[27171] 12345 27171 7522 10 18 58 0 rotatelogs
[27172] 12345 27172 28320 3 11 94 0 run.sh
[27502] 12345 27502 4029300 2716569 6505 226225 0 java
[11729] 0 11729 64122 5003 79 2465 0 snmpd
[12130] 0 12130 122202 565 29 175 0 hpasmlited
[12166] 0 12166 11905 89 24 121 0 cmahealthd
[12190] 0 12190 11871 89 24 119 0 cmastdeqd
[12214] 0 12214 13707 84 31 211 0 cmahostd
[12237] 0 12237 12493 38 28 352 0 cmathreshd
[12276] 0 12276 12368 45 30 210 0 cmasm2d
[12299] 0 12299 12485 43 26 282 0 cmaperfd
[12324] 0 12324 31932 184 31 143 0 cmapeerd
[12352] 0 12352 14280 48 32 169 0 cmaeventd
[12379] 0 12379 14831 26 30 198 0 cmafcad
[12407] 0 12407 11806 12 25 128 0 cmasasd
[12436] 0 12436 14364 86 31 181 0 cmaidad
[12463] 0 12463 11288 15 25 125 0 cmaided
[12492] 0 12492 11805 14 26 127 0 cmascsid
[12523] 0 12523 92228 129 63 433 0 cmanicd
[14002] 0 14002 11803 12 25 128 0 cmasm2d
[32615] 0 32615 36254 323 73 7 0 sshd
[ 894] 12345 894 36254 328 70 5 0 sshd
[ 895] 12345 895 3389 123 11 0 0 ksh
[10620] 0 10620 36254 328 72 0 0 sshd
[10634] 38714 10634 36290 329 70 8 0 sshd
[10635] 38714 10635 14221 25 31 124 0 sftp-server
[29021] 0 29021 36254 314 69 0 0 sshd
[29025] 12345 29025 36254 316 67 0 0 sshd
[29026] 12345 29026 29286 96 12 1 0 ksh
[29051] 12345 29051 29494 330 12 74 0 svr05
[29979] 12345 29979 1666 42 9 0 0 less
[29662] 89 29662 23316 258 43 0 0 pickup
[26065] 89 26065 23317 256 45 0 0 trivial-rewrite
[26066] 89 26066 23353 265 45 0 0 cleanup
[26067] 89 26067 23368 271 45 0 0 smtp
[26743] 0 26743 36254 314 68 0 0 sshd
[26937] 12345 26937 36254 314 67 0 0 sshd
[26938] 12345 26938 29286 96 11 0 0 ksh
[27122] 12345 27122 29494 459 12 0 0 svr05
[28657] 0 28657 36254 314 74 0 0 sshd
[28702] 12345 28702 36254 314 72 0 0 sshd
[28703] 12345 28703 29286 97 11 0 0 ksh
[28993] 0 28993 36254 314 72 0 0 sshd
[28996] 12345 28996 29526 531 12 0 0 svr05
[29006] 12345 29006 36254 314 69 0 0 sshd
[29007] 12345 29007 29286 96 11 0 0 ksh
[29110] 12345 29110 29558 745 12 0 0 svr05
[29481] 12345 29481 29214 58 14 0 0 sed
[29752] 12345 29752 7522 296 19 0 0 rotatelogs
Out of memory: Kill process 6576 (java) score 651 or sacrifice child
Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0kB, shmem-rss:0kB
'''
"""Analyse an OOM object and calculate additional values"""
REC_INVOKED_OOMKILLER = re.compile(
r'^(?P<trigger_proc_name>[\w ]+) invoked oom-killer: '
@ -366,14 +220,6 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
REC_MEM_NODEINFO = re.compile(r'(^Node \d+ (DMA|Normal|hugepages).*(:?\n))+', re.MULTILINE)
mem_modinfo_entries = ("active_anon_pages", "inactive_anon_pages", "isolated_anon_pages",
"active_file_pages", "inactive_file_pages", "isolated_file_pages",
"unevictable_pages", "dirty_pages", "writeback_pages", "unstable_pages",
"slab_reclaimable_pages", "slab_unreclaimable_pages",
"mapped_pages", "shmem_pages", "pagetables_pages", "bounce_pages",
"free_pages", "free_pcp_pages", "free_cma_pages",
)
REC_PAGECACHE = re.compile(r'^(?P<pagecache_total_pages>\d+) total pagecache pages.*$', re.MULTILINE)
REC_SWAP = re.compile(
@ -425,37 +271,11 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
"""All lines of an OOM without leading timestamps"""
details = {}
"""Extracted details"""
"""Extracted result"""
# Reference to the OOM object
oom = None
svg_namespace = 'http://www.w3.org/2000/svg'
# from Sasha Trubetskoy - https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
svg_colours = [
'#e6194b', # Red
'#3cb44b', # Green
'#ffe119', # Yellow
'#0082c8', # Blue
'#f58231', # Orange
'#911eb4', # Purple
'#46f0f0', # Cyan
'#f032e6', # Magenta
'#d2f53c', # Lime
'#fabebe', # Pink
'#008080', # Teal
'#e6beff', # Lavender
'#aa6e28', # Brown
'#fffac8', # Beige
'#800000', # Maroon
'#aaffc3', # Mint
'#808000', # Olive
'#ffd8b1', # Coral
'#000080', # Navy
'#808080', # Grey
]
GFP_FLAGS = {
'GFP_ATOMIC': {'value': '__GFP_HIGH | __GFP_ATOMIC | __GFP_KSWAPD_RECLAIM'},
'GFP_KERNEL': {'value': '__GFP_RECLAIM | __GFP_IO | __GFP_FS'},
@ -511,155 +331,9 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
(see https://github.com/torvalds/linux/commit/e67d4ca79aaf9d13a00d229b1b1c96b86828e8ba#diff-020720d0699e3ae1afb6fcd815ca8500)
"""
def __init__(self):
self._set_defaults()
element = document.getElementById('version')
element.textContent = "v{}".format(VERSION)
def _set_single_item(self, item):
"""
Set content of a single item to the HTML element with the same name.
The content won't be formatted.
"""
element = document.getElementById(item)
if not element:
print("ERROR: HTML element not found: ", item)
return
content = self.details.get(item, '')
if isinstance(content, str):
content = content.strip()
element.textContent = content
if content == '<not found>':
row = element.parentNode
row.classList.add('hide_tablerow')
elif item.endswith('_kb'):
element.classList.add('kbytes')
elif item.endswith('_pages'):
element.classList.add('pages')
if DEBUG:
show_element('notify_box')
def _set_defaults(self, clean_oom=True):
"""\
Reset the whole HTML document
"""
if clean_oom:
document.getElementById('textarea_oom').value = "<paste your OOM here>"
hide_element("analysis")
hide_element("notify_box")
show_element("input")
# show hidden rows
for element in document.getElementsByClassName('hide_tablerow'):
element.classList.remove('hide_tablerow')
self.lines = []
def __init__(self, oom):
self.details = {}
for item in self.mem_modinfo_entries:
element = document.getElementById(item)
element.textContent = ""
# clear notification box
element = document.getElementById('notify_box')
while element.firstChild:
element.removeChild(element.firstChild)
hide_element('notify_box')
# remove svg charts
for element_id in ('svg_swap', 'svg_ram'):
element = document.getElementById(element_id)
while element.firstChild:
element.removeChild(element.firstChild)
def _create_svg_element(self, height, width):
"""
Return an empty SVG element
"""
svg = document.createElementNS(self.svg_namespace, 'svg')
svg.setAttribute('version', '1.1')
svg.setAttribute('height', height)
svg.setAttribute('width', width)
svg.setAttribute('viewBox', '0 0 {} {}'.format(width, height))
return svg
def _create_svg_rect(self, x=0, y=0, width=0, height=0, colour=None):
rect = document.createElementNS(self.svg_namespace, 'rect')
if x:
rect.setAttribute('x', x)
if y:
rect.setAttribute('y', y)
if width:
rect.setAttribute('width', width)
if height:
rect.setAttribute('height', height)
if colour:
rect.setAttribute('fill', colour)
return rect
def _generate_svg_bar_chart(self, *elements):
"""
Generate a SVG bar chart
"""
bar_height = 100
label_height = 80
length_factor = 4
overall_height = bar_height + label_height
overall_width = 100 * length_factor
svg = self._create_svg_element(overall_height, overall_width)
sum_all_elements = sum([length for unused, length in elements])
current_pos = 0
bar_group = document.createElementNS(self.svg_namespace, 'g')
bar_group.setAttribute('id', 'bar_group')
bar_group.setAttribute('stroke', 'black')
bar_group.setAttribute('stroke-width', 2)
nr_processed_elements = 0
for title, length in elements:
rect_len = int(100 * length / sum_all_elements) * length_factor
if not rect_len:
continue
colour = self.svg_colours[nr_processed_elements % len(self.svg_colours)]
rect = self._create_svg_rect(current_pos, 0, rect_len, bar_height, colour)
bar_group.appendChild(rect)
label_group = document.createElementNS(self.svg_namespace, 'g')
label_group.setAttribute('id', title)
colour_rect = self._create_svg_rect(0, 0, 20, 20, colour)
colour_rect.setAttribute('stroke', 'black')
colour_rect.setAttribute('stroke-width', 2)
text = document.createElementNS(self.svg_namespace, 'text')
text.setAttribute('x', '30')
text.setAttribute('y', '18')
text.textContent = title
label_group.appendChild(colour_rect)
label_group.appendChild(text)
# TODO replace hardcoded values
x = 5 + 125 * (nr_processed_elements // 2)
y = bar_height + 10 + (nr_processed_elements % 2) * 40
label_group.setAttribute('transform', 'translate({}, {})'.format(x, y))
bar_group.appendChild(label_group)
current_pos += rect_len
nr_processed_elements += 1
svg.appendChild(bar_group)
return svg
self.oom = oom
def _extract_block_from_next_pos(self, marker):
"""
@ -853,84 +527,350 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
# already fully processed and no own element to display -> delete otherwise an error msg will be shown
del self.details['trigger_proc_gfp_flags']
def _show_details(self):
"""
Show all extracted details as well as additionally generated information
"""
if DEBUG:
print(self.details)
hide_element("input")
show_element("analysis")
for item in self.details.keys():
self._set_single_item(item)
svg_swap = self._generate_svg_bar_chart(
('Swap Used', self.details['swap_used_kb']),
('Swap Free', self.details['swap_free_kb']),
('Swap Cached', self.details['swap_cache_kb']),
)
elem_svg_swap = document.getElementById('svg_swap')
elem_svg_swap.appendChild(svg_swap)
svg_ram = self._generate_svg_bar_chart(
('Active mem', self.details['active_anon_pages']),
('Inactive mem', self.details['inactive_anon_pages']),
('Isolated mem', self.details['isolated_anon_pages']),
('Active PC', self.details['active_file_pages']),
('Inactive PC', self.details['inactive_file_pages']),
('Isolated PC', self.details['isolated_file_pages']),
('Unevictable', self.details['unevictable_pages']),
('Dirty', self.details['dirty_pages']),
('Writeback', self.details['writeback_pages']),
('Unstable', self.details['unstable_pages']),
('Slab reclaimable', self.details['slab_reclaimable_pages']),
('Slab unreclaimable', self.details['slab_unreclaimable_pages']),
('Mapped', self.details['mapped_pages']),
('Shared', self.details['shmem_pages']),
('Pagetable', self.details['pagetables_pages']),
('Bounce', self.details['bounce_pages']),
('Free', self.details['free_pages']),
('Free PCP', self.details['free_pcp_pages']),
('Free CMA', self.details['free_cma_pages']),
)
elem_svg_ram = document.getElementById('svg_ram')
elem_svg_ram.appendChild(svg_ram)
element = document.getElementById('oom')
element.textContent = self.oom.text
self.toggle_oom(show=False)
def analyse(self):
# reset the output elements to default
self._set_defaults(False)
element = document.getElementById('textarea_oom')
oom_text = element.value
self.oom = OOM(oom_text)
if self.oom.state == "oom_complete":
pass
elif self.oom.state == "oom_started":
warning('The inserted OOM is incomplete - only the beginning has found.')
warning('The result may be incomplete!')
elif self.oom.state == "oom_invalid":
error('The inserted text is not a valid OOM!')
return
else:
error('Invalid state "{}" after the OOM has formally checked!'.format(self.oom.state))
return
"""Return the analysis of the given OOM object"""
self._extract_from_oom_text()
self._calc_from_oom_details()
self._show_details()
return self.details
def reset(self):
self._set_defaults()
def copy_example(self):
class OOMDisplay(object):
"""Display the OOM analysis"""
oom_details = {}
"""Extracted result"""
example = u'''\
sed invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
sed cpuset=/ mems_allowed=0-1
CPU: 4 PID: 29481 Comm: sed Not tainted 3.10.0-514.6.1.el7.x86_64 #1
Hardware name: HP ProLiant DL385 G7, BIOS A18 12/08/2012
ffff880182272f10 00000000021dcb0a ffff880418207938 ffffffff816861ac
ffff8804182079c8 ffffffff81681157 ffffffff810eab9c ffff8804182fe910
ffff8804182fe928 0000000000000202 ffff880182272f10 ffff8804182079b8
Call Trace:
[<ffffffff816861ac>] dump_stack+0x19/0x1b
[<ffffffff81681157>] dump_header+0x8e/0x225
[<ffffffff810eab9c>] ? ktime_get_ts64+0x4c/0xf0
[<ffffffff8113ccaf>] ? delayacct_end+0x8f/0xb0
[<ffffffff8118475e>] oom_kill_process+0x24e/0x3c0
[<ffffffff811841fd>] ? oom_unkillable_task+0xcd/0x120
[<ffffffff811842a6>] ? find_lock_task_mm+0x56/0xc0
[<ffffffff810937ee>] ? has_capability_noaudit+0x1e/0x30
[<ffffffff81184f96>] out_of_memory+0x4b6/0x4f0
[<ffffffff81681c60>] __alloc_pages_slowpath+0x5d7/0x725
[<ffffffff8118b0a5>] __alloc_pages_nodemask+0x405/0x420
[<ffffffff811cf25a>] alloc_pages_current+0xaa/0x170
[<ffffffff81180667>] __page_cache_alloc+0x97/0xb0
[<ffffffff811831b0>] filemap_fault+0x170/0x410
[<ffffffffa018f016>] ext4_filemap_fault+0x36/0x50 [ext4]
[<ffffffff811ac2ec>] __do_fault+0x4c/0xc0
[<ffffffff811ac783>] do_read_fault.isra.42+0x43/0x130
[<ffffffff811b0f11>] handle_mm_fault+0x6b1/0xfe0
[<ffffffff811b7825>] ? do_mmap_pgoff+0x305/0x3c0
[<ffffffff81691c94>] __do_page_fault+0x154/0x450
[<ffffffff81691fc5>] do_page_fault+0x35/0x90
[<ffffffff8168e288>] page_fault+0x28/0x30
Mem-Info:
active_anon:7355653 inactive_anon:660960 isolated_anon:0
active_file:1263 inactive_file:1167 isolated_file:32
unevictable:0 dirty:4 writeback:0 unstable:0
slab_reclaimable:27412 slab_unreclaimable:13708
mapped:4818 shmem:87896 pagetables:25222 bounce:0
free:39513 free_pcp:2958 free_cma:0
Node 0 DMA free:15872kB min:40kB low:48kB high:60kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes lowmem_reserve[]: 0 2780 15835 15835
Node 0 DMA32 free:59728kB min:7832kB low:9788kB high:11748kB active_anon:2154380kB inactive_anon:604748kB active_file:500kB inactive_file:112kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3094644kB managed:2848912kB mlocked:0kB dirty:0kB writeback:0kB mapped:4016kB shmem:5140kB slab_reclaimable:6448kB slab_unreclaimable:2796kB kernel_stack:1040kB pagetables:6876kB unstable:0kB bounce:0kB free_pcp:3788kB local_pcp:228kB free_cma:0kB writeback_tmp:0kB pages_scanned:28 all_unreclaimable? no lowmem_reserve[]: 0 0 13055 13055
Node 0 Normal free:36692kB min:36784kB low:45980kB high:55176kB active_anon:12301636kB inactive_anon:793132kB active_file:604kB inactive_file:176kB unevictable:0kB isolated(anon):0kB isolated(file):128kB present:13631488kB managed:13368348kB mlocked:0kB dirty:0kB writeback:0kB mapped:4108kB shmem:207940kB slab_reclaimable:47900kB slab_unreclaimable:28884kB kernel_stack:6624kB pagetables:43340kB unstable:0kB bounce:0kB free_pcp:4204kB local_pcp:640kB free_cma:0kB writeback_tmp:0kB pages_scanned:128 all_unreclaimable? no lowmem_reserve[]: 0 0 0 0
Node 1 Normal free:49436kB min:45444kB low:56804kB high:68164kB active_anon:14967844kB inactive_anon:1244560kB active_file:1552kB inactive_file:1992kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:16777212kB managed:16514220kB mlocked:0kB dirty:16kB writeback:0kB mapped:10760kB shmem:138504kB slab_reclaimable:55300kB slab_unreclaimable:23152kB kernel_stack:6176kB pagetables:50672kB unstable:0kB bounce:0kB free_pcp:3360kB local_pcp:248kB free_cma:0kB writeback_tmp:0kB pages_scanned:125777 all_unreclaimable? yes lowmem_reserve[]: 0 0 0 0
Node 0 DMA: 0*4kB 0*8kB 0*16kB 0*32kB 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15872kB
Node 0 DMA32: 203*4kB (UEM) 231*8kB (UEM) 259*16kB (UEM) 231*32kB (UEM) 157*64kB (UEM) 90*128kB (UEM) 49*256kB (UEM) 20*512kB (UE) 3*1024kB (UEM) 1*2048kB (M) 0*4096kB = 63668kB
Node 0 Normal: 1231*4kB (UEM) 391*8kB (UEM) 456*16kB (UEM) 342*32kB (UEM) 141*64kB (UEM) 23*128kB (UEM) 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 38260kB
Node 1 Normal: 2245*4kB (UEM) 732*8kB (UEM) 594*16kB (UEM) 396*32kB (UEM) 160*64kB (UEM) 16*128kB (UEM) 2*256kB (UM) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 50836kB
Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
Node 1 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
Node 1 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
100155 total pagecache pages
11342 pages in swap cache
Swap cache stats: add 31260615, delete 31249273, find 295999950/297583545
Free swap = 0kB
Total swap = 8388604kB
8379834 pages RAM
0 pages HighMem/MovableOnly
192987 pages reserved
[ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name
[ 390] 0 390 39012 6739 78 51 0 systemd-journal
[ 433] 0 433 11104 2 22 360 -1000 systemd-udevd
[ 530] 0 530 13854 28 27 83 -1000 auditd
[ 559] 0 559 7692 65 19 87 0 systemd-logind
[ 563] 0 563 4817 41 14 36 0 irqbalance
[ 569] 87 569 7684 52 20 48 -900 dbus-daemon
[ 587] 32 587 16240 17 34 116 0 rpcbind
[ 647] 0 647 50303 11 36 113 0 gssproxy
[ 796] 0 796 193856 2897 207 112 0 rsyslogd
[ 818] 0 818 13177 0 27 146 0 vsftpd
[ 840] 0 840 62892 9 36 103 0 ypbind
[ 868] 0 868 21663 28 43 191 -1000 sshd
[ 871] 29 871 11126 2 25 222 0 rpc.statd
[ 907] 0 907 8044 4 21 53 0 atd
[ 916] 0 916 27509 2 10 30 0 agetty
[ 934] 0 934 27509 2 10 31 0 agetty
[ 1255] 0 1255 45716 1 39 337 0 rscd
[ 1268] 0 1268 45746 28 38 353 0 rscd
[ 1269] 0 1269 45716 29 38 311 0 rscd
[ 1285] 0 1285 23290 25 45 235 0 master
[ 1287] 89 1287 23379 52 47 242 0 qmgr
[ 1830] 0 1830 446643 959 68 1234 0 ovcd
[ 2062] 0 2062 144894 511 37 309 0 ovbbccb
[ 2121] 0 2121 33138 26 19 138 0 crond
[ 2136] 38 2136 7846 40 19 88 0 ntpd
[ 2451] 0 2451 177827 0 36 816 0 ovconfd
[ 8145] 0 8145 300303 1616 58 692 0 hpsensor
[ 8204] 0 8204 31508 119 31 328 0 opcmsgi
[ 8405] 0 8405 201479 1289 49 244 0 opcmsga
[ 8472] 0 8472 134080 236 46 514 0 opcmona
[ 8596] 0 8596 31377 172 29 301 0 opcle
[ 8658] 0 8658 81199 124 34 336 0 opcacta
[ 8685] 0 8685 137169 23313 97 3256 0 oacore
[ 6330] 12345 6330 7520 15 18 61 0 rotatelogs
[ 6331] 12345 6331 28318 0 12 83 0 run.sh
[ 6576] 12345 6576 8478546 5157063 15483 1527848 0 java
[27171] 12345 27171 7522 10 18 58 0 rotatelogs
[27172] 12345 27172 28320 3 11 94 0 run.sh
[27502] 12345 27502 4029300 2716569 6505 226225 0 java
[11729] 0 11729 64122 5003 79 2465 0 snmpd
[12130] 0 12130 122202 565 29 175 0 hpasmlited
[12166] 0 12166 11905 89 24 121 0 cmahealthd
[12190] 0 12190 11871 89 24 119 0 cmastdeqd
[12214] 0 12214 13707 84 31 211 0 cmahostd
[12237] 0 12237 12493 38 28 352 0 cmathreshd
[12276] 0 12276 12368 45 30 210 0 cmasm2d
[12299] 0 12299 12485 43 26 282 0 cmaperfd
[12324] 0 12324 31932 184 31 143 0 cmapeerd
[12352] 0 12352 14280 48 32 169 0 cmaeventd
[12379] 0 12379 14831 26 30 198 0 cmafcad
[12407] 0 12407 11806 12 25 128 0 cmasasd
[12436] 0 12436 14364 86 31 181 0 cmaidad
[12463] 0 12463 11288 15 25 125 0 cmaided
[12492] 0 12492 11805 14 26 127 0 cmascsid
[12523] 0 12523 92228 129 63 433 0 cmanicd
[14002] 0 14002 11803 12 25 128 0 cmasm2d
[32615] 0 32615 36254 323 73 7 0 sshd
[ 894] 12345 894 36254 328 70 5 0 sshd
[ 895] 12345 895 3389 123 11 0 0 ksh
[10620] 0 10620 36254 328 72 0 0 sshd
[10634] 38714 10634 36290 329 70 8 0 sshd
[10635] 38714 10635 14221 25 31 124 0 sftp-server
[29021] 0 29021 36254 314 69 0 0 sshd
[29025] 12345 29025 36254 316 67 0 0 sshd
[29026] 12345 29026 29286 96 12 1 0 ksh
[29051] 12345 29051 29494 330 12 74 0 svr05
[29979] 12345 29979 1666 42 9 0 0 less
[29662] 89 29662 23316 258 43 0 0 pickup
[26065] 89 26065 23317 256 45 0 0 trivial-rewrite
[26066] 89 26066 23353 265 45 0 0 cleanup
[26067] 89 26067 23368 271 45 0 0 smtp
[26743] 0 26743 36254 314 68 0 0 sshd
[26937] 12345 26937 36254 314 67 0 0 sshd
[26938] 12345 26938 29286 96 11 0 0 ksh
[27122] 12345 27122 29494 459 12 0 0 svr05
[28657] 0 28657 36254 314 74 0 0 sshd
[28702] 12345 28702 36254 314 72 0 0 sshd
[28703] 12345 28703 29286 97 11 0 0 ksh
[28993] 0 28993 36254 314 72 0 0 sshd
[28996] 12345 28996 29526 531 12 0 0 svr05
[29006] 12345 29006 36254 314 69 0 0 sshd
[29007] 12345 29007 29286 96 11 0 0 ksh
[29110] 12345 29110 29558 745 12 0 0 svr05
[29481] 12345 29481 29214 58 14 0 0 sed
[29752] 12345 29752 7522 296 19 0 0 rotatelogs
Out of memory: Kill process 6576 (java) score 651 or sacrifice child
Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0kB, shmem-rss:0kB
'''
mem_modinfo_entries = ("active_anon_pages", "inactive_anon_pages", "isolated_anon_pages",
"active_file_pages", "inactive_file_pages", "isolated_file_pages",
"unevictable_pages", "dirty_pages", "writeback_pages", "unstable_pages",
"slab_reclaimable_pages", "slab_unreclaimable_pages",
"mapped_pages", "shmem_pages", "pagetables_pages", "bounce_pages",
"free_pages", "free_pcp_pages", "free_cma_pages",
)
svg_namespace = 'http://www.w3.org/2000/svg'
# from Sasha Trubetskoy - https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
svg_colours = [
'#e6194b', # Red
'#3cb44b', # Green
'#ffe119', # Yellow
'#0082c8', # Blue
'#f58231', # Orange
'#911eb4', # Purple
'#46f0f0', # Cyan
'#f032e6', # Magenta
'#d2f53c', # Lime
'#fabebe', # Pink
'#008080', # Teal
'#e6beff', # Lavender
'#aa6e28', # Brown
'#fffac8', # Beige
'#800000', # Maroon
'#aaffc3', # Mint
'#808000', # Olive
'#ffd8b1', # Coral
'#000080', # Navy
'#808080', # Grey
]
def __init__(self):
self.set_HTML_defaults()
element = document.getElementById('version')
element.textContent = "v{}".format(VERSION)
def _set_single_item(self, item):
"""
Set content of a single item to the HTML element with the same name.
The content won't be formatted.
"""
element = document.getElementById(item)
if not element:
print("ERROR: HTML element not found: ", item)
return
content = self.oom_details.get(item, '')
if isinstance(content, str):
content = content.strip()
element.textContent = content
if content == '<not found>':
row = element.parentNode
row.classList.add('hide_tablerow')
elif item.endswith('_kb'):
element.classList.add('kbytes')
elif item.endswith('_pages'):
element.classList.add('pages')
if DEBUG:
show_element('notify_box')
def set_HTML_defaults(self, clean_oom=True):
"""Reset the whole HTML document"""
if clean_oom:
document.getElementById('textarea_oom').value = "<paste your OOM here>"
hide_element("analysis")
hide_element("notify_box")
show_element("input")
# show hidden rows
for element in document.getElementsByClassName('hide_tablerow'):
element.classList.remove('hide_tablerow')
for item in self.mem_modinfo_entries:
element = document.getElementById(item)
element.textContent = ""
# clear notification box
element = document.getElementById('notify_box')
while element.firstChild:
element.removeChild(element.firstChild)
hide_element('notify_box')
# remove svg charts
for element_id in ('svg_swap', 'svg_ram'):
element = document.getElementById(element_id)
while element.firstChild:
element.removeChild(element.firstChild)
def svg_create_element(self, height, width):
"""Return an empty SVG element"""
svg = document.createElementNS(self.svg_namespace, 'svg')
svg.setAttribute('version', '1.1')
svg.setAttribute('height', height)
svg.setAttribute('width', width)
svg.setAttribute('viewBox', '0 0 {} {}'.format(width, height))
return svg
def svg_create_rect(self, x=0, y=0, width=0, height=0, colour=None):
rect = document.createElementNS(self.svg_namespace, 'rect')
if x:
rect.setAttribute('x', x)
if y:
rect.setAttribute('y', y)
if width:
rect.setAttribute('width', width)
if height:
rect.setAttribute('height', height)
if colour:
rect.setAttribute('fill', colour)
return rect
def svg_generate_bar_chart(self, *elements):
"""Generate a SVG bar chart"""
bar_height = 100
label_height = 80
length_factor = 4
overall_height = bar_height + label_height
overall_width = 100 * length_factor
svg = self.svg_create_element(overall_height, overall_width)
sum_all_elements = sum([length for unused, length in elements])
current_pos = 0
bar_group = document.createElementNS(self.svg_namespace, 'g')
bar_group.setAttribute('id', 'bar_group')
bar_group.setAttribute('stroke', 'black')
bar_group.setAttribute('stroke-width', 2)
nr_processed_elements = 0
for title, length in elements:
rect_len = int(100 * length / sum_all_elements) * length_factor
if not rect_len:
continue
colour = self.svg_colours[nr_processed_elements % len(self.svg_colours)]
rect = self.svg_create_rect(current_pos, 0, rect_len, bar_height, colour)
bar_group.appendChild(rect)
label_group = document.createElementNS(self.svg_namespace, 'g')
label_group.setAttribute('id', title)
colour_rect = self.svg_create_rect(0, 0, 20, 20, colour)
colour_rect.setAttribute('stroke', 'black')
colour_rect.setAttribute('stroke-width', 2)
text = document.createElementNS(self.svg_namespace, 'text')
text.setAttribute('x', '30')
text.setAttribute('y', '18')
text.textContent = title
label_group.appendChild(colour_rect)
label_group.appendChild(text)
# TODO replace hardcoded values
x = 5 + 125 * (nr_processed_elements // 2)
y = bar_height + 10 + (nr_processed_elements % 2) * 40
label_group.setAttribute('transform', 'translate({}, {})'.format(x, y))
bar_group.appendChild(label_group)
current_pos += rect_len
nr_processed_elements += 1
svg.appendChild(bar_group)
return svg
def copy_example_to_form(self):
document.getElementById('textarea_oom').value = self.example
def reset_form(self):
self.set_HTML_defaults()
def toggle_oom(self, show=False):
"""Toggle the visibility of the full OOM message"""
oom_element = document.getElementById('oom')
@ -944,5 +884,94 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
row_with_oom.classList.add('hide_tablerow')
toggle_msg.text = "(click to show)"
def analyse_and_show(self):
"""Analyse the OOM text inserted into the form and show the results"""
self.oom = OOM(self.load_from_form())
if not self.is_valid(self.oom):
self.oom = None
return
oomAnalyser = OOMAnalyser()
# set defaults
self.oom_details.clear()
self.set_HTML_defaults(False)
# analyse
analyser = OOMAnalyser(self.oom)
analyser.analyse()
self.oom_details = analyser.details
# display results
self.show()
def load_from_form(self):
element = document.getElementById('textarea_oom')
oom_text = element.value
return oom_text
def is_valid(self, oom):
"""
Return True for a complete OOM otherwise False and a warning msg for a incomplete or an error msg
if the start sequence was not found.
"""
if oom.state == "oom_complete":
return True
elif oom.state == "oom_started":
warning('The inserted OOM is incomplete - only the beginning has found.')
warning('The result may be incomplete!')
elif oom.state == "oom_invalid":
error('The inserted text is not a valid OOM!')
else:
error('Invalid state "{}" after the OOM has formally checked!'.format(self.oom.state))
return False
def show(self):
"""
Show all extracted details as well as additionally generated information
"""
if DEBUG:
print(self.oom_details)
hide_element("input")
show_element("analysis")
for item in self.oom_details.keys():
self._set_single_item(item)
svg_swap = self.svg_generate_bar_chart(
('Swap Used', self.oom_details['swap_used_kb']),
('Swap Free', self.oom_details['swap_free_kb']),
('Swap Cached', self.oom_details['swap_cache_kb']),
)
elem_svg_swap = document.getElementById('svg_swap')
elem_svg_swap.appendChild(svg_swap)
svg_ram = self.svg_generate_bar_chart(
('Active mem', self.oom_details['active_anon_pages']),
('Inactive mem', self.oom_details['inactive_anon_pages']),
('Isolated mem', self.oom_details['isolated_anon_pages']),
('Active PC', self.oom_details['active_file_pages']),
('Inactive PC', self.oom_details['inactive_file_pages']),
('Isolated PC', self.oom_details['isolated_file_pages']),
('Unevictable', self.oom_details['unevictable_pages']),
('Dirty', self.oom_details['dirty_pages']),
('Writeback', self.oom_details['writeback_pages']),
('Unstable', self.oom_details['unstable_pages']),
('Slab reclaimable', self.oom_details['slab_reclaimable_pages']),
('Slab unreclaimable', self.oom_details['slab_unreclaimable_pages']),
('Mapped', self.oom_details['mapped_pages']),
('Shared', self.oom_details['shmem_pages']),
('Pagetable', self.oom_details['pagetables_pages']),
('Bounce', self.oom_details['bounce_pages']),
('Free', self.oom_details['free_pages']),
('Free PCP', self.oom_details['free_pcp_pages']),
('Free CMA', self.oom_details['free_cma_pages']),
)
elem_svg_ram = document.getElementById('svg_ram')
elem_svg_ram.appendChild(svg_ram)
element = document.getElementById('oom')
element.textContent = self.oom.text
self.toggle_oom(show=False)
OOMDisplayInstance = OOMDisplay()