улучшение валидации параметров конфига, улучшение вывода результатов проверки доступной памяти

This commit is contained in:
Alexey Avramov 2018-06-13 15:00:34 +09:00
parent a82159ee68
commit b0805dc450
4 changed files with 314 additions and 156 deletions

View File

@ -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

439
nohang
View File

@ -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()

View File

@ -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. Это приводит к тому, что процессы хрома умирают
первыми вместо действительно тяжелых процессов.

View File

@ -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