diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..98462f5
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,67 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [ master ]
+  schedule:
+    - cron: '19 19 * * 2'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'python' ]
+        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+        # Learn more:
+        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v2
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v1
+      with:
+        languages: ${{ matrix.language }}
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file.
+        # Prefix the list here with "+" to use these queries and those in the config file.
+        # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v1
+
+    # ℹī¸ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v1
diff --git a/README.md b/README.md
index 569fe68..cc810a0 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
 # nohang
 
 [![Build Status](https://travis-ci.org/hakavlad/nohang.svg?branch=master)](https://travis-ci.org/hakavlad/nohang)
+![CodeQL](https://github.com/hakavlad/nohang/workflows/CodeQL/badge.svg)
 [![Total alerts](https://img.shields.io/lgtm/alerts/g/hakavlad/nohang.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hakavlad/nohang/alerts/)
 [![Packaging status](https://repology.org/badge/tiny-repos/nohang.svg)](https://repology.org/project/nohang/versions)
 
@@ -40,12 +41,13 @@ Also look at these discussions:
 Use one of the userspace OOM killers:
 - [earlyoom](https://github.com/rfjakob/earlyoom): This is a simple, stable and tiny OOM prevention daemon written in C (the best choice for emedded and old servers). It has a minimum dependencies and can work with oldest kernels. It is enabled by default on Fedora 32 Workstation (and F33 KDE).
 - [oomd](https://github.com/facebookincubator/oomd): This is a userspace OOM killer for linux systems written in C++ and developed by Facebook. This is the best choice for use in large data centers. It needs Linux 4.20+.
+- [systemd-oomd](https://man7.org/linux/man-pages/man8/systemd-oomd.service.8.html): Provided by systemd as `systemd-oomd.service` that uses cgroups-v2 and pressure stall information (PSI) to monitor and take action on processes before an OOM occurs in kernel space. It's used by default on [desktop versions of Fedora 34](https://fedoraproject.org/wiki/Changes/EnableSystemdOomd).
 - [low-memory-monitor](https://gitlab.freedesktop.org/hadess/low-memory-monitor/): There's a [project announcement](http://www.hadess.net/2019/08/low-memory-monitor-new-project.html).
 - [psi-monitor](https://github.com/endlessm/eos-boot-helper/tree/master/psi-monitor): It's used by default on [Endless OS](https://endlessos.com/).
 - `nohang`: nohang is earlyoom on steroids and has many useful features, see below. Maybe this is a good choice for modern desktops and servers if you need fine-tuning. It's used by default on [Garuda Linux](https://garudalinux.org/).
 
 Use these tools to improve responsiveness during heavy swapping:
-- [le9-patch](https://github.com/hakavlad/le9-patch): Protect active file pages to prevent thrashing and improve responsiveness under low-memory conditions. It's kernel-side solution that can fix OOM killer behavior.
+- [le9-patch](https://github.com/hakavlad/le9-patch): [PATCH] mm: Protect clean file pages under memory pressure to prevent thrashing, avoid high latency and prevent livelock in near-OOM conditions. It's kernel-side solution that can fix the OOM killer behavior.
 - [prelockd](https://github.com/hakavlad/prelockd): Lock executables and shared libraries in memory to improve system responsiveness under low-memory conditions.
 - [memavaild](https://github.com/hakavlad/memavaild): Keep amount of available memory by evicting memory of selected cgroups into swap space.
 - [uresourced](https://gitlab.freedesktop.org/benzea/uresourced): This daemon will give resource allocations to active graphical users. It's [enabled by default](https://fedoraproject.org/wiki/Changes/Reserve_resources_for_active_user_WS) on Fedora 33 Workstation.
@@ -115,7 +117,7 @@ To show GUI notifications (optional):
 
 ## How to install
 
-#### To install on Fedora:
+#### To install on [Fedora](https://src.fedoraproject.org/rpms/nohang/):
 ```bash
 $ sudo dnf install nohang-desktop
 $ sudo systemctl enable --now nohang-desktop.service
diff --git a/docs/psi2log.manpage.md b/docs/psi2log.manpage.md
index e4f222f..60120ef 100644
--- a/docs/psi2log.manpage.md
+++ b/docs/psi2log.manpage.md
@@ -24,7 +24,7 @@ interval in sec
 path to log file
 
 #### -m MODE, --mode MODE
-mode (1 or 2)
+mode (0, 1 or 2)
 
 #### -s SUPPRESS_OUTPUT, --suppress-output SUPPRESS_OUTPUT
 suppress output
diff --git a/man/psi2log.1 b/man/psi2log.1
index e340102..0516b8a 100644
--- a/man/psi2log.1
+++ b/man/psi2log.1
@@ -28,7 +28,7 @@ interval in sec
 path to log file
 .SS \-m MODE, \-\-mode MODE
 .PP
-mode (1 or 2)
+mode (0, 1 or 2)
 .SS \-s SUPPRESS_OUTPUT, \-\-suppress\-output SUPPRESS_OUTPUT
 .PP
 suppress output
diff --git a/src/psi2log b/src/psi2log
index 57b162d..0c0c3c0 100755
--- a/src/psi2log
+++ b/src/psi2log
@@ -1,11 +1,11 @@
 #!/usr/bin/env python3
 """psi2log - PSI metrics monitor and logger"""
 
-from time import sleep, monotonic
-from ctypes import CDLL
-from sys import stdout, exit
 from argparse import ArgumentParser
-from signal import signal, SIGTERM, SIGINT, SIGQUIT, SIGHUP
+from ctypes import CDLL
+from signal import SIGHUP, SIGINT, SIGQUIT, SIGTERM, signal
+from sys import exit, stdout
+from time import monotonic, sleep
 
 
 def read_path(path):
@@ -56,30 +56,21 @@ def signal_handler(signum, frame):
     for i in sig_list:
         signal(i, signal_handler_inner)
 
-    if len(fd) > 0:
-        for f in fd:
-            fd[f].close()
-
     if signum == SIGINT:
         print('')
 
     lpd = len(peaks_dict)
 
-    if lpd == 15:  # mode 1
-
+    if lpd == 15:
         log('=================================')
         log('Peak values:  avg10  avg60 avg300')
-
         log('-----------  ------ ------ ------')
-
         log('some cpu     {:>6} {:>6} {:>6}'.format(
             form1(peaks_dict['c_some_avg10']),
             form1(peaks_dict['c_some_avg60']),
             form1(peaks_dict['c_some_avg300']),
         ))
-
         log('-----------  ------ ------ ------')
-
         log('some io      {:>6} {:>6} {:>6}'.format(
             form1(peaks_dict['i_some_avg10']),
             form1(peaks_dict['i_some_avg60']),
@@ -106,28 +97,74 @@ def signal_handler(signum, frame):
             form1(peaks_dict['m_full_avg300']),
         ))
 
-    if lpd == 5:  # mode 2
-
+    if lpd == 5:
         log('----- | ----- ----- | ----- ----- | --------')
-
         log('{:>5} | {:>5} {:>5} | {:>5} {:>5} | peaks'.format(
-
             form2(peaks_dict['avg_cs']),
-
             form2(peaks_dict['avg_is']),
             form2(peaks_dict['avg_if']),
-
             form2(peaks_dict['avg_ms']),
             form2(peaks_dict['avg_mf'])
-
         ))
 
+    if target == 'SYSTEM_WIDE':
+        log_stall_times()
+
     if separate_log:
         logging.info('')
 
     exit()
 
 
+def log_stall_times():
+    """
+    """
+    total_cs_1 = psi_file_cpu_to_total(cpu_file)
+    total_is_1, total_if_1 = psi_file_mem_to_total(io_file)
+    total_ms_1, total_mf_1 = psi_file_mem_to_total(memory_file)
+    t = monotonic() - t_0
+
+    M = 1000000
+
+    dcs = (total_cs_1 - total_cs_0) / M
+    dis = (total_is_1 - total_is_0) / M
+    dif = (total_if_1 - total_if_0) / M
+    dms = (total_ms_1 - total_ms_0) / M
+    dmf = (total_mf_1 - total_mf_0) / M
+
+    if mode == '0' or mode == '1':
+        log('=================================')
+    else:
+        log('--')
+
+    log('Stall times for the last {}s:'.format(round(t, 1)))
+    log('-----------')
+    log('some cpu     {}s, avg {}%'.format(
+        round(dcs, 1),
+        round(dcs / t * 100, 1)
+    ))
+    log('-----------')
+    log('some io      {}s, avg {}%'.format(
+        round(dis, 1),
+        round(dis / t * 100, 1)
+    ))
+    log('full io      {}s, avg {}%'.format(
+        round(dif, 1),
+        round(dif / t * 100, 1)
+    ))
+    log('-----------')
+
+    log('some memory  {}s, avg {}%'.format(
+        round(dms, 1),
+        round(dms / t * 100, 1)
+    ))
+
+    log('full memory  {}s, avg {}%'.format(
+        round(dmf, 1),
+        round(dmf / t * 100, 1)
+    ))
+
+
 def cgroup2_root():
     """
     """
@@ -144,17 +181,19 @@ def mlockall():
     MCL_FUTURE = 2
     MCL_ONFAULT = 4
 
-    libc = CDLL('libc.so.6', use_errno=True)
+    libc = CDLL(None, use_errno=True)
     result = libc.mlockall(MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT)
 
     if result != 0:
         result = libc.mlockall(MCL_CURRENT | MCL_FUTURE)
         if result != 0:
-            log('WARNING: cannot lock all memory: [Errno {}]'.format(result))
+            log('WARNING: cannot lock process memory: [Errno {}]'.format(
+                result))
         else:
-            log('All memory locked with MCL_CURRENT | MCL_FUTURE')
+            log('Prosess memory locked with MCL_CURRENT | MCL_FUTURE')
     else:
-        log('All memory locked with MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT')
+        log('Process memory locked with '
+            'MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT')
 
 
 def psi_file_mem_to_metrics0(psi_path):
@@ -182,7 +221,6 @@ def psi_file_mem_to_metrics(psi_path):
         return None
 
     try:
-
         psi_list = foo.split('\n')
 
         some_list, full_list = psi_list[0].split(' '), psi_list[1].split(' ')
@@ -209,7 +247,6 @@ def psi_file_cpu_to_metrics(psi_path):
         return None
 
     try:
-
         psi_list = foo.split('\n')
 
         some_list = psi_list[0].split(' ')
@@ -232,7 +269,6 @@ def psi_file_mem_to_total(psi_path):
         return None
 
     try:
-
         psi_list = foo.split('\n')
 
         some_list, full_list = psi_list[0].split(' '), psi_list[1].split(' ')
@@ -255,7 +291,6 @@ def psi_file_cpu_to_total(psi_path):
         return None
 
     try:
-
         psi_list = foo.split('\n')
 
         some_list = psi_list[0].split(' ')
@@ -268,6 +303,24 @@ def psi_file_cpu_to_total(psi_path):
         return None
 
 
+def print_head_0():
+    """
+    """
+    log('==================================================================='
+        '============')
+    log('     cpu      ||               io              ||            memory')
+    log('============= || ============================= || ================='
+        '============')
+    log('     some     ||      some     |      full     ||      some     |  '
+        '     full')
+    log('------------- || ------------- | ------------- || ------------- | -'
+        '------------')
+    log(' avg10  avg60 ||  avg10  avg60 |  avg10  avg60 ||  avg10  avg60 |  '
+        'avg10  avg60')
+    log('------ ------ || ------ ------ | ------ ------ || ------ ------ | -'
+        '----- ------')
+
+
 def print_head_1():
     """
     """
@@ -290,7 +343,7 @@ def print_head_1():
 def print_head_2():
     """
     """
-    log('======|=============|=============|')
+    log('----- - ----------- - ----------- -')
     log(' cpu  |      io     |    memory   |')
     log('----- | ----------- | ----------- |')
     log(' some |  some  full |  some  full | interval')
@@ -314,9 +367,6 @@ def log_head(*msg):
         logging.info(*msg)
 
 
-##############################################################################
-
-
 parser = ArgumentParser()
 
 parser.add_argument(
@@ -349,8 +399,8 @@ parser.add_argument(
 parser.add_argument(
     '-m',
     '--mode',
-    help="""mode (1 or 2)""",
-    default='1',
+    help="""mode (0, 1 or 2)""",
+    default='0',
     type=str
 )
 
@@ -375,21 +425,12 @@ if target != 'SYSTEM_WIDE':
     target = '/' + target.strip('/')
 
 
-##############################################################################
-
-
 if log_file is None:
     separate_log = False
 else:
     separate_log = True
     import logging
 
-
-sig_list = [SIGTERM, SIGINT, SIGQUIT, SIGHUP]
-
-for i in sig_list:
-    signal(i, signal_handler)
-
 if separate_log:
     try:
         logging.basicConfig(
@@ -423,8 +464,8 @@ if interval < 1:
     exit(1)
 
 
-if not (mode == '1' or mode == '2'):
-    log_head('ERROR: invalid mode. Valid values are 1 and 2. Exit.')
+if not (mode == '0' or mode == '1' or mode == '2'):
+    log_head('ERROR: invalid mode. Valid values are 0, 1 and 2. Exit.')
     exit(1)
 
 
@@ -470,214 +511,348 @@ else:
 
 
 abnormal_interval = 1.01 * interval
+abnormal_inaccuracy = 0.05
+
+
+if target == 'SYSTEM_WIDE':
+    total_cs_0 = psi_file_cpu_to_total(cpu_file)
+    total_is_0, total_if_0 = psi_file_mem_to_total(io_file)
+    total_ms_0, total_mf_0 = psi_file_mem_to_total(memory_file)
+    t_0 = monotonic()
 
 
 peaks_dict = dict()
 
 
+sig_list = [SIGTERM, SIGINT, SIGQUIT, SIGHUP]
+
+for i in sig_list:
+    signal(i, signal_handler)
+
+
 mlockall()
 
 
-if mode == '2':
+if mode == '0':
 
-    print_head_2()
+    print_head_0()
 
-    try:
+    while True:
 
-        total_cs0 = psi_file_cpu_to_total(cpu_file)
-        total_is0, total_if0 = psi_file_mem_to_total(io_file)
-        total_ms0, total_mf0 = psi_file_mem_to_total(memory_file)
-        monotonic0 = monotonic()
-        stdout.flush()
-        sleep(interval)
+        try:
+
+            (c_some_avg10, c_some_avg60, c_some_avg300
+             ) = psi_file_cpu_to_metrics(cpu_file)
+
+            (i_some_avg10, i_some_avg60, i_some_avg300,
+             i_full_avg10, i_full_avg60, i_full_avg300
+             ) = psi_file_mem_to_metrics(io_file)
+
+            (m_some_avg10, m_some_avg60, m_some_avg300,
+             m_full_avg10, m_full_avg60, m_full_avg300
+             ) = psi_file_mem_to_metrics(memory_file)
+
+        except TypeError:
+            stdout.flush()
+            sleep(interval)
+            continue
+
+        log('{:>6} {:>6} || {:>6} {:>6} | {:>6} {:>6} || {:>6} {:>6} | {:>6} '
+            '{:>6}'.format(
+
+                c_some_avg10, c_some_avg60,
+
+                i_some_avg10, i_some_avg60,
+                i_full_avg10, i_full_avg60,
+
+                m_some_avg10, m_some_avg60,
+                m_full_avg10, m_full_avg60
+
+            ))
+
+        c_some_avg10 = float(c_some_avg10)
+        if ('c_some_avg10' not in peaks_dict or
+                peaks_dict['c_some_avg10'] < c_some_avg10):
+            peaks_dict['c_some_avg10'] = c_some_avg10
+
+        c_some_avg60 = float(c_some_avg60)
+        if ('c_some_avg60' not in peaks_dict or
+                peaks_dict['c_some_avg60'] < c_some_avg60):
+            peaks_dict['c_some_avg60'] = c_some_avg60
+
+        c_some_avg300 = float(c_some_avg300)
+        if ('c_some_avg300' not in peaks_dict or
+                peaks_dict['c_some_avg300'] < c_some_avg300):
+            peaks_dict['c_some_avg300'] = c_some_avg300
+
+        #######################################################################
+
+        i_some_avg10 = float(i_some_avg10)
+        if ('i_some_avg10' not in peaks_dict or
+                peaks_dict['i_some_avg10'] < i_some_avg10):
+            peaks_dict['i_some_avg10'] = i_some_avg10
+
+        i_some_avg60 = float(i_some_avg60)
+        if ('i_some_avg60' not in peaks_dict or
+                peaks_dict['i_some_avg60'] < i_some_avg60):
+            peaks_dict['i_some_avg60'] = i_some_avg60
+
+        i_some_avg300 = float(i_some_avg300)
+        if ('i_some_avg300' not in peaks_dict or
+                peaks_dict['i_some_avg300'] < i_some_avg300):
+            peaks_dict['i_some_avg300'] = i_some_avg300
+
+        i_full_avg10 = float(i_full_avg10)
+        if ('i_full_avg10' not in peaks_dict or
+                peaks_dict['i_full_avg10'] < i_full_avg10):
+            peaks_dict['i_full_avg10'] = i_full_avg10
+
+        i_full_avg60 = float(i_full_avg60)
+        if ('i_full_avg60' not in peaks_dict or
+                peaks_dict['i_full_avg60'] < i_full_avg60):
+            peaks_dict['i_full_avg60'] = i_full_avg60
+
+        i_full_avg300 = float(i_full_avg300)
+        if ('i_full_avg300' not in peaks_dict or
+                peaks_dict['i_full_avg300'] < i_full_avg300):
+            peaks_dict['i_full_avg300'] = i_full_avg300
+
+        #######################################################################
+
+        m_some_avg10 = float(m_some_avg10)
+        if ('m_some_avg10' not in peaks_dict or
+                peaks_dict['m_some_avg10'] < m_some_avg10):
+            peaks_dict['m_some_avg10'] = m_some_avg10
+
+        m_some_avg60 = float(m_some_avg60)
+        if ('m_some_avg60' not in peaks_dict or
+                peaks_dict['m_some_avg60'] < m_some_avg60):
+            peaks_dict['m_some_avg60'] = m_some_avg60
+
+        m_some_avg300 = float(m_some_avg300)
+        if ('m_some_avg300' not in peaks_dict or
+                peaks_dict['m_some_avg300'] < m_some_avg300):
+            peaks_dict['m_some_avg300'] = m_some_avg300
+
+        m_full_avg10 = float(m_full_avg10)
+        if ('m_full_avg10' not in peaks_dict or
+                peaks_dict['m_full_avg10'] < m_full_avg10):
+            peaks_dict['m_full_avg10'] = m_full_avg10
+
+        m_full_avg60 = float(m_full_avg60)
+        if ('m_full_avg60' not in peaks_dict or
+                peaks_dict['m_full_avg60'] < m_full_avg60):
+            peaks_dict['m_full_avg60'] = m_full_avg60
+
+        m_full_avg300 = float(m_full_avg300)
+        if ('m_full_avg300' not in peaks_dict or
+                peaks_dict['m_full_avg300'] < m_full_avg300):
+            peaks_dict['m_full_avg300'] = m_full_avg300
 
-    except TypeError:
         stdout.flush()
         sleep(interval)
 
+
+if mode == '1':
+
+    print_head_1()
+
     while True:
 
         try:
 
-            total_cs1 = psi_file_cpu_to_total(cpu_file)
-            total_is1, total_if1 = psi_file_mem_to_total(io_file)
-            total_ms1, total_mf1 = psi_file_mem_to_total(memory_file)
-            monotonic1 = monotonic()
-            dm = monotonic1 - monotonic0
+            (c_some_avg10, c_some_avg60, c_some_avg300
+             ) = psi_file_cpu_to_metrics(cpu_file)
 
-            if dm > abnormal_interval and dm - interval > 0.05:
-                log('WARNING: abnormal interval ({} sec), metrics may be prov'
-                    'ided incorrect'.format(round(dm, 3)))
+            (i_some_avg10, i_some_avg60, i_some_avg300,
+             i_full_avg10, i_full_avg60, i_full_avg300
+             ) = psi_file_mem_to_metrics(io_file)
 
-            monotonic0 = monotonic1
+            (m_some_avg10, m_some_avg60, m_some_avg300,
+             m_full_avg10, m_full_avg60, m_full_avg300
+             ) = psi_file_mem_to_metrics(memory_file)
 
         except TypeError:
             stdout.flush()
             sleep(interval)
             continue
 
-        dtotal_cs = total_cs1 - total_cs0
-        avg_cs = dtotal_cs / dm / 10000
-        if 'avg_cs' not in peaks_dict or peaks_dict['avg_cs'] < avg_cs:
-            peaks_dict['avg_cs'] = avg_cs
-        total_cs0 = total_cs1
+        log('{:>6} {:>6} {:>6} || {:>6} {:>6} {:>6} | {:>6} {:>6} {:>6} || '
+            '{:>6} {:>6} {:>6} | {:>6} {:>6} {:>6}'.format(
 
-        dtotal_is = total_is1 - total_is0
-        avg_is = dtotal_is / dm / 10000
-        if 'avg_is' not in peaks_dict or peaks_dict['avg_is'] < avg_is:
-            peaks_dict['avg_is'] = avg_is
-        total_is0 = total_is1
+                c_some_avg10, c_some_avg60, c_some_avg300,
 
-        dtotal_if = total_if1 - total_if0
-        avg_if = dtotal_if / dm / 10000
-        if 'avg_if' not in peaks_dict or peaks_dict['avg_if'] < avg_if:
-            peaks_dict['avg_if'] = avg_if
-        total_if0 = total_if1
+                i_some_avg10, i_some_avg60, i_some_avg300,
+                i_full_avg10, i_full_avg60, i_full_avg300,
 
-        dtotal_ms = total_ms1 - total_ms0
-        avg_ms = dtotal_ms / dm / 10000
-        if 'avg_ms' not in peaks_dict or peaks_dict['avg_ms'] < avg_ms:
-            peaks_dict['avg_ms'] = avg_ms
-        total_ms0 = total_ms1
+                m_some_avg10, m_some_avg60, m_some_avg300,
+                m_full_avg10, m_full_avg60, m_full_avg300
 
-        dtotal_mf = total_mf1 - total_mf0
-        avg_mf = dtotal_mf / dm / 10000
-        if 'avg_mf' not in peaks_dict or peaks_dict['avg_mf'] < avg_mf:
-            peaks_dict['avg_mf'] = avg_mf
-        total_mf0 = total_mf1
+            ))
 
-        log('{:>5} | {:>5} {:>5} | {:>5} {:>5} | {}'.format(
+        c_some_avg10 = float(c_some_avg10)
+        if ('c_some_avg10' not in peaks_dict or
+                peaks_dict['c_some_avg10'] < c_some_avg10):
+            peaks_dict['c_some_avg10'] = c_some_avg10
 
-            round(avg_cs, 1),
+        c_some_avg60 = float(c_some_avg60)
+        if ('c_some_avg60' not in peaks_dict or
+                peaks_dict['c_some_avg60'] < c_some_avg60):
+            peaks_dict['c_some_avg60'] = c_some_avg60
 
-            round(avg_is, 1),
-            round(avg_if, 1),
+        c_some_avg300 = float(c_some_avg300)
+        if ('c_some_avg300' not in peaks_dict or
+                peaks_dict['c_some_avg300'] < c_some_avg300):
+            peaks_dict['c_some_avg300'] = c_some_avg300
 
-            round(avg_ms, 1),
-            round(avg_mf, 1),
+        #######################################################################
 
-            round(dm, 3)
+        i_some_avg10 = float(i_some_avg10)
+        if ('i_some_avg10' not in peaks_dict or
+                peaks_dict['i_some_avg10'] < i_some_avg10):
+            peaks_dict['i_some_avg10'] = i_some_avg10
 
-        ))
+        i_some_avg60 = float(i_some_avg60)
+        if ('i_some_avg60' not in peaks_dict or
+                peaks_dict['i_some_avg60'] < i_some_avg60):
+            peaks_dict['i_some_avg60'] = i_some_avg60
+
+        i_some_avg300 = float(i_some_avg300)
+        if ('i_some_avg300' not in peaks_dict or
+                peaks_dict['i_some_avg300'] < i_some_avg300):
+            peaks_dict['i_some_avg300'] = i_some_avg300
+
+        i_full_avg10 = float(i_full_avg10)
+        if ('i_full_avg10' not in peaks_dict or
+                peaks_dict['i_full_avg10'] < i_full_avg10):
+            peaks_dict['i_full_avg10'] = i_full_avg10
+
+        i_full_avg60 = float(i_full_avg60)
+        if ('i_full_avg60' not in peaks_dict or
+                peaks_dict['i_full_avg60'] < i_full_avg60):
+            peaks_dict['i_full_avg60'] = i_full_avg60
+
+        i_full_avg300 = float(i_full_avg300)
+        if ('i_full_avg300' not in peaks_dict or
+                peaks_dict['i_full_avg300'] < i_full_avg300):
+            peaks_dict['i_full_avg300'] = i_full_avg300
+
+        #######################################################################
+
+        m_some_avg10 = float(m_some_avg10)
+        if ('m_some_avg10' not in peaks_dict or
+                peaks_dict['m_some_avg10'] < m_some_avg10):
+            peaks_dict['m_some_avg10'] = m_some_avg10
+
+        m_some_avg60 = float(m_some_avg60)
+        if ('m_some_avg60' not in peaks_dict or
+                peaks_dict['m_some_avg60'] < m_some_avg60):
+            peaks_dict['m_some_avg60'] = m_some_avg60
+
+        m_some_avg300 = float(m_some_avg300)
+        if ('m_some_avg300' not in peaks_dict or
+                peaks_dict['m_some_avg300'] < m_some_avg300):
+            peaks_dict['m_some_avg300'] = m_some_avg300
+
+        m_full_avg10 = float(m_full_avg10)
+        if ('m_full_avg10' not in peaks_dict or
+                peaks_dict['m_full_avg10'] < m_full_avg10):
+            peaks_dict['m_full_avg10'] = m_full_avg10
+
+        m_full_avg60 = float(m_full_avg60)
+        if ('m_full_avg60' not in peaks_dict or
+                peaks_dict['m_full_avg60'] < m_full_avg60):
+            peaks_dict['m_full_avg60'] = m_full_avg60
+
+        m_full_avg300 = float(m_full_avg300)
+        if ('m_full_avg300' not in peaks_dict or
+                peaks_dict['m_full_avg300'] < m_full_avg300):
+            peaks_dict['m_full_avg300'] = m_full_avg300
 
         stdout.flush()
         sleep(interval)
 
 
-print_head_1()
+print_head_2()
+
+try:
+
+    total_cs0 = psi_file_cpu_to_total(cpu_file)
+    total_is0, total_if0 = psi_file_mem_to_total(io_file)
+    total_ms0, total_mf0 = psi_file_mem_to_total(memory_file)
+    monotonic0 = monotonic()
+    stdout.flush()
+    sleep(interval)
+
+except TypeError:
+    stdout.flush()
+    sleep(interval)
 
+TT = 10000
 
 while True:
 
     try:
 
-        (c_some_avg10, c_some_avg60, c_some_avg300
-         ) = psi_file_cpu_to_metrics(cpu_file)
+        total_cs1 = psi_file_cpu_to_total(cpu_file)
+        total_is1, total_if1 = psi_file_mem_to_total(io_file)
+        total_ms1, total_mf1 = psi_file_mem_to_total(memory_file)
+        monotonic1 = monotonic()
+        dm = monotonic1 - monotonic0
 
-        (i_some_avg10, i_some_avg60, i_some_avg300,
-         i_full_avg10, i_full_avg60, i_full_avg300
-         ) = psi_file_mem_to_metrics(io_file)
+        if dm > abnormal_interval and dm - interval > abnormal_inaccuracy:
+            log('WARNING: abnormal interval ({} sec), metrics may be prov'
+                'ided incorrect'.format(round(dm, 3)))
 
-        (m_some_avg10, m_some_avg60, m_some_avg300,
-         m_full_avg10, m_full_avg60, m_full_avg300
-         ) = psi_file_mem_to_metrics(memory_file)
+        monotonic0 = monotonic1
 
     except TypeError:
         stdout.flush()
         sleep(interval)
         continue
 
-    log('{:>6} {:>6} {:>6} || {:>6} {:>6} {:>6} | {:>6} {:>6} {:>6} || {:>6}'
-        ' {:>6} {:>6} | {:>6} {:>6} {:>6}'.format(
+    dtotal_cs = total_cs1 - total_cs0
+    avg_cs = dtotal_cs / dm / TT
+    if 'avg_cs' not in peaks_dict or peaks_dict['avg_cs'] < avg_cs:
+        peaks_dict['avg_cs'] = avg_cs
+    total_cs0 = total_cs1
 
-            c_some_avg10, c_some_avg60, c_some_avg300,
+    dtotal_is = total_is1 - total_is0
+    avg_is = dtotal_is / dm / TT
+    if 'avg_is' not in peaks_dict or peaks_dict['avg_is'] < avg_is:
+        peaks_dict['avg_is'] = avg_is
+    total_is0 = total_is1
 
-            i_some_avg10, i_some_avg60, i_some_avg300,
-            i_full_avg10, i_full_avg60, i_full_avg300,
+    dtotal_if = total_if1 - total_if0
+    avg_if = dtotal_if / dm / TT
+    if 'avg_if' not in peaks_dict or peaks_dict['avg_if'] < avg_if:
+        peaks_dict['avg_if'] = avg_if
+    total_if0 = total_if1
 
-            m_some_avg10, m_some_avg60, m_some_avg300,
-            m_full_avg10, m_full_avg60, m_full_avg300
+    dtotal_ms = total_ms1 - total_ms0
+    avg_ms = dtotal_ms / dm / TT
+    if 'avg_ms' not in peaks_dict or peaks_dict['avg_ms'] < avg_ms:
+        peaks_dict['avg_ms'] = avg_ms
+    total_ms0 = total_ms1
 
-        ))
+    dtotal_mf = total_mf1 - total_mf0
+    avg_mf = dtotal_mf / dm / TT
+    if 'avg_mf' not in peaks_dict or peaks_dict['avg_mf'] < avg_mf:
+        peaks_dict['avg_mf'] = avg_mf
+    total_mf0 = total_mf1
+
+    log('{:>5} | {:>5} {:>5} | {:>5} {:>5} | {}'.format(
+
+        round(avg_cs, 1),
+
+        round(avg_is, 1),
+        round(avg_if, 1),
+
+        round(avg_ms, 1),
+        round(avg_mf, 1),
 
-    c_some_avg10 = float(c_some_avg10)
-    if ('c_some_avg10' not in peaks_dict or
-            peaks_dict['c_some_avg10'] < c_some_avg10):
-        peaks_dict['c_some_avg10'] = c_some_avg10
-
-    c_some_avg60 = float(c_some_avg60)
-    if ('c_some_avg60' not in peaks_dict or
-            peaks_dict['c_some_avg60'] < c_some_avg60):
-        peaks_dict['c_some_avg60'] = c_some_avg60
-
-    c_some_avg300 = float(c_some_avg300)
-    if ('c_some_avg300' not in peaks_dict or
-            peaks_dict['c_some_avg300'] < c_some_avg300):
-        peaks_dict['c_some_avg300'] = c_some_avg300
-
-    #######################################################################
-
-    i_some_avg10 = float(i_some_avg10)
-    if ('i_some_avg10' not in peaks_dict or
-            peaks_dict['i_some_avg10'] < i_some_avg10):
-        peaks_dict['i_some_avg10'] = i_some_avg10
-
-    i_some_avg60 = float(i_some_avg60)
-    if ('i_some_avg60' not in peaks_dict or
-            peaks_dict['i_some_avg60'] < i_some_avg60):
-        peaks_dict['i_some_avg60'] = i_some_avg60
-
-    i_some_avg300 = float(i_some_avg300)
-    if ('i_some_avg300' not in peaks_dict or
-            peaks_dict['i_some_avg300'] < i_some_avg300):
-        peaks_dict['i_some_avg300'] = i_some_avg300
-
-    i_full_avg10 = float(i_full_avg10)
-    if ('i_full_avg10' not in peaks_dict or
-            peaks_dict['i_full_avg10'] < i_full_avg10):
-        peaks_dict['i_full_avg10'] = i_full_avg10
-
-    i_full_avg60 = float(i_full_avg60)
-    if ('i_full_avg60' not in peaks_dict or
-            peaks_dict['i_full_avg60'] < i_full_avg60):
-        peaks_dict['i_full_avg60'] = i_full_avg60
-
-    i_full_avg300 = float(i_full_avg300)
-    if ('i_full_avg300' not in peaks_dict or
-            peaks_dict['i_full_avg300'] < i_full_avg300):
-        peaks_dict['i_full_avg300'] = i_full_avg300
-
-    #######################################################################
-
-    m_some_avg10 = float(m_some_avg10)
-    if ('m_some_avg10' not in peaks_dict or
-            peaks_dict['m_some_avg10'] < m_some_avg10):
-        peaks_dict['m_some_avg10'] = m_some_avg10
-
-    m_some_avg60 = float(m_some_avg60)
-    if ('m_some_avg60' not in peaks_dict or
-            peaks_dict['m_some_avg60'] < m_some_avg60):
-        peaks_dict['m_some_avg60'] = m_some_avg60
-
-    m_some_avg300 = float(m_some_avg300)
-    if ('m_some_avg300' not in peaks_dict or
-            peaks_dict['m_some_avg300'] < m_some_avg300):
-        peaks_dict['m_some_avg300'] = m_some_avg300
-
-    m_full_avg10 = float(m_full_avg10)
-    if ('m_full_avg10' not in peaks_dict or
-            peaks_dict['m_full_avg10'] < m_full_avg10):
-        peaks_dict['m_full_avg10'] = m_full_avg10
-
-    m_full_avg60 = float(m_full_avg60)
-    if ('m_full_avg60' not in peaks_dict or
-            peaks_dict['m_full_avg60'] < m_full_avg60):
-        peaks_dict['m_full_avg60'] = m_full_avg60
-
-    m_full_avg300 = float(m_full_avg300)
-    if ('m_full_avg300' not in peaks_dict or
-            peaks_dict['m_full_avg300'] < m_full_avg300):
-        peaks_dict['m_full_avg300'] = m_full_avg300
+        round(dm, 2)
+    ))
 
     stdout.flush()
     sleep(interval)