diff --git a/OOMAnalyser.html b/OOMAnalyser.html
index d85677a..671bcd0 100644
--- a/OOMAnalyser.html
+++ b/OOMAnalyser.html
@@ -23,6 +23,9 @@
.js-text--default-show {
/* empty just used to show elements in the default view */
}
+ .js-text--display-none {
+ display: none;
+ }
.table__sub-section--bold {
font-weight: bold;
@@ -59,6 +62,13 @@
max-height: 200px;
}
+ .js-oom-automatic--show {
+ /* empty - used to show sections for automatically triggered OOMs */
+ }
+ .js-oom-manual--show {
+ /* empty - used to show sections for manually triggered OOMs */
+ }
+
.result__table {
border-collapse: collapse;
padding: 10px;
@@ -149,9 +159,6 @@
color: #D8000C;
background-color: #FFD2D2;
}
- .js-text--display-none {
- display: none;
- }
.license__text {
font-size: small;
@@ -282,16 +289,28 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
-
- The system couldn't satisfy this request and started the OOM killer to free memory. The OOM killer
- calculates a score for each process and terminates the process with the highest score to satisfy the
- initial memory request.
-
-
- The process "" (PID )
- requested
- () memory.
-
+
+
+ The OOM killer was automatically triggered to free memory, because the system couldn't satisfy the
+ memory request.
+ The OOM killer calculates a score for each process and terminates the process with the highest score
+ to satisfy the original memory request.
+
+
+ The process "" (PID )
+ requested
+ () memory.
+
+
+
+
+ The OOM killer was manually triggered (e.g. with "echo f > /proc/sysrq-trigger
")
+ by a user with root privileges.
+ There is no demand to free memory but the OOM killer started nevertheless.
+ The OOM killer calculates a score for each process and terminates the process with the highest score.
+
+
The process ""
(PID ) with an OOM score of
@@ -326,7 +345,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
Trigger Process |
-
+
|
(PID ) |
This process requests memory and is triggering thereby the OOM situation. |
@@ -342,7 +361,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
|
Bit mask indicating the cores on which the process can run. |
-
+
Requested memory (order) |
(2) pages /
@@ -842,6 +861,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
Fix to allow process names with spaces
Rework removal of unused information
Report uncaught errors to the user
+ Add support for manually triggered OOM (suggested by Mikko Rantalainen)
...
diff --git a/OOMAnalyser.py b/OOMAnalyser.py
index 90cf918..c943847 100644
--- a/OOMAnalyser.py
+++ b/OOMAnalyser.py
@@ -63,6 +63,13 @@ class OOMEntityState:
complete = 4
+class OOMEntityType:
+ """Enum for the type of the OOM"""
+ unknown = 0
+ automatic = 1
+ manual = 2
+
+
def is_visible(element):
return element.offsetWidth > 0 and element.offsetHeight > 0
@@ -79,6 +86,18 @@ def show_element(element_id):
element.classList.remove('js-text--display-none')
+def hide_elements(selector):
+ """Hide all matching elements by adding class js-text--display-none"""
+ for element in document.querySelectorAll(selector):
+ element.classList.add('js-text--display-none')
+
+
+def show_elements(selector):
+ """Show all matching elements by removing class js-text--display-none"""
+ for element in document.querySelectorAll(selector):
+ element.classList.remove('js-text--display-none')
+
+
def toggle(element_id):
"""Toggle the visibility of the given HTML element"""
element = document.getElementById(element_id)
@@ -420,6 +439,13 @@ class OOMResult:
:type: OOMEntityState
"""
+ oom_type = OOMEntityType.unknown
+ """
+ Type of this OOM (manually or automatically triggered)
+
+ :type: OOMEntityType
+ """
+
error_msg = ""
"""
Error message
@@ -450,7 +476,7 @@ class OOMAnalyser:
r'^(?P[\S ]+) invoked oom-killer: '
r'gfp_mask=(?P0x[a-z0-9]+)(\((?P[A-Z_|]+)\))?, '
r'(nodemask=(?P([\d,-]+|\(null\))), )?'
- r'order=(?P\d+), '
+ r'order=(?P-?\d+), '
r'oom_score_adj=(?P\d+)',
True,
),
@@ -674,6 +700,11 @@ class OOMAnalyser:
'does not find anything. This will cause subsequent errors.'.format(k, pattern))
# __pragma__ ('nojsiter')
+ if self.oom_result.details['trigger_proc_order'] == "-1":
+ self.oom_result.oom_type = OOMEntityType.manual
+ else:
+ self.oom_result.oom_type = OOMEntityType.automatic
+
self.oom_result.details['hardware_info'] = self._extract_block_from_next_pos('Hardware name:')
# strip "Call Trace" line at beginning and remove leading spaces
@@ -1308,16 +1339,13 @@ Killed process 6576 (mysqld) total-vm:33914892kB, anon-rss:20629004kB, file-rss:
def set_HTML_defaults(self):
"""Reset the HTML document but don't clean elements"""
# hide all elements marked to be hidden by default
- for element in document.querySelectorAll('.js-text--default-hide'):
- element.classList.add('js-text--display-none')
+ hide_elements('.js-text--default-hide')
# show all elements marked to be shown by default
- for element in document.querySelectorAll('.js-text--default-show'):
- element.classList.remove('js-text--display-none')
+ show_elements('.js-text--default-show')
# show hidden rows
- for element in document.querySelectorAll('table .js-text--display-none'):
- element.classList.remove('js-text--display-none')
+ show_elements('table .js-text--display-none')
# clear notification box
element = document.getElementById('notify_box')
@@ -1490,6 +1518,12 @@ Killed process 6576 (mysqld) total-vm:33914892kB, anon-rss:20629004kB, file-rss:
hide_element('input')
show_element('analysis')
+ if self.oom_result.oom_type == OOMEntityType.manual:
+ hide_elements('.js-oom-automatic--show')
+ show_elements('.js-oom-manual--show')
+ else:
+ show_elements('.js-oom-automatic--show')
+ hide_elements('.js-oom-manual--show')
for item in self.oom_result.details.keys():
# ignore internal items
diff --git a/test.py b/test.py
index 30fa0ae..4d17f88 100755
--- a/test.py
+++ b/test.py
@@ -190,6 +190,10 @@ class TestInBrowser(TestBase):
swap_total_kb = self.driver.find_element_by_class_name('swap_total_kb')
self.assertEqual(swap_total_kb.text, '8388604 kBytes')
+ explanation = self.driver.find_element_by_id('explanation')
+ self.assertTrue('OOM killer was automatically triggered' in explanation.text,
+ 'Missing text "OOM killer was automatically triggered"')
+
def test_010_load_page(self):
"""Test if the page is loading"""
assert "OOM Analyser" in self.driver.title
@@ -291,6 +295,17 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
self.check_results()
self.click_reset()
+ def test_070_manually_triggered_OOM(self):
+ """Test for manually triggered OOM"""
+ example = OOMAnalyser.OOMDisplay.example
+ example = example.replace('order=0', 'order=-1')
+ self.analyse_oom(example)
+ self.assert_on_warn_error()
+
+ explanation = self.driver.find_element_by_id('explanation')
+ self.assertTrue('OOM killer was manually triggered' in explanation.text,
+ 'Missing text "OOM killer was manually triggered"')
+
class TestPython(TestBase):
|