~carstengrohmann/OOMAnalyser

c1a5ed34203f4f944f2f1b3de591021635a6742f — Carsten Grohmann a month ago 8ed7678
Add support for systems w/o swap

Suggested-by: Mikko Rantalainen <mikko.rantalainen@gmail.com>
3 files changed, 102 insertions(+), 26 deletions(-)

M OOMAnalyser.html
M OOMAnalyser.py
M test.py
M OOMAnalyser.html => OOMAnalyser.html +36 -14
@@ 69,6 69,13 @@
            /* empty - used to show sections for manually triggered OOMs */
        }

        .js-swap-active--show {
            /* empty - used to show if the swap space is activated */
        }
        .js-swap-inactive--show {
            /* empty - used to show if the swap space is not activated */
        }

        .result__table {
            border-collapse: collapse;
            padding: 10px;


@@ 317,14 324,25 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
            has been terminated. It uses <span class="killed_proc_rss_percent"></span>
            (<span class="killed_proc_total_rss_kb"></span>) of the resident memory.
        </p>
        <p>
            The system has <span class="system_total_ram_kb"></span> physical memory and
            <span class="swap_total_kb"></span> swap space. That's <span class="system_total_ramswap_kb"></span> total.
            <span class="system_total_used_percent"></span>
            (<span class="system_total_ram_used_kb"></span> out of <span class="system_total_ram_kb"></span>) physical
            memory and <span class="system_swap_used_percent"></span>
            (<span class="swap_used_kb"></span> out of <span class="swap_total_kb"></span>) swap space are in use.
        </p>

        <div class="js-text--default-show js-swap-active--show">
            <p>
                The system has <span class="system_total_ram_kb"></span> physical memory and
                <span class="swap_total_kb"></span> swap space. That's <span class="system_total_ramswap_kb"></span>
                total. <span class="system_total_used_percent"></span>
                (<span class="system_total_ram_used_kb"></span> out of <span class="system_total_ram_kb"></span>)
                physical memory and <span class="system_swap_used_percent"></span>
                (<span class="swap_used_kb"></span> out of <span class="swap_total_kb"></span>) swap space are in use.
            </p>
        </div>
        <div class="js-text--default-show js-swap-inactive--show">
            <p>
                The system has <span class="system_total_ram_kb"></span> physical memory and no swap space.
                <span class="system_total_used_percent"></span>
                (<span class="system_total_ram_used_kb"></span> out of <span class="system_total_ram_kb"></span>)
                physical memory are in use.
            </p>
        </div>
    </div>

    <h3>Details of analysis</h3>


@@ 445,31 463,34 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
            <td>RAM Summary</td>
            <td class="result__table--border" colspan="2"><div id="svg_ram"></div></td>
        </tr>
        <tr>
        <tr class="js-text--default-show js-swap-active--show">>
            <td>Swap Summary</td>
            <td class="result__table--border" colspan="2"><div id="svg_swap"></div></td>
        </tr>

        <!-- Swap Usage -->

        <tr>
        <tr class="js-text--default-show">
            <th class="table__sub-section--bold" colspan="3" scope="row">Swap Usage</th>
        </tr>
        <tr>
        <tr class="js-text--default-show js-swap-inactive--show">
            <td colspan="3">No swap space available</td>
        </tr>
        <tr class="js-text--default-show js-swap-active--show">
            <td>Swap Total</td>
            <td class="swap_total_kb text--align-right"></td>
            <td>Total amount of swap space available.
                <a class="a__footnote" href="#footnote-proc5">[1]</a>
            </td>
        </tr>
        <tr>
        <tr class="js-text--default-show js-swap-active--show">
            <td>Swap Free</td>
            <td class="swap_free_kb text--align-right"></td>
            <td>Amount of swap space that is currently unused.
                <a class="a__footnote" href="#footnote-proc5">[1]</a>
            </td>
        </tr>
        <tr>
        <tr class="js-text--default-show js-swap-active--show">
            <td>Swap Cached</td>
            <td class="swap_cache_kb text--align-right"></td>
            <td>Memory that once was swapped out, is swapped back in


@@ 480,7 501,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
                <a class="a__footnote" href="#footnote-proc5">[1]</a>
            </td>
        </tr>
        <tr>
        <tr class="js-text--default-show js-swap-active--show">
            <td>Swap Used</td>
            <td class="swap_used_kb text--align-right"></td>
            <td>Amount of used swap space w/o cached swap <br>


@@ 862,6 883,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
        <li>Rework removal of unused information</li>
        <li>Report uncaught errors to the user</li>
        <li>Add support for manually triggered OOM (suggested by Mikko Rantalainen)</li>
        <li>Add support for systems w/o swap (suggested by Mikko Rantalainen)</li>
        <li>...</li>
    </ol>


M OOMAnalyser.py => OOMAnalyser.py +38 -12
@@ 467,6 467,13 @@ class OOMResult:
    @type: str
    """

    swap_active = False
    """
    Swap space active or inactive
    
    @type: bool
    """


class OOMAnalyser:
    """Analyse an OOM object and calculate additional values"""


@@ 531,7 538,7 @@ class OOMAnalyser:
            r'^Free swap  = (?P<swap_free_kb>\d+)kB'
            r'(?:\n)'
            r'^Total swap = (?P<swap_total_kb>\d+)kB',
            True,
            False,
        ),
        'Page information': (
            r'^(?P<ram_pages>\d+) pages RAM'


@@ 697,7 704,7 @@ class OOMAnalyser:
                self.oom_result.details.update(match.groupdict())
            elif is_mandatory:
                error('Failed to extract information from OOM text. The regular expression "{}" (pattern "{}") '
                      'does not find anything. This will cause subsequent errors.'.format(k, pattern))
                      'does not find anything. This can lead to errors later on.'.format(k, pattern))
        # __pragma__ ('nojsiter')

        if self.oom_result.details['trigger_proc_order'] == "-1":


@@ 891,6 898,14 @@ class OOMAnalyser:

    def _calc_swap_values(self):
        """Calculate all swap related values"""
        try:
            self.oom_result.swap_active = self.oom_result.details['swap_total_kb'] > 0
        except KeyError:
            self.oom_result.swap_active = False

        if not self.oom_result.swap_active:
            return

        self.oom_result.details['swap_cache_kb'] = self.oom_result.details['swap_cache_pages'] * self.oom_result.details['page_size_kb']
        del self.oom_result.details['swap_cache_pages']



@@ 909,7 924,11 @@ class OOMAnalyser:

        # calculate remaining explanation values
        self.oom_result.details['system_total_ram_kb'] = self.oom_result.details['ram_pages'] * self.oom_result.details['page_size_kb']
        self.oom_result.details['system_total_ramswap_kb'] = self.oom_result.details['system_total_ram_kb'] + self.oom_result.details['swap_total_kb']
        if self.oom_result.swap_active:
            self.oom_result.details['system_total_ramswap_kb'] = self.oom_result.details['system_total_ram_kb'] + \
                                                                 self.oom_result.details['swap_total_kb']
        else:
            self.oom_result.details['system_total_ramswap_kb'] = self.oom_result.details['system_total_ram_kb']
        total_rss_pages = 0
        for pid in self.oom_result.details['_ps'].keys():
            total_rss_pages += self.oom_result.details['_ps'][pid]['rss_pages']


@@ 1534,15 1553,22 @@ Killed process 6576 (mysqld) total-vm:33914892kB, anon-rss:20629004kB, file-rss:
        # generate process table
        self.update_process_table()

        # generate swap usage diagram
        svg_swap = self.svg_generate_bar_chart(
            self.svg_colors_swap,
            ('Swap Used', self.oom_result.details['swap_used_kb']),
            ('Swap Free', self.oom_result.details['swap_free_kb']),
            ('Swap Cached', self.oom_result.details['swap_cache_kb']),
        )
        elem_svg_swap = document.getElementById('svg_swap')
        elem_svg_swap.appendChild(svg_swap)
        # show/hide swap space
        if self.oom_result.swap_active:
            # generate swap usage diagram
            svg_swap = self.svg_generate_bar_chart(
                self.svg_colors_swap,
                ('Swap Used', self.oom_result.details['swap_used_kb']),
                ('Swap Free', self.oom_result.details['swap_free_kb']),
                ('Swap Cached', self.oom_result.details['swap_cache_kb']),
            )
            elem_svg_swap = document.getElementById('svg_swap')
            elem_svg_swap.appendChild(svg_swap)
            show_elements('.js-swap-active--show')
            hide_elements('.js-swap-inactive--show')
        else:
            hide_elements('.js-swap-active--show')
            show_elements('.js-swap-inactive--show')

        # generate RAM usage diagram
        svg_ram = self.svg_generate_bar_chart(

M test.py => test.py +28 -0
@@ 193,6 193,8 @@ class TestInBrowser(TestBase):
        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"')
        self.assertTrue('swap space are in use' in explanation.text,
                        'Missing text "swap space are in use"')

    def test_010_load_page(self):
        """Test if the page is loading"""


@@ 306,6 308,32 @@ Killed process 6576 (java) total-vm:33914892kB, anon-rss:20629004kB, file-rss:0k
        self.assertTrue('OOM killer was manually triggered' in explanation.text,
                        'Missing text "OOM killer was manually triggered"')

    def test_080_swap_deactivated(self):
        """Test w/o swap or with deactivated swap"""
        example = OOMAnalyser.OOMDisplay.example
        example = example.replace('Total swap = 8388604kB', 'Total swap = 0kB')
        self.analyse_oom(example)
        self.assert_on_warn_error()

        explanation = self.driver.find_element_by_id('explanation')
        self.assertFalse('swap space are in use' in explanation.text,
                         'No swap space but text "swap space are in use"')

        self.click_reset()

        example = OOMAnalyser.OOMDisplay.example
        example = re.sub(r'\d+ pages in swap cac.*\n*', '', example, re.MULTILINE)
        example = re.sub(r'Swap cache stats.*\n*', '', example)
        example = re.sub(r'Free swap.*\n*', '', example)
        example = re.sub(r'Total swap.*\n*', '', example)

        self.analyse_oom(example)
        self.assert_on_warn_error()

        explanation = self.driver.find_element_by_id('explanation')
        self.assertFalse('swap space are in use' in explanation.text,
                         'No swap space but text "swap space are in use"')


class TestPython(TestBase):