diff --git a/Makefile b/Makefile index 05a2b66..84e5721 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ install: install -d $(DESTDIR)/$(PREFIX)/usr/sbin install -m0755 ./nohang_notify_low_mem $(DESTDIR)/$(PREFIX)/usr/sbin/nohang_notify_low_mem + install -d $(DESTDIR)/$(PREFIX)/usr/bin + install -m0755 ./oom-top $(DESTDIR)/$(PREFIX)/usr/bin/oom-top + install -d $(DESTDIR)/$(PREFIX)/etc/nohang install -m0644 ./nohang.conf $(DESTDIR)/$(PREFIX)/etc/nohang install -m0644 ./nohang.conf.backup $(DESTDIR)/$(PREFIX)/etc/nohang @@ -21,12 +24,12 @@ install: install -d $(DESTDIR)/$(PREFIX)/lib/systemd/system install -m0644 ./nohang.service $(DESTDIR)/$(PREFIX)/lib/systemd/system/nohang.service - uninstall: # 'make uninstall' must not fail with error if systemctl is unavailable or returns error systemctl disable nohang.service || true rm -fv $(PREFIX)/usr/sbin/nohang rm -fv $(PREFIX)/usr/sbin/nohang_notify_low_mem + rm -fv $(PREFIX)/usr/bin/oom-top rm -fv $(PREFIX)/usr/share/man/man1/nohang.1.gz rm -fv $(PREFIX)/lib/systemd/system/nohang.service rm -fvr $(PREFIX)/etc/nohang/ diff --git a/README.md b/README.md index f3a123e..97b1fb5 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,33 @@ The program can be configured by editing the [config file](https://github.com/ha Just read the description of the parameters and edit the values. Please restart nohang to apply changes. Default path to the config after installing is `/etc/nohang/nohang.conf`. + +## Oom-top + +oom-top is an additional diagnostic utility from the nohang package. It sorts the processes in descending order of their oom_score. + +Usage: + +``` +$ oom-top +``` + +It will be installed together with nohang. Output like this: + +``` +oom_score oom_adj oom_score_adj Pid Name RSS Swap +--------- ------- ------------- ----- --------------- --------- --------- + 59 0 0 4133 firefox-esr 671 M 24 M + 18 0 0 4543 Web Content 213 M 8 M + 5 0 0 815 Xorg 46 M 21 M + 5 0 0 4088 kate 51 M 9 M + 4 0 0 4716 kate 48 M 0 M + 3 0 0 835 tor 18 M 18 M + 3 0 0 1412 dolphin 35 M 10 M + +``` + + ## Logging If nohang is installed on a system that uses systemd, you can use the following command to view the log: diff --git a/oom-top b/oom-top new file mode 100755 index 0000000..0deec2b --- /dev/null +++ b/oom-top @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +# top oom_score + +from time import sleep +from operator import itemgetter +from os import listdir + +period = 1 +num_lines = 20 +oom_score_min_value = 0 + +# перевод кило в мегабайты и выравнивание по правому краю +def human(num): + return str(round(num / 1024.0)).rjust(7, ' ') + +with open('/proc/self/status') as file: + status_list = file.readlines() + +# список имен из /proc/*/status для дальнейшего поиска позиций VmRSS and VmSwap +status_names = [] +for s in status_list: + status_names.append(s.split(':')[0]) + +vm_rss_index = status_names.index('VmRSS') +vm_swap_index = status_names.index('VmSwap') + + +while True: + + oom_list = [] + + # цикл для наполнения oom_list + for i in listdir('/proc'): + + # пропускаем элементы, состоящие не из цифр + if i.isdigit() is not True: + continue + + try: + + with open('/proc/' + i + '/oom_score') as file: + oom_score = int(file.readlines()[0][:-1]) + + with open('/proc/' + i + '/oom_adj') as file: + oom_adj = int(file.readlines()[0][:-1]) + + with open('/proc/' + i + '/oom_score_adj') as file: + oom_score_adj = int(file.readlines()[0][:-1]) + + except FileNotFoundError: + pass + except ProcessLookupError: + pass + + oom_list.append((i, oom_score, oom_adj, oom_score_adj)) + + # получаем сортированный список oom_score + oom_list_sorted = sorted(oom_list, key=itemgetter(1), reverse=True) + + # если общее число процессов меньше num_lines - приравниваем последний к числу процессов + if len(oom_list_sorted) < num_lines: + num_lines = len(oom_list_sorted) - 1 + + + print('\033coom_score oom_adj oom_score_adj Pid Name RSS Swap') + print('--------- ------- ------------- ----- --------------- --------- ---------') + + # итерируемся по сортированному списку oom_score, печатая name, pid etc + for i in oom_list_sorted[:num_lines]: + + pid = i[0] + oom_score = i[1] + oom_adj = i[2] + oom_score_adj = i[3] + + try: + + # читать часть файла не дальше VmSwap + with open('/proc/' + pid + '/status') as file: + status_list = file.readlines() + + vm_rss = int(status_list[vm_rss_index].split(':')[1].split(' ')[-2]) + vm_swap = int(status_list[vm_swap_index].split(':')[1].split(' ')[-2]) + name = status_list[0][:-1].split('\t')[1] + + # потоки ядра + except IndexError: + vm_rss = 0 + vm_swap = 0 + name = status_list[0][:-1].split('\t')[1] + + except FileNotFoundError: + vm_rss = 0 + vm_swap = 0 + name = '' + + except ProcessLookupError: + vm_rss = 0 + vm_swap = 0 + name = '' + + if oom_score >= oom_score_min_value: + + print( + '{} {} {} {} {} {} M {} M'.format( + str(oom_score).rjust(9), + str(oom_adj).rjust(7), + str(oom_score_adj).rjust(13), + str(pid).rjust(5), + name.ljust(15), + human(vm_rss), + human(vm_swap), + ) + ) + + sleep(period) +