множество улучшений
This commit is contained in:
parent
2aa4f5c7b5
commit
27d22d41e4
26
README.md
26
README.md
@ -47,24 +47,21 @@ 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` для предотвращения убийства невиновных
|
||||||
|
- опциональность печати результатов проверки памяти
|
||||||
- `min_delay_after_sigkill` для предотвращения массовых убийств
|
- `min_delay_after_sigkill` для предотвращения массовых убийств
|
||||||
- наличие `man` страницы
|
- наличие `man` страницы
|
||||||
- наличие установщика для пользователей `systemd`
|
- наличие установщика для пользователей `systemd`
|
||||||
- протестировано на `Debian 9 x86_64`, `Debian 8 i386`, `Fedora 28 x86_64`
|
- протестировано на `Debian 9 x86_64`, `Debian 8 i386`, `Fedora 28 x86_64`
|
||||||
- пример вывода с отчетом об успешной отпраке сигнала:
|
- пример вывода с отчетом об успешной отпраке сигнала:
|
||||||
```
|
```
|
||||||
MemAvail: 0M 0.0%, SwapFree: 985M 8.4%, MemUsedZram: 625M 10.6%
|
MemAvail: 0M 0.0%, SwapFree: 706M 6.0%, MemUsedZram: 357M 6.1%
|
||||||
MemAvail: 0M 0.0%, SwapFree: 962M 8.2%, MemUsedZram: 626M 10.6%
|
MemAvail: 0M 0.0%, SwapFree: 411M 3.5%, MemUsedZram: 362M 6.2%
|
||||||
MemAvail: 9M 0.1%, SwapFree: 939M 8.0%, MemUsedZram: 626M 10.7%
|
+ MemAvail (0M, 0.0%) < mem_min_sigterm (235M, 4.0%)
|
||||||
MemAvailable 9M < 353M and SwapFree 939M < 940M
|
SwapFree (411M, 3.5%) < swap_min_sigterm (470M, 4.0%)
|
||||||
Try to send signal 15 to process python3, Pid 3392, oom_score 818
|
Try to send signal 15 to python3, Pid 3930, oom_score 903
|
||||||
Success
|
Success
|
||||||
MemAvail: 29M 0.5%, SwapFree: 2866M 24.4%, MemUsedZram: 582M 9.9%
|
MemAvail: 107M 1.8%, SwapFree: 3461M 29.5%, MemUsedZram: 311M 5.3%
|
||||||
MemAvail: 77M 1.3%, SwapFree: 5037M 42.9%, MemUsedZram: 532M 9.1%
|
MemAvail: 5159M 87.8%, SwapFree: 11311M 96.3%, MemUsedZram: 186M 3.2%
|
||||||
MemAvail: 168M 2.9%, SwapFree: 8956M 76.2%, MemUsedZram: 441M 7.5%
|
|
||||||
MemAvail: 5006M 85.2%, SwapFree: 10632M 90.5%, MemUsedZram: 356M 6.1%
|
|
||||||
MemAvail: 5000M 85.1%, SwapFree: 10633M 90.5%, MemUsedZram: 356M 6.1%
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Установка и удаление для пользователей systemd
|
### Установка и удаление для пользователей systemd
|
||||||
@ -91,8 +88,7 @@ sudo ./uninstall.sh
|
|||||||
```
|
```
|
||||||
/etc/nohang/nohang.conf
|
/etc/nohang/nohang.conf
|
||||||
```
|
```
|
||||||
К опциям прилагается описание. Отредактируйте значения параметров в соответствии с вашими предпочтениями.
|
К опциям прилагается описание. Отредактируйте значения параметров в соответствии с вашими предпочтениями и перезапустите сервис командой `sudo systemctl restart nohang`.
|
||||||
|
|
||||||
### Известные баги
|
### Известные баги
|
||||||
Известных нет, если найдете - пишите в [Issues](https://github.com/hakavlad/nohang/issues).
|
В рабочем алгоритме известных нет, если найдете - пишите в [Issues](https://github.com/hakavlad/nohang/issues).
|
||||||
|
|
||||||
|
497
nohang
497
nohang
@ -8,40 +8,297 @@ from operator import itemgetter
|
|||||||
from time import sleep
|
from time import sleep
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
# найден экспериментально, требует уточнения с разными ядрами и архитектурами
|
||||||
|
zram_disksize_factor = 0.0042
|
||||||
|
|
||||||
|
# где искать конфиг, если не указан через --config
|
||||||
|
default_configs = ('./nohang.conf', '/etc/nohang/nohang.conf')
|
||||||
|
|
||||||
|
err_mess = '\nSet up path to the valid config file with -c/--config CONFIG option!\nexit'
|
||||||
|
|
||||||
|
|
||||||
|
# парсинг аргументов командной строки
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-c',
|
'-c',
|
||||||
'--config',
|
'--config',
|
||||||
help='path to 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,
|
default=None,
|
||||||
type=str
|
type=str
|
||||||
)
|
)
|
||||||
|
|
||||||
arg_config = parser.parse_args().config
|
arg_config = parser.parse_args().config
|
||||||
|
|
||||||
|
|
||||||
# ветвление требует переработки и лучшей обработки исключений
|
|
||||||
if arg_config != None:
|
if arg_config is None:
|
||||||
if os.path.exists:
|
|
||||||
|
# print('конфиг не задан через опцию -с/--config, берем его из дефолтных путей')
|
||||||
|
del arg_config
|
||||||
|
|
||||||
|
config = None
|
||||||
|
for i in default_configs:
|
||||||
|
if os.path.exists(i):
|
||||||
|
config = i
|
||||||
|
break
|
||||||
|
if config is None:
|
||||||
|
print('По дефолтным путям конфиг не найден', err_mess)
|
||||||
|
exit()
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# print('через опцию задан путь к конфигу {}'.format(arg_config))
|
||||||
|
|
||||||
|
if os.path.exists(arg_config):
|
||||||
config = arg_config
|
config = arg_config
|
||||||
else:
|
else:
|
||||||
print('Указанный конфиг файл {} не существует!'.format(arg_config))
|
print('нет файла по указанному пути: {}'.format(arg_config), err_mess)
|
||||||
exit()
|
exit()
|
||||||
elif os.path.exists('./nohang.conf'):
|
|
||||||
config = './nohang.conf'
|
|
||||||
elif os.path.exists('/etc/nohang/nohang.conf'):
|
|
||||||
config = '/etc/nohang/nohang.conf'
|
|
||||||
else:
|
print('path to config:', config)
|
||||||
print('Пожалуйста, укажите путь к конфигу опцией -c или --config')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(config) as f:
|
||||||
|
config_dict = dict()
|
||||||
|
for line in f:
|
||||||
|
a = line.startswith('#')
|
||||||
|
b = line.startswith('\n')
|
||||||
|
c = line.startswith('\t')
|
||||||
|
d = line.startswith(' ')
|
||||||
|
if not a and not b and not c and not d:
|
||||||
|
a = line.split('=')
|
||||||
|
config_dict[a[0].strip()] = a[1].strip()
|
||||||
|
except PermissionError:
|
||||||
|
print('PermissionError', err_mess)
|
||||||
|
exit()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print('UnicodeDecodeError', err_mess)
|
||||||
|
exit()
|
||||||
|
except IsADirectoryError:
|
||||||
|
print('IsADirectoryError', err_mess)
|
||||||
|
exit()
|
||||||
|
except IndexError:
|
||||||
|
print('IndexError', err_mess)
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
# найден экспериментально, требует уточнения с разными ядрами и архитектурами
|
|
||||||
zram_disksize_factor = 0.0042
|
|
||||||
|
|
||||||
|
if 'print_mem_check_results' in config_dict:
|
||||||
|
print_mem_check_results = config_dict['print_mem_check_results']
|
||||||
|
if print_mem_check_results == 'True':
|
||||||
|
print_mem_check_results = True
|
||||||
|
elif print_mem_check_results == 'False':
|
||||||
|
print_mem_check_results = False
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
'invalid mlockall value {} (should be True or False), exit!'.format(
|
||||||
|
print_mem_check_results
|
||||||
|
)
|
||||||
|
)
|
||||||
|
exit()
|
||||||
|
print('print_mem_check_results: {}'.format(print_mem_check_results))
|
||||||
|
else:
|
||||||
|
print('print_mem_check_results not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'mlockall' in config_dict:
|
||||||
|
mlockall = config_dict['mlockall']
|
||||||
|
if mlockall == 'True':
|
||||||
|
mlockall = True
|
||||||
|
elif mlockall == 'False':
|
||||||
|
mlockall = False
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
'invalid mlockall value {} (should be True or False), exit!'.format(
|
||||||
|
mlockall
|
||||||
|
)
|
||||||
|
)
|
||||||
|
exit()
|
||||||
|
print('mlockall: {}'.format(mlockall))
|
||||||
|
else:
|
||||||
|
print('mlockall not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'self_nice' in config_dict:
|
||||||
|
self_nice = int(config_dict['self_nice'])
|
||||||
|
print('self_nice: {}'.format(self_nice))
|
||||||
|
else:
|
||||||
|
print('self_nice not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'self_oom_score_adj' in config_dict:
|
||||||
|
self_oom_score_adj = int(config_dict['self_oom_score_adj'])
|
||||||
|
print('self_oom_score_adj: {}'.format(self_oom_score_adj))
|
||||||
|
else:
|
||||||
|
print('self_oom_score_adj not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'rate_mem' in config_dict:
|
||||||
|
rate_mem = float(config_dict['rate_mem'])
|
||||||
|
if rate_mem <= 0:
|
||||||
|
print('rate_mem должен быть положительным')
|
||||||
|
exit()
|
||||||
|
print('rate_mem: {}'.format(rate_mem))
|
||||||
|
else:
|
||||||
|
print('rate_mem not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'rate_swap' in config_dict:
|
||||||
|
rate_swap = float(config_dict['rate_swap'])
|
||||||
|
if rate_swap <= 0:
|
||||||
|
print('rate_swap должен быть положительным')
|
||||||
|
exit()
|
||||||
|
print('rate_swap: {}'.format(rate_swap))
|
||||||
|
else:
|
||||||
|
print('rate_swap not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'rate_zram' in config_dict:
|
||||||
|
rate_zram = float(config_dict['rate_zram'])
|
||||||
|
if rate_zram <= 0:
|
||||||
|
print('rate_zram должен быть положительным')
|
||||||
|
exit()
|
||||||
|
print('rate_zram: {}'.format(rate_zram))
|
||||||
|
else:
|
||||||
|
print('rate_zram not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'mem_min_sigterm' in config_dict:
|
||||||
|
mem_min_sigterm = config_dict['mem_min_sigterm']
|
||||||
|
print('mem_min_sigterm: {}'.format(mem_min_sigterm))
|
||||||
|
else:
|
||||||
|
print('mem_min_sigterm not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'mem_min_sigkill' in config_dict:
|
||||||
|
mem_min_sigkill = config_dict['mem_min_sigkill']
|
||||||
|
print('mem_min_sigkill: {}'.format(mem_min_sigkill))
|
||||||
|
else:
|
||||||
|
print('mem_min_sigkill not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'swap_min_sigterm' in config_dict:
|
||||||
|
swap_min_sigterm = config_dict['swap_min_sigterm']
|
||||||
|
print('swap_min_sigterm: {}'.format(swap_min_sigterm))
|
||||||
|
else:
|
||||||
|
print('swap_min_sigterm not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'swap_min_sigkill' in config_dict:
|
||||||
|
swap_min_sigkill = config_dict['swap_min_sigkill']
|
||||||
|
print('swap_min_sigkill: {}'.format(swap_min_sigkill))
|
||||||
|
else:
|
||||||
|
print('swap_min_sigkill not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'zram_max_sigterm' in config_dict:
|
||||||
|
zram_max_sigterm = config_dict['zram_max_sigterm']
|
||||||
|
print('zram_max_sigterm: {}'.format(zram_max_sigterm))
|
||||||
|
else:
|
||||||
|
print('zram_max_sigterm not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'zram_max_sigkill' in config_dict:
|
||||||
|
zram_max_sigkill = config_dict['zram_max_sigkill']
|
||||||
|
print('zram_max_sigkill: {}'.format(zram_max_sigkill))
|
||||||
|
else:
|
||||||
|
print('zram_max_sigkill not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'min_delay_after_sigterm' in config_dict:
|
||||||
|
min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm'])
|
||||||
|
print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm))
|
||||||
|
else:
|
||||||
|
print('min_delay_after_sigterm not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'min_delay_after_sigkill' in config_dict:
|
||||||
|
min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill'])
|
||||||
|
print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill))
|
||||||
|
else:
|
||||||
|
print('min_delay_after_sigkill not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'oom_score_min' in config_dict:
|
||||||
|
oom_score_min = int(config_dict['oom_score_min'])
|
||||||
|
print('oom_score_min: {}'.format(oom_score_min))
|
||||||
|
else:
|
||||||
|
print('oom_score_min not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'decrease_oom_score_adj_enable' in config_dict:
|
||||||
|
decrease_oom_score_adj_enable = config_dict['decrease_oom_score_adj_enable']
|
||||||
|
if decrease_oom_score_adj_enable == 'True':
|
||||||
|
decrease_oom_score_adj_enable = True
|
||||||
|
elif decrease_oom_score_adj_enable == 'False':
|
||||||
|
decrease_oom_score_adj_enable = False
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
'invalid mlockall value {} (should be True or False), exit!'.format(
|
||||||
|
decrease_oom_score_adj_enable
|
||||||
|
)
|
||||||
|
)
|
||||||
|
exit()
|
||||||
|
print('decrease_oom_score_adj_enable: {}'.format(decrease_oom_score_adj_enable))
|
||||||
|
else:
|
||||||
|
print('decrease_oom_score_adj_enable not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'oom_score_adj_before' in config_dict:
|
||||||
|
oom_score_adj_before = int(config_dict['oom_score_adj_before'])
|
||||||
|
print('oom_score_adj_before: {}'.format(oom_score_adj_before))
|
||||||
|
else:
|
||||||
|
print('oom_score_adj_before not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
if 'oom_score_adj_after' in config_dict:
|
||||||
|
oom_score_adj_after = config_dict['oom_score_adj_after']
|
||||||
|
print('oom_score_adj_after: {}'.format(oom_score_adj_after))
|
||||||
|
else:
|
||||||
|
print('oom_score_adj_after not in config, exit!')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
@ -72,30 +329,14 @@ def rline1(path):
|
|||||||
def write(path, string):
|
def write(path, string):
|
||||||
with open(path, 'w') as f:
|
with open(path, 'w') as f:
|
||||||
f.write(string)
|
f.write(string)
|
||||||
|
# дикриз не от рута
|
||||||
|
|
||||||
|
|
||||||
# возвращает словарь с параметрами из конфига
|
def percent(n):
|
||||||
def config_parser(config):
|
return round(n * 100, 1)
|
||||||
if os.path.exists(config):
|
|
||||||
try:
|
|
||||||
with open(config) as f:
|
|
||||||
name_value_dict = dict()
|
|
||||||
for line in f:
|
|
||||||
a = line.startswith('#')
|
|
||||||
b = line.startswith('\n')
|
|
||||||
c = line.startswith('\t')
|
|
||||||
d = line.startswith(' ')
|
|
||||||
if not a and not b and not c and not d:
|
|
||||||
a = line.split('=')
|
|
||||||
name_value_dict[a[0].strip()] = a[1].strip()
|
|
||||||
return name_value_dict
|
|
||||||
except PermissionError:
|
|
||||||
return 2
|
|
||||||
else:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
def to_percent(num):
|
def just_percent(num):
|
||||||
return str(round(num * 100, 1)).rjust(5, ' ')
|
return str(round(num * 100, 1)).rjust(5, ' ')
|
||||||
|
|
||||||
|
|
||||||
@ -163,22 +404,22 @@ def find_victim_and_send_signal(signal):
|
|||||||
name = pid_to_name(pid)
|
name = pid_to_name(pid)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
'Try to send signal {} to process {}, Pid {}, oom_score {}'.format(
|
' Try to send signal {} to {}, Pid {}, oom_score {}'.format(
|
||||||
signal, name, pid, oom_score
|
signal, name, pid, oom_score
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.kill(int(pid), signal)
|
os.kill(int(pid), signal)
|
||||||
print('Success')
|
print(' Success')
|
||||||
except ProcessLookupError:
|
except ProcessLookupError:
|
||||||
print('No such process')
|
print(' No such process')
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
print('Operation not permitted')
|
print(' Operation not permitted')
|
||||||
|
|
||||||
else:
|
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))
|
||||||
|
|
||||||
|
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
@ -206,105 +447,21 @@ mem_total = int(mem_list[0].split(':')[1].split(' ')[-2])
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
config_dict = config_parser(config)
|
|
||||||
|
|
||||||
if config_dict is 1:
|
|
||||||
print('config {} does not exists'.format(config))
|
|
||||||
|
|
||||||
elif config_dict is 2:
|
|
||||||
print('cannot read config {}, permission error'.format(config))
|
|
||||||
|
|
||||||
else:
|
|
||||||
print('config: {}\n'.format(config))
|
|
||||||
|
|
||||||
if 'mlockall' in config_dict:
|
|
||||||
mlockall = config_dict['mlockall']
|
|
||||||
if mlockall == 'True':
|
|
||||||
mlockall = True
|
|
||||||
print('mlockall: {}'.format(mlockall))
|
|
||||||
|
|
||||||
if 'self_nice' in config_dict:
|
|
||||||
self_nice = int(config_dict['self_nice'])
|
|
||||||
print('self_nice: {}'.format(self_nice))
|
|
||||||
|
|
||||||
if 'self_oom_score_adj' in config_dict:
|
|
||||||
self_oom_score_adj = int(config_dict['self_oom_score_adj'])
|
|
||||||
print('self_oom_score_adj: {}'.format(self_oom_score_adj))
|
|
||||||
|
|
||||||
if 'rate_mem' in config_dict:
|
|
||||||
rate_mem = float(config_dict['rate_mem'])
|
|
||||||
print('rate_mem: {}'.format(rate_mem))
|
|
||||||
|
|
||||||
if 'rate_swap' in config_dict:
|
|
||||||
rate_swap = float(config_dict['rate_swap'])
|
|
||||||
print('rate_swap: {}'.format(rate_swap))
|
|
||||||
|
|
||||||
if 'rate_zram' in config_dict:
|
|
||||||
rate_zram = float(config_dict['rate_zram'])
|
|
||||||
print('rate_zram: {}'.format(rate_zram))
|
|
||||||
|
|
||||||
if 'mem_min_sigterm' in config_dict:
|
|
||||||
mem_min_sigterm = config_dict['mem_min_sigterm']
|
|
||||||
print('mem_min_sigterm: {}'.format(mem_min_sigterm))
|
|
||||||
|
|
||||||
if 'mem_min_sigkill' in config_dict:
|
|
||||||
mem_min_sigkill = config_dict['mem_min_sigkill']
|
|
||||||
print('mem_min_sigkill: {}'.format(mem_min_sigkill))
|
|
||||||
|
|
||||||
if 'swap_min_sigterm' in config_dict:
|
|
||||||
swap_min_sigterm = config_dict['swap_min_sigterm']
|
|
||||||
print('swap_min_sigterm: {}'.format(swap_min_sigterm))
|
|
||||||
|
|
||||||
if 'swap_min_sigkill' in config_dict:
|
|
||||||
swap_min_sigkill = config_dict['swap_min_sigkill']
|
|
||||||
print('swap_min_sigkill: {}'.format(swap_min_sigkill))
|
|
||||||
|
|
||||||
if 'zram_max_sigterm' in config_dict:
|
|
||||||
zram_max_sigterm = config_dict['zram_max_sigterm']
|
|
||||||
print('zram_max_sigterm: {}'.format(zram_max_sigterm))
|
|
||||||
|
|
||||||
if 'zram_max_sigkill' in config_dict:
|
|
||||||
zram_max_sigkill = config_dict['zram_max_sigkill']
|
|
||||||
print('zram_max_sigkill: {}'.format(zram_max_sigkill))
|
|
||||||
|
|
||||||
if 'min_delay_after_sigterm' in config_dict:
|
|
||||||
min_delay_after_sigterm = float(config_dict['min_delay_after_sigterm'])
|
|
||||||
print('min_delay_after_sigterm: {}'.format(min_delay_after_sigterm))
|
|
||||||
|
|
||||||
if 'min_delay_after_sigkill' in config_dict:
|
|
||||||
min_delay_after_sigkill = float(config_dict['min_delay_after_sigkill'])
|
|
||||||
print('min_delay_after_sigkill: {}'.format(min_delay_after_sigkill))
|
|
||||||
|
|
||||||
if 'oom_score_min' in config_dict:
|
|
||||||
oom_score_min = int(config_dict['oom_score_min'])
|
|
||||||
print('oom_score_min: {}'.format(oom_score_min))
|
|
||||||
|
|
||||||
if 'decrease_oom_score_adj_enable' in config_dict:
|
|
||||||
decrease_oom_score_adj_enable = config_dict['decrease_oom_score_adj_enable']
|
|
||||||
if decrease_oom_score_adj_enable == 'True':
|
|
||||||
decrease_oom_score_adj_enable = True
|
|
||||||
print('decrease_oom_score_adj_enable: {}'.format(decrease_oom_score_adj_enable))
|
|
||||||
|
|
||||||
if 'oom_score_adj_before' in config_dict:
|
|
||||||
oom_score_adj_before = int(config_dict['oom_score_adj_before'])
|
|
||||||
print('oom_score_adj_before: {}'.format(oom_score_adj_before))
|
|
||||||
|
|
||||||
if 'oom_score_adj_after' in config_dict:
|
|
||||||
oom_score_adj_after = config_dict['oom_score_adj_after']
|
|
||||||
print('oom_score_adj_after: {}'.format(oom_score_adj_after))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def sig_level_to_kb(string):
|
def sig_level_to_kb(string):
|
||||||
if string.endswith('%'):
|
if string.endswith('%'):
|
||||||
return float(string[:-1].strip()) / 100 * mem_total
|
return float(string[:-1].strip()) / 100 * mem_total
|
||||||
if string.endswith('K'):
|
elif string.endswith('K'):
|
||||||
return float(string[:-1].strip())
|
return float(string[:-1].strip())
|
||||||
if string.endswith('M'):
|
elif string.endswith('M'):
|
||||||
return float(string[:-1].strip()) * 1024
|
return float(string[:-1].strip()) * 1024
|
||||||
if string.endswith('G'):
|
elif string.endswith('G'):
|
||||||
return float(string[:-1].strip()) * 1048576
|
return float(string[:-1].strip()) * 1048576
|
||||||
|
else:
|
||||||
|
print('Конфиг инвалид, где-то неверно указаны единицы измерения')
|
||||||
|
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)
|
||||||
@ -313,7 +470,6 @@ zram_max_sigkill_kb = sig_level_to_kb(zram_max_sigkill)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# возвращает число килобайт при задании в конфиге абсолютного значения,
|
# возвращает число килобайт при задании в конфиге абсолютного значения,
|
||||||
# или кортеж с числом процентов
|
# или кортеж с числом процентов
|
||||||
def sig_level_to_kb_swap(string):
|
def sig_level_to_kb_swap(string):
|
||||||
@ -321,12 +477,16 @@ def sig_level_to_kb_swap(string):
|
|||||||
if string.endswith('%'):
|
if string.endswith('%'):
|
||||||
return float(string[:-1].strip()), True
|
return float(string[:-1].strip()), True
|
||||||
|
|
||||||
if string.endswith('K'):
|
elif string.endswith('K'):
|
||||||
return float(string[:-1].strip())
|
return float(string[:-1].strip())
|
||||||
if string.endswith('M'):
|
elif string.endswith('M'):
|
||||||
return float(string[:-1].strip()) * 1024
|
return float(string[:-1].strip()) * 1024
|
||||||
if string.endswith('G'):
|
elif string.endswith('G'):
|
||||||
return float(string[:-1].strip()) * 1048576
|
return float(string[:-1].strip()) * 1048576
|
||||||
|
else:
|
||||||
|
print('Конфиг инвалид, где-то неверно указаны единицы измерения')
|
||||||
|
exit()
|
||||||
|
|
||||||
|
|
||||||
# получаем число килобайт или кортеж с процентами
|
# получаем число килобайт или кортеж с процентами
|
||||||
swap_min_sigterm_swap = sig_level_to_kb_swap(swap_min_sigterm)
|
swap_min_sigterm_swap = sig_level_to_kb_swap(swap_min_sigterm)
|
||||||
@ -400,7 +560,10 @@ def kib_to_mib(num):
|
|||||||
|
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
|
print('Start monitoring...')
|
||||||
|
|
||||||
# рабочий цикл
|
# рабочий цикл
|
||||||
while True:
|
while True:
|
||||||
@ -457,27 +620,44 @@ while True:
|
|||||||
t = t_mem_zram
|
t = t_mem_zram
|
||||||
|
|
||||||
|
|
||||||
# печать состояния памяти
|
if print_mem_check_results:
|
||||||
print(
|
print(
|
||||||
'MemAvail: {}M {}%, SwapFree: {}M {}%, MemUsedZram: {}M {}%'.format(
|
'MemAvail: {}M {}%, SwapFree: {}M {}%, MemUsedZram: {}M {}%'.format(
|
||||||
human(mem_available),
|
human(mem_available),
|
||||||
to_percent(mem_available / mem_total),
|
just_percent(mem_available / mem_total),
|
||||||
human(swap_free),
|
human(swap_free),
|
||||||
to_percent(swap_free / (swap_total + 0.0001)),
|
just_percent(swap_free / (swap_total + 0.0001)),
|
||||||
human(mem_used_zram),
|
human(mem_used_zram),
|
||||||
to_percent(mem_used_zram / mem_total)
|
just_percent(mem_used_zram / mem_total)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
if swap_total > swap_min_sigkill_kb:
|
||||||
|
swap_sigkill_pc = percent(swap_min_sigkill_kb / (swap_total + 1))
|
||||||
|
else:
|
||||||
|
swap_sigkill_pc = '-'
|
||||||
|
|
||||||
|
if swap_total > swap_min_sigterm_kb:
|
||||||
|
swap_sigterm_pc = percent(swap_min_sigterm_kb / (swap_total + 1))
|
||||||
|
else:
|
||||||
|
swap_sigterm_pc = '-'
|
||||||
|
|
||||||
|
|
||||||
# MEM SWAP KILL
|
# MEM SWAP KILL
|
||||||
if mem_available <= mem_min_sigkill_kb and swap_free <= swap_min_sigkill_kb:
|
if mem_available <= mem_min_sigkill_kb and swap_free <= swap_min_sigkill_kb:
|
||||||
print(
|
print(
|
||||||
'MemAvailable {}M < {}M and SwapFree {}M < {}M'.format(
|
'+ MemAvail ({}M, {}%) < mem_min_sigkill ({}M, {}%)\n SwapFree' \
|
||||||
|
' ({}M, {}%) < swap_min_sigkill ({}M, {}%)'.format(
|
||||||
kib_to_mib(mem_available),
|
kib_to_mib(mem_available),
|
||||||
|
percent(mem_available / mem_total),
|
||||||
kib_to_mib(mem_min_sigkill_kb),
|
kib_to_mib(mem_min_sigkill_kb),
|
||||||
|
percent(mem_min_sigkill_kb / mem_total),
|
||||||
kib_to_mib(swap_free),
|
kib_to_mib(swap_free),
|
||||||
kib_to_mib(swap_min_sigkill_kb)
|
percent(swap_free / (swap_total + 0.0001)),
|
||||||
|
kib_to_mib(swap_min_sigkill_kb),
|
||||||
|
swap_sigkill_pc
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
find_victim_and_send_signal(9)
|
find_victim_and_send_signal(9)
|
||||||
@ -487,9 +667,11 @@ while True:
|
|||||||
# MEM ZRAM KILL
|
# MEM ZRAM KILL
|
||||||
if mem_used_zram >= zram_max_sigkill_kb:
|
if mem_used_zram >= zram_max_sigkill_kb:
|
||||||
print(
|
print(
|
||||||
'MemUsedZram {}M > {}M'.format(
|
'+ MemUsedZram ({}M, {}%) > zram_max_sigkill ({}M, {}%)'.format(
|
||||||
kib_to_mib(mem_used_zram),
|
kib_to_mib(mem_used_zram),
|
||||||
kib_to_mib(zram_max_sigkill_kb)
|
percent(mem_used_zram / mem_total),
|
||||||
|
kib_to_mib(zram_max_sigkill_kb),
|
||||||
|
percent(zram_max_sigkill_kb / mem_total)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
find_victim_and_send_signal(9)
|
find_victim_and_send_signal(9)
|
||||||
@ -499,11 +681,16 @@ while True:
|
|||||||
# MEM SWAP TERM
|
# MEM SWAP TERM
|
||||||
if mem_available <= mem_min_sigterm_kb and swap_free <= swap_min_sigterm_kb:
|
if mem_available <= mem_min_sigterm_kb and swap_free <= swap_min_sigterm_kb:
|
||||||
print(
|
print(
|
||||||
'MemAvailable {}M < {}M and SwapFree {}M < {}M'.format(
|
'+ MemAvail ({}M, {}%) < mem_min_sigterm ({}M, {}%)\n SwapFree' \
|
||||||
|
' ({}M, {}%) < swap_min_sigterm ({}M, {}%)'.format(
|
||||||
kib_to_mib(mem_available),
|
kib_to_mib(mem_available),
|
||||||
|
percent(mem_available / mem_total),
|
||||||
kib_to_mib(mem_min_sigterm_kb),
|
kib_to_mib(mem_min_sigterm_kb),
|
||||||
|
percent(mem_min_sigterm_kb / mem_total),
|
||||||
kib_to_mib(swap_free),
|
kib_to_mib(swap_free),
|
||||||
kib_to_mib(swap_min_sigterm_kb)
|
percent(swap_free / (swap_total + 0.0001)),
|
||||||
|
kib_to_mib(swap_min_sigterm_kb),
|
||||||
|
swap_sigterm_pc
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
find_victim_and_send_signal(15)
|
find_victim_and_send_signal(15)
|
||||||
@ -512,9 +699,11 @@ while True:
|
|||||||
# MEM ZRAM TERM
|
# MEM ZRAM TERM
|
||||||
if mem_used_zram >= zram_max_sigterm_kb:
|
if mem_used_zram >= zram_max_sigterm_kb:
|
||||||
print(
|
print(
|
||||||
'MemUsedZram {}M > {}M'.format(
|
'+ MemUsedZram ({}M, {}%) > zram_max_sigterm ({}M, {}%)'.format(
|
||||||
kib_to_mib(mem_used_zram),
|
kib_to_mib(mem_used_zram),
|
||||||
kib_to_mib(zram_max_sigterm_kb)
|
percent(mem_used_zram / mem_total),
|
||||||
|
kib_to_mib(zram_max_sigterm_kb),
|
||||||
|
percent(zram_max_sigterm_kb / mem_total)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
find_victim_and_send_signal(15)
|
find_victim_and_send_signal(15)
|
||||||
|
2
nohang.1
2
nohang.1
@ -13,7 +13,7 @@ Nohang - аналог earlyoom с поддержкой zram и SIGTERM. При
|
|||||||
.TP
|
.TP
|
||||||
.BI \-c " CONFIG",
|
.BI \-c " CONFIG",
|
||||||
.BI \-\-config " CONFIG"
|
.BI \-\-config " CONFIG"
|
||||||
path to config file, default values:
|
path to the config file, default values:
|
||||||
.I ./nohang.conf,
|
.I ./nohang.conf,
|
||||||
.I /etc/nohang/nohang.conf
|
.I /etc/nohang/nohang.conf
|
||||||
.TP
|
.TP
|
||||||
|
63
nohang.conf
63
nohang.conf
@ -7,12 +7,18 @@
|
|||||||
и табуляций. Инлайновые комментарии запрещены. Пробелы допустиы
|
и табуляций. Инлайновые комментарии запрещены. Пробелы допустиы
|
||||||
внутри строк в любом количестве.
|
внутри строк в любом количестве.
|
||||||
|
|
||||||
В конце конфига перечислены значения по умолчанию.
|
#####################################################################
|
||||||
|
|
||||||
|
Печатать ли результаты измерения доступной памяти.
|
||||||
|
Допустимые значения: True и False
|
||||||
|
|
||||||
|
print_mem_check_results = True
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
True - заблокировать процесс в памяти для запрета его своппинга.
|
True - заблокировать процесс в памяти для запрета его своппинга.
|
||||||
False - не блокировать. Значения чувствительны к регистру!
|
False - не блокировать. Значения чувствительны к регистру!
|
||||||
|
Требует рут прав.
|
||||||
|
|
||||||
mlockall = True
|
mlockall = True
|
||||||
|
|
||||||
@ -20,6 +26,7 @@ mlockall = True
|
|||||||
|
|
||||||
Повысить приоритет процесса, установив niceness -20
|
Повысить приоритет процесса, установив niceness -20
|
||||||
Допустимые значения - целые числа из диапазона [-20; 19]
|
Допустимые значения - целые числа из диапазона [-20; 19]
|
||||||
|
Требует рут прав.
|
||||||
|
|
||||||
self_nice = -20
|
self_nice = -20
|
||||||
|
|
||||||
@ -28,6 +35,7 @@ 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
|
||||||
|
|
||||||
@ -38,8 +46,8 @@ self_oom_score_adj = -1000
|
|||||||
Уменьшение коэффициентов способно снизить нагрузку на
|
Уменьшение коэффициентов способно снизить нагрузку на
|
||||||
прцессор и увеличить периоды между проверками памяти.
|
прцессор и увеличить периоды между проверками памяти.
|
||||||
|
|
||||||
Почему три коэффициента, а не один? - Потому что
|
Почему три коэффициента, а не один? - Потому что скорость
|
||||||
скорость наполнения свопа обычно ниже скорости наполнения RAM.
|
наполнения свопа обычно ниже скорости наполнения RAM.
|
||||||
Можно для свопа задать более низкую интенсивность
|
Можно для свопа задать более низкую интенсивность
|
||||||
мониторинга без ущерба для предотвращения нехватки памяти
|
мониторинга без ущерба для предотвращения нехватки памяти
|
||||||
и тем самым снизить нагрузку на процессор.
|
и тем самым снизить нагрузку на процессор.
|
||||||
@ -49,7 +57,7 @@ self_oom_score_adj = -1000
|
|||||||
памяти.
|
памяти.
|
||||||
|
|
||||||
rate_mem = 6
|
rate_mem = 6
|
||||||
rate_swap = 2
|
rate_swap = 0.2
|
||||||
rate_zram = 1
|
rate_zram = 1
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
@ -67,10 +75,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 = 6 %
|
mem_min_sigterm = 4%
|
||||||
mem_min_sigkill = 3 %
|
mem_min_sigkill = 2%
|
||||||
swap_min_sigterm = 8 %
|
|
||||||
swap_min_sigkill = 4 %
|
swap_min_sigterm = 4%
|
||||||
|
swap_min_sigkill = 2%
|
||||||
|
|
||||||
Задание общей доли zram в памяти, при превышении которой
|
Задание общей доли zram в памяти, при превышении которой
|
||||||
происходит отправка соответствующих сигналов.
|
происходит отправка соответствующих сигналов.
|
||||||
@ -91,7 +100,7 @@ zram_max_sigkill = 65 %
|
|||||||
пойдет не так.
|
пойдет не так.
|
||||||
Значение должно быть целым числом из диапазона [0; 1000]
|
Значение должно быть целым числом из диапазона [0; 1000]
|
||||||
|
|
||||||
oom_score_min = 10
|
oom_score_min = 15
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
@ -115,40 +124,10 @@ min_delay_after_sigkill = 3
|
|||||||
False - не изменять oom_score_adj процессов перед поиском
|
False - не изменять oom_score_adj процессов перед поиском
|
||||||
жертвы. Значения чувствительны к регистру!
|
жертвы. Значения чувствительны к регистру!
|
||||||
|
|
||||||
decrease_oom_score_adj_enable = False
|
Требует рут прав.
|
||||||
|
|
||||||
|
decrease_oom_score_adj_enable = True
|
||||||
|
|
||||||
oom_score_adj_before = 50
|
oom_score_adj_before = 50
|
||||||
oom_score_adj_after = 10
|
oom_score_adj_after = 10
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
#####################################################################
|
|
||||||
#####################################################################
|
|
||||||
#####################################################################
|
|
||||||
#####################################################################
|
|
||||||
|
|
||||||
Значения по умолчанию
|
|
||||||
|
|
||||||
mlockall = True
|
|
||||||
self_nice = -20
|
|
||||||
self_oom_score_adj = -1000
|
|
||||||
|
|
||||||
rate_mem = 6
|
|
||||||
rate_swap = 2
|
|
||||||
rate_zram = 1
|
|
||||||
|
|
||||||
mem_min_sigterm = 6 %
|
|
||||||
mem_min_sigkill = 3 %
|
|
||||||
swap_min_sigterm = 8 %
|
|
||||||
swap_min_sigkill = 4 %
|
|
||||||
zram_max_sigterm = 60 %
|
|
||||||
zram_max_sigkill = 65 %
|
|
||||||
|
|
||||||
oom_score_min = 10
|
|
||||||
|
|
||||||
min_delay_after_sigterm = 0.1
|
|
||||||
min_delay_after_sigkill = 3
|
|
||||||
|
|
||||||
decrease_oom_score_adj_enable = False
|
|
||||||
oom_score_adj_before = 50
|
|
||||||
oom_score_adj_after = 10
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user