diff --git a/README.md b/README.md index 0a5c2a3..70b82b5 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ https://2ch.hk/s/res/2310304.html#2311483, https://archive.li/idixk - `earlyoom` завершает (точнее убивает) процессы исключительно с помощью сигнала `SIGKILL`, в то время как `nohang` дает возможность сначала отправлять `SIGTERM`, и только если процесс не реагирует на `SIGTERM` - отправляется сигнал `SIGKILL`. - `earlyoom` не поддерживает работу со `zram` и не реагирует на общую долю `zram` в памяти (`mem_used_total`). Это может привести к тому, что система все также встанет колом, как если бы `earlyoom` и не было (если `disksize` большой, а энтропия сжимаемых данных велика). `Nohang` позволяет избавиться от этой проблемы. По умолчанию если доля `zram` достигнет 60% памяти - будет отправлен сигнал `SIGTERM` процессу с наибольшим `oom_score`. -### Особенности +### Некоторые особенности - задача - препятствовать зависанию системы при нехватке доступной памяти, а также корректное завершение процессов с целью увеличения объема доступной памяти - демон на Python 3, VmRSS не более 13 MiB - требуется ядро `Linux 3.14` или новее @@ -55,14 +55,14 @@ https://2ch.hk/s/res/2310304.html#2311483, https://archive.li/idixk - протестировано на `Debian 9 x86_64`, `Debian 8 i386`, `Fedora 28 x86_64` - пример вывода с отчетом об успешной отпраке сигнала: ``` -MemAvail: 0M 0.0% | SwapFree: 1400M 11.9% | MemUsedZram: 397M 6.8% -MemAvail: 0M 0.0% | SwapFree: 861M 7.3% | MemUsedZram: 413M 7.0% -+ MemAvail (0M, 0.0%) < mem_min_sigterm (470M, 8.0%) - SwapFree (861M, 7.3%) < swap_min_sigterm (940M, 8.0%) - Try to send signal 15 to tail, Pid 10435, oom_score 826 +MemAvail: 0 M, 0.0 % | SwapFree: 97 M, 8.3 % | MemUsedZram: 147 M, 2.5 % +MemAvail: 0 M, 0.0 % | SwapFree: 80 M, 6.8 % | MemUsedZram: 147 M, 2.5 % ++ MemAvail (0 M, 0.0 %) < mem_min_sigterm (470 M, 8.0 %) + SwapFree (80 M, 6.8 %) < swap_min_sigterm (94 M, 8.0 %) + Try to send signal 15 to tail, Pid 17907, oom_score 837 Success -MemAvail: 102M 1.7% | SwapFree: 8106M 69.0% | MemUsedZram: 338M 5.7% -MemAvail: 4507M 76.7% | SwapFree: 10908M 92.8% | MemUsedZram: 296M 5.0% +MemAvail: 640 M, 10.9 % | SwapFree: 730 M, 62.1 % | MemUsedZram: 141 M, 2.4 % +MemAvail: 5197 M, 88.5 % | SwapFree: 734 M, 62.5 % | MemUsedZram: 141 M, 2.4 % ``` ### Установка и удаление для пользователей systemd diff --git a/nohang b/nohang index aad6031..b0ecc4a 100755 --- a/nohang +++ b/nohang @@ -3,9 +3,9 @@ # Nohang - No Hang Daemon -########################################################################################### +################################################################################ -# - импорты +### импорты import os from ctypes import CDLL @@ -13,19 +13,25 @@ from operator import itemgetter from time import sleep from argparse import ArgumentParser -########################################################################################### +################################################################################ -# - задание констант +### задание констант + +# директория, в которой запущен скрипт +cd = os.getcwd() # где искать конфиг, если не указан через опцию -c/--config CONFIG default_configs = ( - './nohang.conf', + cd + '/nohang.conf', '/etc/nohang/nohang.conf' ) -err_mess = '\nSet up path to the valid config file with -c/--config CONFIG option!\nexit' +# универсальное сообщение при инвалидном конфиге +conf_err_mess = "\nSet up the path to the valid config file w' \ +'ith -c/--config CONFIG option!\nExit" -# означает, что при задани zram disksize = 10000M доступная память уменьшится на 42M +# означает, что при задани zram disksize = 10000M доступная память +# уменьшится на 42M # найден экспериментально, требует уточнения с разными ядрами и архитектурами # на небольших дисксайзах (до гигабайта) может быть больше, до 0.0045 # создатель модуля zram утверждает, что zram_disksize_factor доожен быть 0.001 @@ -34,9 +40,23 @@ err_mess = '\nSet up path to the valid config file with -c/--config CONFIG optio # но это утверждение противоречит опытным данным zram_disksize_factor = 0.0042 -########################################################################################### +################################################################################ -# - задание функций +### задание функций + + +def string_to_float_convert_test(string): + try: + return float(string) + except ValueError: + return None + + +def string_to_int_convert_test(string): + try: + return int(string) + except ValueError: + return None def func_decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after): @@ -50,7 +70,10 @@ def func_decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after): try: oom_score_adj = int(rline1('/proc/' + i + '/oom_score_adj')) if oom_score_adj > oom_score_adj_before: - write('/proc/' + i + '/oom_score_adj', oom_score_adj_after + '\n') + write( + '/proc/' + i + '/oom_score_adj', + oom_score_adj_after + '\n' + ) except FileNotFoundError: pass except ProcessLookupError: @@ -78,7 +101,10 @@ def percent(num): return round(num * 100, 1) -def just_percent(num): +def just_percent_mem(num): + return str(round(num * 100, 1)).rjust(4, ' ') + +def just_percent_swap(num): return str(round(num * 100, 1)).rjust(5, ' ') @@ -122,7 +148,9 @@ def pid_to_name(pid): def find_victim_and_send_signal(signal): if decrease_oom_score_adj and root: - func_decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after) + func_decrease_oom_score_adj( + oom_score_adj_before, oom_score_adj_after + ) oom_list = [] for i in os.listdir('/proc'): @@ -160,22 +188,24 @@ def find_victim_and_send_signal(signal): print(' Operation not permitted') else: - print(' oom_score {} < oom_score_min {}'.format(oom_score, oom_score_min)) + print(' oom_score {} < oom_score_min {}'.format( + oom_score, oom_score_min) + ) # спать всегда или только при успешной отправке сигнала? if signal is 9: - if print_sleep_pediods: + if print_sleep_periods: print(' sleep', min_delay_after_sigkill) sleep(min_delay_after_sigterm) else: - if print_sleep_pediods: + if print_sleep_periods: print(' sleep', min_delay_after_sigterm) sleep(min_delay_after_sigterm) -########################################################################################### +################################################################################ -# - поиск позиций +### поиск позиций # ищем позиции @@ -187,7 +217,7 @@ for s in mem_list: mem_list_names.append(s.split(':')[0]) if mem_list_names[2] != 'MemAvailable': - print('Your Linux kernel is too old (3.14+ requie), bye!') + print('Your Linux kernel is too old, 3.14+ requie\nExit') exit() swap_total_index = mem_list_names.index('SwapTotal') @@ -199,16 +229,17 @@ mem_total = int(mem_list[0].split(':')[1].split(' ')[-2]) # еще найти позиции VmRSS & VmSwap -########################################################################################### +################################################################################ -# - получение пути к конфигу +### получение пути к конфигу # парсинг аргументов командной строки parser = ArgumentParser() parser.add_argument( '-c', '--config', - help='path to the config file, default values: ./nohang.conf, /etc/nohang/nohang.conf', + help="""path to the config file, default values: + ./nohang.conf, /etc/nohang/nohang.conf""", default=None, type=str ) @@ -224,7 +255,7 @@ if arg_config is None: config = i break if config is None: - print('По дефолтным путям конфиг не найден', err_mess) + print('По дефолтным путям конфиг не найден\nExit', conf_err_mess) exit() else: @@ -232,16 +263,16 @@ else: if os.path.exists(arg_config): config = arg_config else: - print('нет файла по указанному пути: {}'.format(arg_config), err_mess) + print("File {} doesn't exists{}".format(arg_config, conf_err_mess)) exit() -print('Path to nohang config file:', config) +print('The path to the config file to be used:') +print(config) +################################################################################ -########################################################################################### - -# - парсинг конфига с получением словаря параметров +### парсинг конфига с получением словаря параметров try: with open(config) as f: @@ -255,22 +286,25 @@ try: a = line.split('=') config_dict[a[0].strip()] = a[1].strip() except PermissionError: - print('PermissionError', err_mess) + print('PermissionError', conf_err_mess) exit() except UnicodeDecodeError: - print('UnicodeDecodeError', err_mess) + print('UnicodeDecodeError', conf_err_mess) exit() except IsADirectoryError: - print('IsADirectoryError', err_mess) + print('IsADirectoryError', conf_err_mess) exit() except IndexError: - print('IndexError', err_mess) + print('IndexError', conf_err_mess) exit() -########################################################################################### +################################################################################ + +### извлечение параметров из словаря +### проверка наличия всех необходимых параметров +### валидация всех параметров -# - извлечение параметров из словаря, проверка наличия всех необходимых параметров if 'print_config' in config_dict: @@ -281,15 +315,17 @@ if 'print_config' in config_dict: print_config = False else: print( - 'invalid print_config value {} (should be True or False), exit!'.format( + 'Invalid print_config value {} (should be True or Fa' \ + 'lse)\nExit'.format( print_config ) ) exit() else: - print('print_config not in config, exit!') + print('Print_config not in config\nExit') exit() + if 'print_mem_check_results' in config_dict: print_mem_check_results = config_dict['print_mem_check_results'] if print_mem_check_results == 'True': @@ -298,32 +334,36 @@ if 'print_mem_check_results' in config_dict: print_mem_check_results = False else: print( - 'invalid print_mem_check_results value {} (should be True or False), exit!'.format( + 'Invalid print_mem_check_results value {} (should be True o' \ + 'r False)\nExit'.format( print_mem_check_results ) ) exit() else: - print('print_mem_check_results not in config, exit!') + print('print_mem_check_results not in config\nExit') exit() -if 'print_sleep_pediods' in config_dict: - print_sleep_pediods = config_dict['print_sleep_pediods'] - if print_sleep_pediods == 'True': - print_sleep_pediods = True - elif print_sleep_pediods == 'False': - print_sleep_pediods = False + +if 'print_sleep_periods' in config_dict: + print_sleep_periods = config_dict['print_sleep_periods'] + if print_sleep_periods == 'True': + print_sleep_periods = True + elif print_sleep_periods == 'False': + print_sleep_periods = False else: print( - 'invalid print_sleep_pediods value {} (should be True or False), exit!'.format( - print_sleep_pediods + 'Invalid print_sleep_periods value {} (should be Tru' \ + 'e or False)\nExit'.format( + print_sleep_periods ) ) exit() else: - print('print_sleep_pediods not in config, exit!') + print('print_sleep_periods not in config\nExit') exit() + if 'mlockall' in config_dict: mlockall = config_dict['mlockall'] if mlockall == 'True': @@ -332,108 +372,178 @@ if 'mlockall' in config_dict: mlockall = False else: print( - 'invalid mlockall value {} (should be True or False), exit!'.format( + 'Invalid mlockall value {} (should be True or False)\nExit'.format( mlockall ) ) exit() else: - print('mlockall not in config, exit!') + print('mlockall not in config\nExit') exit() + if 'self_nice' in config_dict: - self_nice = int(config_dict['self_nice']) + self_nice = config_dict['self_nice'] + if string_to_int_convert_test(self_nice) is None: + print('Invalid self_nice value, not integer\nExit') + exit() + else: + self_nice = int(self_nice) + if self_nice < -20 or self_nice > 19: + print('Недопустимое значение self_nice\nExit') + exit() else: - print('self_nice not in config, exit!') + print('self_nice not in config\nExit') exit() + + if 'self_oom_score_adj' in config_dict: - self_oom_score_adj = int(config_dict['self_oom_score_adj']) + self_oom_score_adj = config_dict['self_oom_score_adj'] + if string_to_int_convert_test(self_oom_score_adj) is None: + print('Invalid self_oom_score_adj value, not integer\nExit') + exit() + else: + self_oom_score_adj = int(self_oom_score_adj) + if self_oom_score_adj < -1000 or self_oom_score_adj > 1000: + print('Недопустимое значение self_oom_score_adj\nExit') + exit() else: - print('self_oom_score_adj not in config, exit!') + print('self_oom_score_adj not in config\nExit') exit() + if 'rate_mem' in config_dict: - rate_mem = float(config_dict['rate_mem']) + rate_mem = string_to_float_convert_test(config_dict['rate_mem']) + if rate_mem is None: + print('Invalid rate_mem value, not float\nExit') + exit() + rate_mem = float(rate_mem) if rate_mem <= 0: - print('rate_mem должен быть положительным') + print('rate_mem должен быть положительным\nExit') exit() else: - print('rate_mem not in config, exit!') + print('rate_mem not in config\nExit') exit() + if 'rate_swap' in config_dict: - rate_swap = float(config_dict['rate_swap']) + rate_swap = string_to_float_convert_test(config_dict['rate_swap']) + if rate_swap is None: + print('Invalid rate_swap value, not float\nExit') + exit() + rate_swap = float(rate_swap) if rate_swap <= 0: - print('rate_swap должен быть положительным') + print('rate_swap должен быть положительным\nExit') exit() else: - print('rate_swap not in config, exit!') + print('rate_swap not in config\nExit') exit() + if 'rate_zram' in config_dict: - rate_zram = float(config_dict['rate_zram']) + rate_zram = string_to_float_convert_test(config_dict['rate_zram']) + if rate_zram is None: + print('Invalid rate_zram value, not float\nExit') + exit() + rate_zram = float(rate_zram) if rate_zram <= 0: - print('rate_zram должен быть положительным') + print('rate_zram должен быть положительным\nExit') exit() else: - print('rate_zram not in config, exit!') + print('rate_zram not in config\nExit') exit() + + if 'mem_min_sigterm' in config_dict: mem_min_sigterm = config_dict['mem_min_sigterm'] else: - print('mem_min_sigterm not in config, exit!') + print('mem_min_sigterm not in config\nExit') exit() + if 'mem_min_sigkill' in config_dict: mem_min_sigkill = config_dict['mem_min_sigkill'] else: - print('mem_min_sigkill not in config, exit!') + print('mem_min_sigkill not in config\nExit') exit() + if 'swap_min_sigterm' in config_dict: swap_min_sigterm = config_dict['swap_min_sigterm'] else: - print('swap_min_sigterm not in config, exit!') + print('swap_min_sigterm not in config\nExit') exit() + if 'swap_min_sigkill' in config_dict: swap_min_sigkill = config_dict['swap_min_sigkill'] else: - print('swap_min_sigkill not in config, exit!') + print('swap_min_sigkill not in config\nExit') exit() + if 'zram_max_sigterm' in config_dict: zram_max_sigterm = config_dict['zram_max_sigterm'] else: - print('zram_max_sigterm not in config, exit!') + print('zram_max_sigterm not in config\nExit') exit() + if 'zram_max_sigkill' in config_dict: zram_max_sigkill = config_dict['zram_max_sigkill'] else: - print('zram_max_sigkill not in config, exit!') + print('zram_max_sigkill not in config\nExit') exit() + + if 'min_delay_after_sigterm' in config_dict: - min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm']) + min_delay_after_sigterm = string_to_float_convert_test(config_dict['m' \ + 'in_delay_after_sigterm']) + if min_delay_after_sigterm is None: + print('Invalid min_delay_after_sigterm value, not float\nExit') + exit() + min_delay_after_sigterm = float(min_delay_after_sigterm) + if min_delay_after_sigterm < 0: + print('min_delay_after_sigterm должен быть неотрицательным\nExit') + exit() else: - print('min_delay_after_sigterm not in config, exit!') + print('min_delay_after_sigterm not in config\nExit') exit() + if 'min_delay_after_sigkill' in config_dict: - min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill']) + min_delay_after_sigkill = string_to_float_convert_test(config_dict['mi' \ + 'n_delay_after_sigkill']) + if min_delay_after_sigkill is None: + print('Invalid min_delay_after_sigkill value, not float\nExit') + exit() + min_delay_after_sigkill = float(min_delay_after_sigkill) + if min_delay_after_sigkill < 0: + print('min_delay_after_sigkill должен быть неотрицательным\nExit') + exit() else: - print('min_delay_after_sigkill not in config, exit!') + print('min_delay_after_sigkill not in config\nExit') exit() + if 'oom_score_min' in config_dict: - oom_score_min = int(config_dict['oom_score_min']) + oom_score_min = config_dict['oom_score_min'] + if string_to_int_convert_test(oom_score_min) is None: + print('Invalid oom_score_min value, not integer\nExit') + exit() + else: + oom_score_min = int(oom_score_min) + if oom_score_min < 0 or oom_score_min > 1000: + print('Недопустимое значение oom_score_min\nExit') + exit() else: - print('oom_score_min not in config, exit!') + print('oom_score_min not in config\nExit') exit() + if 'decrease_oom_score_adj' in config_dict: decrease_oom_score_adj = config_dict['decrease_oom_score_adj'] if decrease_oom_score_adj == 'True': @@ -442,32 +552,50 @@ if 'decrease_oom_score_adj' in config_dict: decrease_oom_score_adj = False else: print( - 'invalid decrease_oom_score_adj value {} (should be True or False), exit!'.format( + 'invalid decrease_oom_score_adj value {} (should be Tru' \ + 'e or False)\nExit'.format( decrease_oom_score_adj ) ) exit() else: - print('decrease_oom_score_adj not in config, exit!') + print('decrease_oom_score_adj not in config\nExit') exit() + if 'oom_score_adj_before' in config_dict: - oom_score_adj_before = int(config_dict['oom_score_adj_before']) + oom_score_adj_before = config_dict['oom_score_adj_before'] + if string_to_int_convert_test(oom_score_adj_before) is None: + print('Invalid oom_score_adj_before value, not integer\nExit') + exit() + else: + oom_score_adj_before = int(oom_score_adj_before) + if oom_score_adj_before < 0 or oom_score_adj_before > 1000: + print('Недопустимое значение oom_score_adj_before\nExit') + exit() else: - print('oom_score_adj_before not in config, exit!') + print('oom_score_adj_before not in config\nExit') exit() + if 'oom_score_adj_after' in config_dict: oom_score_adj_after = config_dict['oom_score_adj_after'] + if string_to_int_convert_test(oom_score_adj_after) is None: + print('Invalid oom_score_adj_after value, not integer\nExit') + exit() + else: + oom_score_adj_after = int(oom_score_adj_after) + if oom_score_adj_after < 0 or oom_score_adj_after > 1000: + print('Недопустимое значение oom_score_adj_after\nExit') + exit() else: - print('oom_score_adj_after not in config, exit!') + print('oom_score_adj_after not in config\nExit') exit() +################################################################################ -########################################################################################### - -# - получение уровней в килобайтах +### получение уровней в кибибайтах def sig_level_to_kb(string): @@ -480,7 +608,9 @@ def sig_level_to_kb(string): elif string.endswith('G'): return float(string[:-1].strip()) * 1048576 else: - print('Конфиг инвалид, где-то неверно указаны единицы измерения') + print( + 'Конфиг инвалид, где-то неверно указаны единицы измерения\nExit' + ) exit() @@ -504,7 +634,7 @@ def sig_level_to_kb_swap(string): elif string.endswith('G'): return float(string[:-1].strip()) * 1048576 else: - print('Конфиг инвалид, где-то неверно указаны единицы измерения') + print('Конфиг инвалид, где-то неверно указаны единицы измерения\nExit') exit() @@ -528,9 +658,9 @@ else: -########################################################################################### +################################################################################ -# - самозащита и печать конфига +### самозащита и печать конфига # повышаем приоритет @@ -574,31 +704,46 @@ else: if print_config: - print('print_config: {}'.format(print_config)) - print('print_mem_check_results: {}'.format(print_mem_check_results)) - print('print_sleep_pediods: {}'.format(print_sleep_pediods)) - print('mlockall: {} ({})'.format(mlockall, mla_res)) - print('self_nice: {} ({})'.format(self_nice, self_nice_result)) - print('self_oom_score_adj: {} ({})'.format(self_oom_score_adj, self_oom_score_adj_result)) - print('rate_mem: {}'.format(rate_mem)) - print('rate_swap: {}'.format(rate_swap)) - print('rate_zram: {}'.format(rate_zram)) - print('mem_min_sigterm: {}'.format(mem_min_sigterm)) - print('mem_min_sigkill: {}'.format(mem_min_sigkill)) - print('swap_min_sigterm: {}'.format(swap_min_sigterm)) - print('swap_min_sigkill: {}'.format(swap_min_sigkill)) - print('zram_max_sigterm: {}'.format(zram_max_sigterm)) - print('zram_max_sigkill: {}'.format(zram_max_sigkill)) - print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm)) - print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill)) - print('oom_score_min: {}'.format(oom_score_min)) - + + print('\nI. VERBOSITY') + print('print_config: {}'.format(print_config)) + print('print_mem_check_results: {}'.format(print_mem_check_results)) + print('print_sleep_periods: {}'.format(print_sleep_periods)) + + print('\nII. SELF PROTECTION') + print('mlockall: {} ({})'.format(mlockall, mla_res)) + print('self_nice: {} ({})'.format( + self_nice, self_nice_result + )) + print('self_oom_score_adj: {} ({})'.format( + self_oom_score_adj, self_oom_score_adj_result + )) + + print('\nIII. ИНТЕНСИВНОСТЬ МОНИТОРИНГА') + print('rate_mem: {}'.format(rate_mem)) + print('rate_swap: {}'.format(rate_swap)) + print('rate_zram: {}'.format(rate_zram)) + + print('\nIV. ПОРОГИ ДЛЯ ОТПРАВКИ СИГНАЛОВ') + print('mem_min_sigterm: {}'.format(mem_min_sigterm)) + print('mem_min_sigkill: {}'.format(mem_min_sigkill)) + print('swap_min_sigterm: {}'.format(swap_min_sigterm)) + print('swap_min_sigkill: {}'.format(swap_min_sigkill)) + print('zram_max_sigterm: {}'.format(zram_max_sigterm)) + print('zram_max_sigkill: {}'.format(zram_max_sigkill)) + + print('\nV. ПРЕДОТВРАЩЕНИЕ УБИЙСТВ НЕВИНОВНЫХ') + print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm)) + print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill)) + print('oom_score_min: {}'.format(oom_score_min)) + # False (OK) - OK не нужен когда фолс - print('decrease_oom_score_adj: {} ({})'.format(decrease_oom_score_adj, decrease_res)) - print('oom_score_adj_before: {}'.format(oom_score_adj_before)) - print('oom_score_adj_after: {}'.format(oom_score_adj_after)) - - + print('decrease_oom_score_adj: {} ({})'.format( + decrease_oom_score_adj, decrease_res + )) + if decrease_oom_score_adj: + print('oom_score_adj_before: {}'.format(oom_score_adj_before)) + print('oom_score_adj_after: {}'.format(oom_score_adj_after)) @@ -606,31 +751,30 @@ if print_config: mem_len = len(str(round(mem_total / 1024.0))) -########################################################################################### +print('\nStart monitoring...') -# - цикл проверки уровней доступной памяти +################################################################################ + +### цикл проверки уровней доступной памяти -print('Start monitoring...') -# рабочий цикл while True: #decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after) # находим mem_available, swap_total, swap_free with open('/proc/meminfo') as f: for n, line in enumerate(f): - if n == 2: + if n is 2: mem_available = int(line.split(':')[1].split(' ')[-2]) continue - if n == swap_total_index: + if n is swap_total_index: swap_total = int(line.split(':')[1].split(' ')[-2]) continue - if n == swap_free_index: + if n is swap_free_index: swap_free = int(line.split(':')[1].split(' ')[-2]) break - # если swap_min_sigkill задан в процентах if swap_kill_is_percent: swap_min_sigkill_kb = swap_total * swap_min_sigkill_percent / 100.0 @@ -656,18 +800,38 @@ while True: swap_len = len(str(round(swap_total / 1024.0))) - # печать результатов проверк доступной памяти - if print_mem_check_results: - print( - 'MemAvail: {}M {}% | SwapFree: {}M {}% | MemUsedZram: {}M {}%'.format( - human(mem_available, mem_len), - just_percent(mem_available / mem_total), - human(swap_free, swap_len), - just_percent(swap_free / (swap_total + 0.0001)), - human(mem_used_zram, mem_len), - just_percent(mem_used_zram / mem_total) + # печать размеров доступной памяти + if swap_total == 0 and mem_used_zram == 0: + if print_mem_check_results: + print( + 'MemAvail: {} M, {} %'.format( + human(mem_available, mem_len), + just_percent_mem(mem_available / mem_total) + ) + ) + elif swap_total > 0 and mem_used_zram == 0: + if print_mem_check_results: + print( + 'MemAvail: {} M, {} % | SwapFree: {} M, {} %'.format( + human(mem_available, mem_len), + just_percent_mem(mem_available / mem_total), + human(swap_free, swap_len), + just_percent_swap(swap_free / (swap_total + 0.0001)) + ) + ) + else: + if print_mem_check_results: + print( + 'MemAvail: {} M, {} % | SwapFree: {} M, {} % | MemUsed' \ + 'Zram: {} M, {} %'.format( + human(mem_available, mem_len), + just_percent_mem(mem_available / mem_total), + human(swap_free, swap_len), + just_percent_swap(swap_free / (swap_total + 0.0001)), + human(mem_used_zram, mem_len), + just_percent_mem(mem_used_zram / mem_total) + ) ) - ) # если swap_min_sigkill задан в абсолютной величине и Swap_total = 0 @@ -685,8 +849,8 @@ while True: # MEM SWAP KILL if mem_available <= mem_min_sigkill_kb and swap_free <= swap_min_sigkill_kb: print( - '+ MemAvail ({}M, {}%) < mem_min_sigkill ({}M, {}%)\n SwapFree' \ - ' ({}M, {}%) < swap_min_sigkill ({}M, {}%)'.format( + '+ MemAvail ({} M, {} %) < mem_min_sigkill ({} M, {} %)\n S' \ + 'wapFree ({} M, {} %) < swap_min_sigkill ({} M, {} %)'.format( kib_to_mib(mem_available), percent(mem_available / mem_total), kib_to_mib(mem_min_sigkill_kb), @@ -701,10 +865,10 @@ while True: continue - # MEM ZRAM KILL + # ZRAM KILL if mem_used_zram >= zram_max_sigkill_kb: print( - '+ MemUsedZram ({}M, {}%) > zram_max_sigkill ({}M, {}%)'.format( + '+ MemUsedZram ({} M, {} %) > zram_max_sigkill ({} M, {} %)'.format( kib_to_mib(mem_used_zram), percent(mem_used_zram / mem_total), kib_to_mib(zram_max_sigkill_kb), @@ -718,8 +882,8 @@ while True: # MEM SWAP TERM if mem_available <= mem_min_sigterm_kb and swap_free <= swap_min_sigterm_kb: print( - '+ MemAvail ({}M, {}%) < mem_min_sigterm ({}M, {}%)\n SwapFree' \ - ' ({}M, {}%) < swap_min_sigterm ({}M, {}%)'.format( + '+ MemAvail ({} M, {} %) < mem_min_sigterm ({} M, {} %)\n SwapFree' \ + ' ({} M, {} %) < swap_min_sigterm ({} M, {} %)'.format( kib_to_mib(mem_available), percent(mem_available / mem_total), kib_to_mib(mem_min_sigterm_kb), @@ -733,10 +897,10 @@ while True: find_victim_and_send_signal(15) - # MEM ZRAM TERM + # ZRAM TERM if mem_used_zram >= zram_max_sigterm_kb: print( - '+ MemUsedZram ({}M, {}%) > zram_max_sigterm ({}M, {}%)'.format( + '+ MemUsedZram ({} M, {} %) > zram_max_sigterm ({} M, {} %)'.format( kib_to_mib(mem_used_zram), percent(mem_used_zram / mem_total), kib_to_mib(zram_max_sigterm_kb), @@ -746,7 +910,6 @@ while True: find_victim_and_send_signal(15) - # задание периода в зависимости от рейтов и уровней доступной памяти t_mem = mem_available / 1000000.0 / rate_mem @@ -765,8 +928,8 @@ while True: t = t_mem_zram try: - if print_sleep_pediods: - print('sleep', round(t, 2)) + if print_sleep_periods: + print('sleep', round(t, 3)) sleep(t) except KeyboardInterrupt: exit() diff --git a/nohang.conf b/nohang.conf index a6dfd32..7c7a7d0 100644 --- a/nohang.conf +++ b/nohang.conf @@ -23,11 +23,11 @@ print_mem_check_results = True сигналов. Можно установить в значение True для дебага. Допустимые значения: True и False -print_sleep_pediods = False +print_sleep_periods = False ##################################################################### - II. САМОЗАЩИТА ПРОЦЕССА + II. SELF PROTECTION True - заблокировать процесс в памяти для запрета его своппинга. False - не блокировать. Значения чувствительны к регистру! @@ -68,7 +68,7 @@ self_oom_score_adj = -1000 памяти. rate_mem = 6 -rate_swap = 0.2 +rate_swap = 0.5 rate_zram = 1 ##################################################################### @@ -107,7 +107,7 @@ zram_max_sigkill = 60 % ##################################################################### - VI. ПРЕДОТВРАЩЕНИЕ ИЗБЫТОЧНЫХ УБИЙСТВ + V. ПРЕДОТВРАЩЕНИЕ УБИЙСТВ НЕВИНОВНЫХ Минимальное значение oom_score, которым должен обладать процесс для того, чтобы ему был отправлен сигнал. @@ -125,10 +125,6 @@ oom_score_min = 15 min_delay_after_sigterm = 0.1 min_delay_after_sigkill = 3 -##################################################################### - - VII. ЗАЩИТА ПРОЦЕССОВ CHROMIUM ОТ СМЕРТИ ПО ЧУЖОЙ ВИНЕ - Процессы браузера chromium обычно имеют oom_score_adj 200 или 300. Это приводит к тому, что процессы хрома умирают первыми вместо действительно тяжелых процессов. diff --git a/nohang.service b/nohang.service index 95b83f7..698c5e2 100644 --- a/nohang.service +++ b/nohang.service @@ -6,7 +6,6 @@ Documentation=man:nohang(1) https://github.com/hakavlad/nohang [Service] Type=simple -PIDFile=/run/nohang.pid Restart=always ExecStart=/usr/local/bin/nohang