добавлены verbosity опции

This commit is contained in:
Alexey Avramov 2018-06-11 16:08:28 +09:00
parent 27d22d41e4
commit 7647a1fd7f
3 changed files with 135 additions and 121 deletions

View File

@ -47,7 +47,7 @@ https://2ch.hk/s/res/2310304.html#2311483, https://archive.li/idixk
- по умолчанию высокий приоритет процесса `nice -20`, может регулироваться через конфиг - по умолчанию высокий приоритет процесса `nice -20`, может регулироваться через конфиг
- предотвращение самоубийства с помощью `self_oom_score_adj = -1000` - предотвращение самоубийства с помощью `self_oom_score_adj = -1000`
- возможность задания `oom_score_min` для предотвращения убийства невиновных - возможность задания `oom_score_min` для предотвращения убийства невиновных
- опциональность печати результатов проверки памяти - verbosity: опциональность печати параметров конфига при старте программы, опциональность печати результатов проверки памяти
- `min_delay_after_sigkill` для предотвращения массовых убийств - `min_delay_after_sigkill` для предотвращения массовых убийств
- наличие `man` страницы - наличие `man` страницы
- наличие установщика для пользователей `systemd` - наличие установщика для пользователей `systemd`
@ -90,5 +90,16 @@ sudo ./uninstall.sh
``` ```
К опциям прилагается описание. Отредактируйте значения параметров в соответствии с вашими предпочтениями и перезапустите сервис командой `sudo systemctl restart nohang`. К опциям прилагается описание. Отредактируйте значения параметров в соответствии с вашими предпочтениями и перезапустите сервис командой `sudo systemctl restart nohang`.
### Почему Python, а не C?
- Скорость разработки на Python значительно выше. Больше фич за приемлемое время.
- Практически единственный минус разработки на Python - большее потребление памяти.
### Известные баги ### Известные баги
В рабочем алгоритме известных нет, если найдете - пишите в [Issues](https://github.com/hakavlad/nohang/issues). В рабочем алгоритме известных нет, если найдете - пишите в [Issues](https://github.com/hakavlad/nohang/issues).

193
nohang
View File

@ -56,12 +56,7 @@ else:
exit() exit()
print('Path to nohang config file:', config)
print('path to config:', config)
try: try:
@ -90,6 +85,29 @@ except IndexError:
###########################################################################################
# проверка наличия параметров в словаре, их извречение из словаря
if 'print_config' in config_dict:
print_config = config_dict['print_config']
if print_config == 'True':
print_config = True
elif print_config == 'False':
print_config = False
else:
print(
'invalid print_config value {} (should be True or False), exit!'.format(
print_config
)
)
exit()
else:
print('print_config not in config, exit!')
exit()
if 'print_mem_check_results' in config_dict: if 'print_mem_check_results' in config_dict:
print_mem_check_results = config_dict['print_mem_check_results'] print_mem_check_results = config_dict['print_mem_check_results']
@ -99,17 +117,15 @@ if 'print_mem_check_results' in config_dict:
print_mem_check_results = False print_mem_check_results = False
else: else:
print( print(
'invalid mlockall value {} (should be True or False), exit!'.format( 'invalid print_mem_check_results value {} (should be True or False), exit!'.format(
print_mem_check_results print_mem_check_results
) )
) )
exit() exit()
print('print_mem_check_results: {}'.format(print_mem_check_results))
else: else:
print('print_mem_check_results not in config, exit!') print('print_mem_check_results not in config, exit!')
exit() exit()
if 'mlockall' in config_dict: if 'mlockall' in config_dict:
mlockall = config_dict['mlockall'] mlockall = config_dict['mlockall']
if mlockall == 'True': if mlockall == 'True':
@ -123,133 +139,103 @@ if 'mlockall' in config_dict:
) )
) )
exit() exit()
print('mlockall: {}'.format(mlockall))
else: else:
print('mlockall not in config, exit!') print('mlockall not in config, exit!')
exit() exit()
if 'self_nice' in config_dict: if 'self_nice' in config_dict:
self_nice = int(config_dict['self_nice']) self_nice = int(config_dict['self_nice'])
print('self_nice: {}'.format(self_nice))
else: else:
print('self_nice not in config, exit!') print('self_nice not in config, exit!')
exit() exit()
if 'self_oom_score_adj' in config_dict: if 'self_oom_score_adj' in config_dict:
self_oom_score_adj = int(config_dict['self_oom_score_adj']) self_oom_score_adj = int(config_dict['self_oom_score_adj'])
print('self_oom_score_adj: {}'.format(self_oom_score_adj))
else: else:
print('self_oom_score_adj not in config, exit!') print('self_oom_score_adj not in config, exit!')
exit() exit()
if 'rate_mem' in config_dict: if 'rate_mem' in config_dict:
rate_mem = float(config_dict['rate_mem']) rate_mem = float(config_dict['rate_mem'])
if rate_mem <= 0: if rate_mem <= 0:
print('rate_mem должен быть положительным') print('rate_mem должен быть положительным')
exit() exit()
print('rate_mem: {}'.format(rate_mem))
else: else:
print('rate_mem not in config, exit!') print('rate_mem not in config, exit!')
exit() exit()
if 'rate_swap' in config_dict: if 'rate_swap' in config_dict:
rate_swap = float(config_dict['rate_swap']) rate_swap = float(config_dict['rate_swap'])
if rate_swap <= 0: if rate_swap <= 0:
print('rate_swap должен быть положительным') print('rate_swap должен быть положительным')
exit() exit()
print('rate_swap: {}'.format(rate_swap))
else: else:
print('rate_swap not in config, exit!') print('rate_swap not in config, exit!')
exit() exit()
if 'rate_zram' in config_dict: if 'rate_zram' in config_dict:
rate_zram = float(config_dict['rate_zram']) rate_zram = float(config_dict['rate_zram'])
if rate_zram <= 0: if rate_zram <= 0:
print('rate_zram должен быть положительным') print('rate_zram должен быть положительным')
exit() exit()
print('rate_zram: {}'.format(rate_zram))
else: else:
print('rate_zram not in config, exit!') print('rate_zram not in config, exit!')
exit() exit()
if 'mem_min_sigterm' in config_dict: if 'mem_min_sigterm' in config_dict:
mem_min_sigterm = config_dict['mem_min_sigterm'] mem_min_sigterm = config_dict['mem_min_sigterm']
print('mem_min_sigterm: {}'.format(mem_min_sigterm))
else: else:
print('mem_min_sigterm not in config, exit!') print('mem_min_sigterm not in config, exit!')
exit() exit()
if 'mem_min_sigkill' in config_dict: if 'mem_min_sigkill' in config_dict:
mem_min_sigkill = config_dict['mem_min_sigkill'] mem_min_sigkill = config_dict['mem_min_sigkill']
print('mem_min_sigkill: {}'.format(mem_min_sigkill))
else: else:
print('mem_min_sigkill not in config, exit!') print('mem_min_sigkill not in config, exit!')
exit() exit()
if 'swap_min_sigterm' in config_dict: if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm'] swap_min_sigterm = config_dict['swap_min_sigterm']
print('swap_min_sigterm: {}'.format(swap_min_sigterm))
else: else:
print('swap_min_sigterm not in config, exit!') print('swap_min_sigterm not in config, exit!')
exit() exit()
if 'swap_min_sigkill' in config_dict: if 'swap_min_sigkill' in config_dict:
swap_min_sigkill = config_dict['swap_min_sigkill'] swap_min_sigkill = config_dict['swap_min_sigkill']
print('swap_min_sigkill: {}'.format(swap_min_sigkill))
else: else:
print('swap_min_sigkill not in config, exit!') print('swap_min_sigkill not in config, exit!')
exit() exit()
if 'zram_max_sigterm' in config_dict: if 'zram_max_sigterm' in config_dict:
zram_max_sigterm = config_dict['zram_max_sigterm'] zram_max_sigterm = config_dict['zram_max_sigterm']
print('zram_max_sigterm: {}'.format(zram_max_sigterm))
else: else:
print('zram_max_sigterm not in config, exit!') print('zram_max_sigterm not in config, exit!')
exit() exit()
if 'zram_max_sigkill' in config_dict: if 'zram_max_sigkill' in config_dict:
zram_max_sigkill = config_dict['zram_max_sigkill'] zram_max_sigkill = config_dict['zram_max_sigkill']
print('zram_max_sigkill: {}'.format(zram_max_sigkill))
else: else:
print('zram_max_sigkill not in config, exit!') print('zram_max_sigkill not in config, exit!')
exit() exit()
if 'min_delay_after_sigterm' in config_dict: if 'min_delay_after_sigterm' in config_dict:
min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm']) min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm'])
print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm))
else: else:
print('min_delay_after_sigterm not in config, exit!') print('min_delay_after_sigterm not in config, exit!')
exit() exit()
if 'min_delay_after_sigkill' in config_dict: if 'min_delay_after_sigkill' in config_dict:
min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill']) min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill'])
print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill))
else: else:
print('min_delay_after_sigkill not in config, exit!') print('min_delay_after_sigkill not in config, exit!')
exit() exit()
if 'oom_score_min' in config_dict: if 'oom_score_min' in config_dict:
oom_score_min = int(config_dict['oom_score_min']) oom_score_min = int(config_dict['oom_score_min'])
print('oom_score_min: {}'.format(oom_score_min))
else: else:
print('oom_score_min not in config, exit!') print('oom_score_min not in config, exit!')
exit() exit()
if 'decrease_oom_score_adj_enable' in config_dict: if 'decrease_oom_score_adj_enable' in config_dict:
decrease_oom_score_adj_enable = config_dict['decrease_oom_score_adj_enable'] decrease_oom_score_adj_enable = config_dict['decrease_oom_score_adj_enable']
if decrease_oom_score_adj_enable == 'True': if decrease_oom_score_adj_enable == 'True':
@ -258,33 +244,93 @@ if 'decrease_oom_score_adj_enable' in config_dict:
decrease_oom_score_adj_enable = False decrease_oom_score_adj_enable = False
else: else:
print( print(
'invalid mlockall value {} (should be True or False), exit!'.format( 'invalid decrease_oom_score_adj_enable value {} (should be True or False), exit!'.format(
decrease_oom_score_adj_enable decrease_oom_score_adj_enable
) )
) )
exit() exit()
print('decrease_oom_score_adj_enable: {}'.format(decrease_oom_score_adj_enable))
else: else:
print('decrease_oom_score_adj_enable not in config, exit!') print('decrease_oom_score_adj_enable not in config, exit!')
exit() exit()
if 'oom_score_adj_before' in config_dict: if 'oom_score_adj_before' in config_dict:
oom_score_adj_before = int(config_dict['oom_score_adj_before']) oom_score_adj_before = int(config_dict['oom_score_adj_before'])
print('oom_score_adj_before: {}'.format(oom_score_adj_before))
else: else:
print('oom_score_adj_before not in config, exit!') print('oom_score_adj_before not in config, exit!')
exit() exit()
if 'oom_score_adj_after' in config_dict: if 'oom_score_adj_after' in config_dict:
oom_score_adj_after = config_dict['oom_score_adj_after'] oom_score_adj_after = config_dict['oom_score_adj_after']
print('oom_score_adj_after: {}'.format(oom_score_adj_after))
else: else:
print('oom_score_adj_after not in config, exit!') print('oom_score_adj_after not in config, exit!')
exit() exit()
###########################################################################################
# повышаем приоритет
try:
os.nice(self_nice)
self_nice_result = 'OK'
except PermissionError:
self_nice_result = 'Fail'
pass
# возможность запрета самоубийства
try:
with open('/proc/self/oom_score_adj', 'w') as file:
file.write('{}\n'.format(self_oom_score_adj))
self_oom_score_adj_result = 'OK'
except PermissionError:
pass
self_oom_score_adj_result = 'Fail'
except OSError:
self_oom_score_adj_result = 'Fail'
pass
# запрет своппинга процесса
if mlockall:
result = CDLL('libc.so.6', use_errno=True).mlockall(3)
if result is 0:
mla_res = 'OK'
else:
mla_res = 'Fail'
else:
mla_res = ''
if os.geteuid() == 0:
root = True
decrease_res = 'OK'
else:
root = False
decrease_res = 'Impossible'
if print_config:
print('print_config: {}'.format(print_config))
print('print_mem_check_results: {}'.format(print_mem_check_results))
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('decrease_oom_score_adj_enable: {} ({})'.format(decrease_oom_score_adj_enable, decrease_res))
print('oom_score_adj_before: {}'.format(oom_score_adj_before))
print('oom_score_adj_after: {}'.format(oom_score_adj_after))
@ -294,11 +340,6 @@ else:
def decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after): def decrease_oom_score_adj(oom_score_adj_before, oom_score_adj_after):
#print('Decrease oom_score_adj...') #print('Decrease oom_score_adj...')
# цикл для наполнения oom_list # цикл для наполнения oom_list
@ -461,8 +502,6 @@ def sig_level_to_kb(string):
exit() exit()
mem_min_sigterm_kb = sig_level_to_kb(mem_min_sigterm) mem_min_sigterm_kb = sig_level_to_kb(mem_min_sigterm)
mem_min_sigkill_kb = sig_level_to_kb(mem_min_sigkill) mem_min_sigkill_kb = sig_level_to_kb(mem_min_sigkill)
zram_max_sigterm_kb = sig_level_to_kb(zram_max_sigterm) zram_max_sigterm_kb = sig_level_to_kb(zram_max_sigterm)
@ -507,53 +546,6 @@ else:
swap_min_sigkill_kb = swap_min_sigkill_swap swap_min_sigkill_kb = swap_min_sigkill_swap
# print('\nswap term is percent:', swap_term_is_percent)
# print('swap kill is percent:', swap_kill_is_percent)
print("\ncurrent process's effective user id", os.geteuid())
if os.geteuid() == 0:
root = True
else:
root = False
print()
# lock all memory for prevent swapping
if mlockall:
print('mlockall = True')
print('try to lock memory...')
result = CDLL('libc.so.6', use_errno=True).mlockall(3)
if result is 0:
print('memory locked!', 'result', result)
else:
print('cannot lock memory!', 'result', result)
else:
print('mlockall != True')
# повышаем приоритет
try:
os.nice(self_nice)
print('self_nice = {}'.format(self_nice))
except PermissionError:
pass
# запрещаем самоубийство по возможности
try:
with open('/proc/self/oom_score_adj', 'w') as file:
file.write('{}\n'.format(self_oom_score_adj))
print('self_oom_score_adj = {}'.format(self_oom_score_adj))
except PermissionError:
pass
except OSError:
pass
def kib_to_mib(num): def kib_to_mib(num):
return round(num / 1024.0) return round(num / 1024.0)
@ -562,7 +554,6 @@ def kib_to_mib(num):
print('Start monitoring...') print('Start monitoring...')
# рабочий цикл # рабочий цикл
@ -582,6 +573,8 @@ while True:
swap_free = int(line.split(':')[1].split(' ')[-2]) swap_free = int(line.split(':')[1].split(' ')[-2])
break break
if swap_kill_is_percent: if swap_kill_is_percent:
swap_min_sigkill_kb = swap_total * swap_min_sigkill_percent / 100.0 swap_min_sigkill_kb = swap_total * swap_min_sigkill_percent / 100.0

View File

@ -1,14 +1,19 @@
Nohang config file Nohang config file
#####################################################################
Комментариями являются строки, начинающиеся с решёток, пробелов Комментариями являются строки, начинающиеся с решёток, пробелов
и табуляций. Инлайновые комментарии запрещены. Пробелы допустиы и табуляций. Инлайновые комментарии запрещены. Пробелы допустиы
внутри строк в любом количестве. внутри строк в любом количестве.
##################################################################### #####################################################################
I. VERBOSITY
Печатать параметров конфига при запуске программы.
Допустимые значения: True и False
print_config = True
Печатать ли результаты измерения доступной памяти. Печатать ли результаты измерения доступной памяти.
Допустимые значения: True и False Допустимые значения: True и False
@ -16,31 +21,31 @@ print_mem_check_results = True
##################################################################### #####################################################################
II. САМОЗАЩИТА ПРОЦЕССА
True - заблокировать процесс в памяти для запрета его своппинга. True - заблокировать процесс в памяти для запрета его своппинга.
False - не блокировать. Значения чувствительны к регистру! False - не блокировать. Значения чувствительны к регистру!
Требует рут прав.
mlockall = True mlockall = True
##################################################################### Установка отрицательных значений self_nice и self_oom_score_adj
требует наличия root прав.
Повысить приоритет процесса, установив niceness -20 Повысить приоритет процесса, установив niceness -20
Допустимые значения - целые числа из диапазона [-20; 19] Допустимые значения - целые числа из диапазона [-20; 19]
Требует рут прав.
self_nice = -20 self_nice = -20
#####################################################################
Задать oom_score_adj для процесса. Задать oom_score_adj для процесса.
Задание значения -1000 запретит самоубийство. Установка значения -1000 запретит самоубийство.
Допустимые значения - целые числа из диапазона [-1000; 1000] Допустимые значения - целые числа из диапазона [-1000; 1000]
Требует рут прав.
self_oom_score_adj = -1000 self_oom_score_adj = -1000
##################################################################### #####################################################################
III. ИНТЕНСИВНОСТЬ МОНИТОРИНГА
Коэффициенты, влияющие на интенсивность мониторинга. Коэффициенты, влияющие на интенсивность мониторинга.
Допустимыми значениями являются положительные числа. Допустимыми значениями являются положительные числа.
Уменьшение коэффициентов способно снизить нагрузку на Уменьшение коэффициентов способно снизить нагрузку на
@ -53,7 +58,7 @@ self_oom_score_adj = -1000
и тем самым снизить нагрузку на процессор. и тем самым снизить нагрузку на процессор.
В дефолтных настройках на данной интенсивности демон работает В дефолтных настройках на данной интенсивности демон работает
очень хорошо, успешно справляясь с резкими скачками потребления достаточно хорошо, успешно справляясь с резкими скачками потребления
памяти. памяти.
rate_mem = 6 rate_mem = 6
@ -62,6 +67,8 @@ rate_zram = 1
##################################################################### #####################################################################
IV. ПОРОГИ ДЛЯ ОТПРАВКИ СИГНАЛОВ
Задание уровней доступной памяти, ниже которых происходит Задание уровней доступной памяти, ниже которых происходит
отправка сигналов SIGTERM или SIGKILL. отправка сигналов SIGTERM или SIGKILL.
@ -75,11 +82,11 @@ rate_zram = 1
mem_min_sigterm = 0.5 G mem_min_sigterm = 0.5 G
swap_min_sigkill = 200 M swap_min_sigkill = 200 M
mem_min_sigterm = 4% mem_min_sigterm = 8%
mem_min_sigkill = 2% mem_min_sigkill = 4%
swap_min_sigterm = 4% swap_min_sigterm = 8%
swap_min_sigkill = 2% swap_min_sigkill = 4%
Задание общей доли zram в памяти, при превышении которой Задание общей доли zram в памяти, при превышении которой
происходит отправка соответствующих сигналов. происходит отправка соответствующих сигналов.
@ -89,21 +96,22 @@ swap_min_sigkill = 2%
отзывчивость системы. отзывчивость системы.
Может также задаваться в %, K, M, G Может также задаваться в %, K, M, G
zram_max_sigterm = 60 % zram_max_sigterm = 55 %
zram_max_sigkill = 65 % zram_max_sigkill = 60 %
##################################################################### #####################################################################
VI. ПРЕДОТВРАЩЕНИЕ ИЗБЫТОЧНЫХ УБИЙСТВ
Минимальное значение oom_score, которым должен обладать Минимальное значение oom_score, которым должен обладать
процесс для того, чтобы ему был отправлен сигнал. процесс для того, чтобы ему был отправлен сигнал.
Позволяет предотвратить убийство невиновных если что-то Позволяет предотвратить убийство невиновных если что-то
пойдет не так. пойдет не так.
Значение должно быть целым числом из диапазона [0; 1000] Значение должно быть целым числом из диапазона [0; 1000]
oom_score_min = 15 oom_score_min = 15
#####################################################################
Мнинмальная задержка после отправки соответствующих сигналов Мнинмальная задержка после отправки соответствующих сигналов
для предотвращения риска убийства сразу множества процессов. для предотвращения риска убийства сразу множества процессов.
Должно быть неотрицательным числом. Должно быть неотрицательным числом.
@ -113,6 +121,8 @@ min_delay_after_sigkill = 3
##################################################################### #####################################################################
VII. ЗАЩИТА ПРОЦЕССОВ CHROMIUM ОТ СМЕРТИ ПО ЧУЖОЙ ВИНЕ
Процессы браузера chromium обычно имеют oom_score_adj Процессы браузера chromium обычно имеют oom_score_adj
200 или 300. Это приводит к тому, что процессы хрома умирают 200 или 300. Это приводит к тому, что процессы хрома умирают
первыми вместо действительно тяжелых процессов. первыми вместо действительно тяжелых процессов.
@ -124,9 +134,9 @@ min_delay_after_sigkill = 3
False - не изменять oom_score_adj процессов перед поиском False - не изменять oom_score_adj процессов перед поиском
жертвы. Значения чувствительны к регистру! жертвы. Значения чувствительны к регистру!
Требует рут прав. Требует root прав.
decrease_oom_score_adj_enable = True decrease_oom_score_adj_enable = False
oom_score_adj_before = 50 oom_score_adj_before = 50
oom_score_adj_after = 10 oom_score_adj_after = 10