add support white, black, avoid, prefer lists
This commit is contained in:
parent
6bccc3402f
commit
8825021f6b
8
.gitignore
vendored
8
.gitignore
vendored
@ -107,11 +107,3 @@ venv.bak/
|
||||
# Kate
|
||||
.kate-swp
|
||||
|
||||
# man
|
||||
*.1.gz
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -57,6 +57,7 @@ https://2ch.hk/s/res/2310304.html#2311483, https://archive.li/idixk
|
||||
- verbosity: опциональность печати параметров конфига при старте программы, опциональность печати результатов проверки памяти и времени между проверками памяти
|
||||
- возможность предотвращения избыточного убийства процессов с помощью задания миниального `oom_score` для убиваемых процессов и установка минимальной задержки просле отправки сигналов (параметры конфига `min_delay_after_sigkill` и `min_delay_after_sigterm`)
|
||||
- возможность показа десктопных уведомлений c помощью `notify-send`, с показом сигнала (`SIGTERM` или `SIGKILL`), который отправлен процессу, а также `Pid`, `oom_score`, `VmRSS`, `VmSwap`, которыми обладал процесс перед получением сигнала.
|
||||
- поддержка white, black, prefer и avoid списков с использованием Perl-compatible regular expressions
|
||||
- наличие `man` страницы
|
||||
- наличие установщика для пользователей `systemd`
|
||||
- протестировано на `Debian 9 x86_64`, `Debian 8 i386`, `Fedora 28 x86_64`
|
||||
|
406
nohang
406
nohang
@ -10,6 +10,7 @@ import os
|
||||
from operator import itemgetter
|
||||
from time import sleep
|
||||
from argparse import ArgumentParser
|
||||
from re import fullmatch
|
||||
|
||||
##########################################################################
|
||||
|
||||
@ -147,35 +148,58 @@ def pid_to_name(pid):
|
||||
|
||||
|
||||
def send_notify(signal, name, pid, oom_score, vm_rss, vm_swap):
|
||||
|
||||
# текст отправляемого уведомления
|
||||
info = '"<u>Nohang</u> sent <u>{}</u> \nto the process <b>{}</b> \n<i>P' \
|
||||
'id:</i> <b>{}</b> \n<i>oom_score:</i> <b>{}</b> \n<i>VmRSS:</i> <b' \
|
||||
'id:</i> <b>{}</b> \n<i>Badness:</i> <b>{}</b> \n<i>VmRSS:</i> <b' \
|
||||
'>{} MiB</b> \n<i>VmSwap:</i> <b>{} MiB</b>" &'.format(
|
||||
sig_dict[signal], name, pid, oom_score, vm_rss, vm_swap)
|
||||
|
||||
if root:
|
||||
|
||||
# отправляем уведомление всем залогиненным пользователям
|
||||
for uid in os.listdir('/run/user'):
|
||||
|
||||
root_notify_command = 'sudo -u {} DISPLAY={} notify-send {} "Pr' \
|
||||
'eventing OOM" '.format(
|
||||
users_dict[uid], display, notify_options)
|
||||
|
||||
os.system(root_notify_command + info)
|
||||
|
||||
else:
|
||||
|
||||
# отправляем уведомление пользователю, который запустил nohang
|
||||
user_notify_command = 'notify-send {} "Preventing OOM" '.format(
|
||||
notify_options)
|
||||
|
||||
os.system(user_notify_command + info)
|
||||
|
||||
|
||||
|
||||
def send_notify_black(signal, name, pid):
|
||||
# текст отправляемого уведомления
|
||||
info = '"<u>Nohang</u> sent <u>{}</u>\nto blacklisted proce' \
|
||||
'ss <b>{}</b>, <i>Pid</i> <b>{}</b>" &'.format(
|
||||
sig_dict[signal], name, pid)
|
||||
if root:
|
||||
# отправляем уведомление всем залогиненным пользователям
|
||||
for uid in os.listdir('/run/user'):
|
||||
root_notify_command = 'sudo -u {} DISPLAY={} notify-send {} "Pr' \
|
||||
'eventing OOM" '.format(
|
||||
users_dict[uid], display, notify_options)
|
||||
os.system(root_notify_command + info)
|
||||
else:
|
||||
# отправляем уведомление пользователю, который запустил nohang
|
||||
user_notify_command = 'notify-send {} "Preventing OOM" '.format(
|
||||
notify_options)
|
||||
os.system(user_notify_command + info)
|
||||
|
||||
|
||||
def sleep_after_send_signal(signal):
|
||||
if signal is 9:
|
||||
if print_sleep_periods:
|
||||
print(' sleep', min_delay_after_sigkill)
|
||||
sleep(min_delay_after_sigterm)
|
||||
else:
|
||||
if print_sleep_periods:
|
||||
print(' sleep', min_delay_after_sigterm)
|
||||
sleep(min_delay_after_sigterm)
|
||||
|
||||
|
||||
# принимает int (9 или 15)
|
||||
def find_victim_and_send_signal(signal):
|
||||
def find_victim_and_send_signal_without_regexp_lists(signal):
|
||||
|
||||
# выставляем потолок для oom_score_adj всех процессов
|
||||
if decrease_oom_score_adj and root:
|
||||
@ -247,18 +271,160 @@ def find_victim_and_send_signal(signal):
|
||||
|
||||
else:
|
||||
print(' oom_score {} < oom_score_min {}'.format(
|
||||
oom_score, oom_score_min)
|
||||
)
|
||||
oom_score, oom_score_min))
|
||||
|
||||
sleep_after_send_signal(signal)
|
||||
|
||||
|
||||
# принимает int (9 или 15)
|
||||
def find_victim_and_send_signal_with_regexp_lists(signal):
|
||||
|
||||
# выставляем потолок для oom_score_adj всех процессов
|
||||
if decrease_oom_score_adj and root:
|
||||
func_decrease_oom_score_adj(oom_score_adj_max)
|
||||
|
||||
# получаем список процессов ((pid, badness))
|
||||
oom_list = []
|
||||
|
||||
# pid list
|
||||
oom_black_list = []
|
||||
|
||||
for pid in os.listdir('/proc'):
|
||||
if pid.isdigit() is not True:
|
||||
continue
|
||||
try:
|
||||
|
||||
# пошла итерация для каждого существующего процесса
|
||||
|
||||
oom_score = int(rline1('/proc/' + pid + '/oom_score'))
|
||||
|
||||
name = pid_to_name(pid)
|
||||
|
||||
# если имя в списке,то пропускаем!
|
||||
res = fullmatch(white_list, name)
|
||||
if res is not None:
|
||||
#print(' {} (Pid: {}) is in white list'.format(name, pid)),
|
||||
continue
|
||||
|
||||
# если имя в черном списке - добавляем Pid в список для убийства
|
||||
res = fullmatch(black_list, name)
|
||||
if res is not None:
|
||||
oom_black_list.append(pid)
|
||||
#print(' {} (Pid: {}) is in black list'.format(name, pid)),
|
||||
|
||||
res = fullmatch(avoid_list, name)
|
||||
if res is not None:
|
||||
# тут уже получаем badness
|
||||
oom_score = int(oom_score / avoid_factor)
|
||||
#print(' {} (Pid: {}) is in avoid list'.format(name, pid)),
|
||||
|
||||
res = fullmatch(prefer_list, name)
|
||||
if res is not None:
|
||||
oom_score = int((oom_score + 1) * prefer_factor)
|
||||
#print(' {} (Pid: {}) is in prefer list'.format(name, pid)),
|
||||
|
||||
|
||||
except FileNotFoundError:
|
||||
oom_score = 0
|
||||
except ProcessLookupError:
|
||||
oom_score = 0
|
||||
oom_list.append((pid, oom_score))
|
||||
|
||||
|
||||
if oom_black_list != []:
|
||||
|
||||
print(' Black list is not empty')
|
||||
|
||||
for pid in oom_black_list:
|
||||
|
||||
name = pid_to_name(pid)
|
||||
print(' Try to send the {} signal to blacklisted process {}, Pid {}'.format(
|
||||
sig_dict[signal], name, pid))
|
||||
|
||||
try:
|
||||
os.kill(int(pid), signal)
|
||||
print(' Success')
|
||||
|
||||
if desktop_notifications:
|
||||
send_notify_black(signal, name, pid)
|
||||
|
||||
except FileNotFoundError:
|
||||
print(' No such process')
|
||||
except ProcessLookupError:
|
||||
print(' No such process')
|
||||
except PermissionError:
|
||||
print(' Operation not permitted')
|
||||
|
||||
# после отправки сигнала процессам из черного списка поспать и выйти из функции
|
||||
#sleep_after_send_signal(signal)
|
||||
#sleep(0.1)
|
||||
return 0
|
||||
|
||||
|
||||
# получаем отсортированный по oom_score (по badness!) список пар (pid, oom_score)
|
||||
pid_tuple_list = sorted(oom_list, key=itemgetter(1), reverse=True)[0]
|
||||
|
||||
# получаем максимальный oom_score
|
||||
oom_score = pid_tuple_list[1]
|
||||
|
||||
# посылаем сигнал
|
||||
if oom_score >= oom_score_min:
|
||||
|
||||
pid = pid_tuple_list[0]
|
||||
|
||||
name = pid_to_name(pid)
|
||||
|
||||
# находим VmRSS и VmSwap процесса, которому попытаемся послать сигнал
|
||||
try:
|
||||
with open('/proc/' + pid + '/status') as f:
|
||||
for n, line in enumerate(f):
|
||||
if n is vm_rss_index:
|
||||
vm_rss = kib_to_mib(int(
|
||||
line.split('\t')[1][:-4]))
|
||||
continue
|
||||
if n is vm_swap_index:
|
||||
vm_swap = kib_to_mib(int(
|
||||
line.split('\t')[1][:-4]))
|
||||
break
|
||||
except FileNotFoundError:
|
||||
vm_rss = 0
|
||||
vm_swap = 0
|
||||
except ProcessLookupError:
|
||||
vm_rss = 0
|
||||
vm_swap = 0
|
||||
except IndexError:
|
||||
vm_rss = 0
|
||||
vm_swap = 0
|
||||
|
||||
print(' Try to send the {} signal to {},\n Pid {}, Badness {}, V'
|
||||
'mRSS {} MiB, VmSwap {} MiB'.format(
|
||||
sig_dict[signal], name, pid, oom_score, vm_rss, vm_swap))
|
||||
|
||||
try:
|
||||
os.kill(int(pid), signal)
|
||||
print(' Success')
|
||||
|
||||
if desktop_notifications:
|
||||
send_notify(signal, name, pid, oom_score, vm_rss, vm_swap)
|
||||
|
||||
except FileNotFoundError:
|
||||
print(' No such process')
|
||||
except ProcessLookupError:
|
||||
print(' No such process')
|
||||
|
||||
# спать всегда или только при успешной отправке сигнала?
|
||||
if signal is 9:
|
||||
if print_sleep_periods:
|
||||
print(' sleep', min_delay_after_sigkill)
|
||||
sleep(min_delay_after_sigterm)
|
||||
else:
|
||||
if print_sleep_periods:
|
||||
print(' sleep', min_delay_after_sigterm)
|
||||
sleep(min_delay_after_sigterm)
|
||||
print(' oom_score {} < oom_score_min {}'.format(
|
||||
oom_score, oom_score_min))
|
||||
|
||||
sleep_after_send_signal(signal)
|
||||
|
||||
|
||||
def find_victim_and_send_signal(signal):
|
||||
if use_regexp_lists:
|
||||
find_victim_and_send_signal_with_regexp_lists(signal)
|
||||
else:
|
||||
find_victim_and_send_signal_without_regexp_lists(signal)
|
||||
|
||||
|
||||
##########################################################################
|
||||
|
||||
@ -370,6 +536,8 @@ except IndexError:
|
||||
# валидация всех параметров
|
||||
|
||||
|
||||
|
||||
# OK
|
||||
if 'print_config' in config_dict:
|
||||
print_config = config_dict['print_config']
|
||||
if print_config == 'True':
|
||||
@ -377,15 +545,15 @@ if 'print_config' in config_dict:
|
||||
elif print_config == 'False':
|
||||
print_config = False
|
||||
else:
|
||||
print('Invalid print_config value {} (should be True or False)\nE'
|
||||
'xit'.format(
|
||||
print_config))
|
||||
print('Invalid print_config value {} (shou' \
|
||||
'ld be True or False)\nExit'.format(print_config))
|
||||
exit()
|
||||
else:
|
||||
print('Print_config not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'print_mem_check_results' in config_dict:
|
||||
print_mem_check_results = config_dict['print_mem_check_results']
|
||||
if print_mem_check_results == 'True':
|
||||
@ -393,15 +561,16 @@ if 'print_mem_check_results' in config_dict:
|
||||
elif print_mem_check_results == 'False':
|
||||
print_mem_check_results = False
|
||||
else:
|
||||
print('Invalid print_mem_check_results value {} (should be Tr'
|
||||
'ue or False)\nExit'.format(
|
||||
print_mem_check_results))
|
||||
print('Invalid print_mem_check_result' \
|
||||
's value {} (should be True or False)\nExit'.format(
|
||||
print_mem_check_results))
|
||||
exit()
|
||||
else:
|
||||
print('print_mem_check_results not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'print_sleep_periods' in config_dict:
|
||||
print_sleep_periods = config_dict['print_sleep_periods']
|
||||
if print_sleep_periods == 'True':
|
||||
@ -409,15 +578,15 @@ if 'print_sleep_periods' in config_dict:
|
||||
elif print_sleep_periods == 'False':
|
||||
print_sleep_periods = False
|
||||
else:
|
||||
print('Invalid print_sleep_periods value {} (should be True or F'
|
||||
'alse)\nExit'.format(
|
||||
print_sleep_periods))
|
||||
print('Invalid print_sleep_periods value {} (shou' \
|
||||
'ld be True or False)\nExit'.format(print_sleep_periods))
|
||||
exit()
|
||||
else:
|
||||
print('print_sleep_periods not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'mlockall' in config_dict:
|
||||
mlockall = config_dict['mlockall']
|
||||
if mlockall == 'True':
|
||||
@ -427,51 +596,48 @@ if 'mlockall' in config_dict:
|
||||
else:
|
||||
print(
|
||||
'Invalid mlockall value {} (should be True or False)\nExit'.format(
|
||||
mlockall
|
||||
)
|
||||
)
|
||||
mlockall))
|
||||
exit()
|
||||
else:
|
||||
print('mlockall not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'self_nice' in config_dict:
|
||||
self_nice = config_dict['self_nice']
|
||||
if string_to_int_convert_test(self_nice) is None:
|
||||
self_nice = string_to_int_convert_test(config_dict['self_nice'])
|
||||
if 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()
|
||||
if self_nice < -20 or self_nice > 19:
|
||||
print('Недопустимое значение self_nice\nExit')
|
||||
exit()
|
||||
else:
|
||||
print('self_nice not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'self_oom_score_adj' in config_dict:
|
||||
self_oom_score_adj = config_dict['self_oom_score_adj']
|
||||
self_oom_score_adj = string_to_int_convert_test(self_oom_score_adj)
|
||||
self_oom_score_adj = string_to_int_convert_test(
|
||||
config_dict['self_oom_score_adj'])
|
||||
if self_oom_score_adj is None:
|
||||
print('Invalid self_oom_score_adj value, not integer\nExit')
|
||||
exit()
|
||||
else:
|
||||
if self_oom_score_adj < -1000 or self_oom_score_adj > 1000:
|
||||
print('Недопустимое значение self_oom_score_adj\nExit')
|
||||
exit()
|
||||
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\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'rate_mem' in config_dict:
|
||||
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 должен быть положительным\nExit')
|
||||
exit()
|
||||
@ -480,12 +646,12 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'rate_swap' in config_dict:
|
||||
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 должен быть положительным\nExit')
|
||||
exit()
|
||||
@ -494,12 +660,12 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'rate_zram' in config_dict:
|
||||
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 должен быть положительным\nExit')
|
||||
exit()
|
||||
@ -508,6 +674,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
|
||||
if 'mem_min_sigterm' in config_dict:
|
||||
mem_min_sigterm = config_dict['mem_min_sigterm']
|
||||
else:
|
||||
@ -515,6 +682,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
|
||||
if 'mem_min_sigkill' in config_dict:
|
||||
mem_min_sigkill = config_dict['mem_min_sigkill']
|
||||
else:
|
||||
@ -522,6 +690,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
|
||||
if 'swap_min_sigterm' in config_dict:
|
||||
swap_min_sigterm = config_dict['swap_min_sigterm']
|
||||
else:
|
||||
@ -529,6 +698,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
|
||||
if 'swap_min_sigkill' in config_dict:
|
||||
swap_min_sigkill = config_dict['swap_min_sigkill']
|
||||
else:
|
||||
@ -536,6 +706,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
|
||||
if 'zram_max_sigterm' in config_dict:
|
||||
zram_max_sigterm = config_dict['zram_max_sigterm']
|
||||
else:
|
||||
@ -543,6 +714,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
|
||||
if 'zram_max_sigkill' in config_dict:
|
||||
zram_max_sigkill = config_dict['zram_max_sigkill']
|
||||
else:
|
||||
@ -550,13 +722,13 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'min_delay_after_sigterm' in config_dict:
|
||||
min_delay_after_sigterm = string_to_float_convert_test(
|
||||
config_dict['m' 'in_delay_after_sigterm'])
|
||||
config_dict['min_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()
|
||||
@ -565,13 +737,13 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'min_delay_after_sigkill' in config_dict:
|
||||
min_delay_after_sigkill = string_to_float_convert_test(
|
||||
config_dict['mi' 'n_delay_after_sigkill'])
|
||||
config_dict['min_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()
|
||||
@ -580,21 +752,22 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'oom_score_min' in config_dict:
|
||||
oom_score_min = config_dict['oom_score_min']
|
||||
if string_to_int_convert_test(oom_score_min) is None:
|
||||
oom_score_min = string_to_int_convert_test(
|
||||
config_dict['oom_score_min'])
|
||||
if 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()
|
||||
if oom_score_min < 0 or oom_score_min > 1000:
|
||||
print('Недопустимое значение oom_score_min\nExit')
|
||||
exit()
|
||||
else:
|
||||
print('oom_score_min not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'decrease_oom_score_adj' in config_dict:
|
||||
decrease_oom_score_adj = config_dict['decrease_oom_score_adj']
|
||||
if decrease_oom_score_adj == 'True':
|
||||
@ -602,19 +775,18 @@ if 'decrease_oom_score_adj' in config_dict:
|
||||
elif decrease_oom_score_adj == 'False':
|
||||
decrease_oom_score_adj = False
|
||||
else:
|
||||
print('invalid decrease_oom_score_adj value {} (should be Tru'
|
||||
'e or False)\nExit'.format(
|
||||
decrease_oom_score_adj))
|
||||
print('invalid decrease_oom_score_adj value {} (should b' \
|
||||
'e True or False\nExit'.format(decrease_oom_score_adj))
|
||||
exit()
|
||||
else:
|
||||
print('decrease_oom_score_adj not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'oom_score_adj_max' in config_dict:
|
||||
oom_score_adj_max = config_dict['oom_score_adj_max']
|
||||
|
||||
oom_score_adj_max = string_to_int_convert_test(oom_score_adj_max)
|
||||
oom_score_adj_max = string_to_int_convert_test(
|
||||
config_dict['oom_score_adj_max'])
|
||||
if oom_score_adj_max is None:
|
||||
print('Invalid oom_score_adj_max value, not integer\nExit')
|
||||
exit()
|
||||
@ -626,6 +798,7 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'desktop_notifications' in config_dict:
|
||||
desktop_notifications = config_dict['desktop_notifications']
|
||||
if desktop_notifications == 'True':
|
||||
@ -640,15 +813,16 @@ if 'desktop_notifications' in config_dict:
|
||||
elif desktop_notifications == 'False':
|
||||
desktop_notifications = False
|
||||
else:
|
||||
print('Invalid desktop_notifications value {} (should be Tru'
|
||||
'e or False)\nExit'.format(
|
||||
desktop_notifications))
|
||||
print('Invalid desktop_notifications value {} (shoul' \
|
||||
'd be True or False)\nExit'.format(
|
||||
desktop_notifications))
|
||||
exit()
|
||||
else:
|
||||
print('desktop_notifications not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'notify_options' in config_dict:
|
||||
notify_options = config_dict['notify_options'].strip()
|
||||
else:
|
||||
@ -656,12 +830,90 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'display' in config_dict:
|
||||
display = config_dict['display'].strip()
|
||||
else:
|
||||
print('display not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'use_regexp_lists' in config_dict:
|
||||
use_regexp_lists = config_dict['use_regexp_lists']
|
||||
if use_regexp_lists == 'True':
|
||||
use_regexp_lists = True
|
||||
elif use_regexp_lists == 'False':
|
||||
use_regexp_lists = False
|
||||
else:
|
||||
print('invalid use_regexp_lists value {} (shoul' \
|
||||
'd be True or False)\nExit'.format(use_regexp_lists))
|
||||
exit()
|
||||
else:
|
||||
print('use_regexp_lists not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'white_list' in config_dict:
|
||||
white_list = config_dict['white_list'].strip()
|
||||
else:
|
||||
print('white_list not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'black_list' in config_dict:
|
||||
black_list = config_dict['black_list'].strip()
|
||||
else:
|
||||
print('black_list not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'prefer_list' in config_dict:
|
||||
prefer_list = config_dict['prefer_list'].strip()
|
||||
else:
|
||||
print('prefer_list not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'prefer_factor' in config_dict:
|
||||
prefer_factor = string_to_float_convert_test(config_dict['prefer_factor'])
|
||||
if prefer_factor is None:
|
||||
print('Invalid prefer_factor value, not float\nExit')
|
||||
exit()
|
||||
if prefer_factor <= 0:
|
||||
print('prefer_factor должен быть положительным\nExit')
|
||||
exit()
|
||||
else:
|
||||
print('prefer_factor not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'avoid_list' in config_dict:
|
||||
avoid_list = config_dict['avoid_list'].strip()
|
||||
else:
|
||||
print('avoid_list not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
# OK
|
||||
if 'avoid_factor' in config_dict:
|
||||
avoid_factor = string_to_float_convert_test(config_dict['avoid_factor'])
|
||||
if avoid_factor is None:
|
||||
print('Invalid avoid_factor value, not float\nExit')
|
||||
exit()
|
||||
if avoid_factor <= 0:
|
||||
print('avoid_factor должен быть положительным\nExit')
|
||||
exit()
|
||||
else:
|
||||
print('avoid_factor not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
##########################################################################
|
||||
|
||||
# получение уровней в кибибайтах
|
||||
@ -813,6 +1065,17 @@ if print_config:
|
||||
print('desktop_notifications: {}'.format(desktop_notifications))
|
||||
if desktop_notifications:
|
||||
print('notify_options: {}'.format(notify_options))
|
||||
print('display: {}'.format(display))
|
||||
|
||||
print('\nVII. BLACK, WHITE, AVOID AND PREFER LISTS')
|
||||
print('use_regexp_lists: {}'.format(use_regexp_lists))
|
||||
if use_regexp_lists:
|
||||
print('white_list: {}'.format(white_list))
|
||||
print('black_list: {}'.format(black_list))
|
||||
print('prefer_list: {}'.format(prefer_list))
|
||||
print('prefer_factor: {}'.format(prefer_factor))
|
||||
print('avoid_list: {}'.format(avoid_list))
|
||||
print('avoid_factor: {}'.format(avoid_factor))
|
||||
|
||||
|
||||
# для рассчета ширины столбцов при печати mem и zram
|
||||
@ -950,11 +1213,11 @@ while True:
|
||||
find_victim_and_send_signal(15)
|
||||
|
||||
# задание периода в зависимости от рейтов и уровней доступной памяти
|
||||
t_mem = mem_available / 1000000.0 / rate_mem
|
||||
t_mem = mem_available / rate_mem
|
||||
|
||||
t_swap = swap_free / 10000000.0 / rate_swap
|
||||
t_swap = swap_free / rate_swap
|
||||
|
||||
t_zram = (mem_total * 0.8 - mem_used_zram) / 1000000.0 / rate_zram
|
||||
t_zram = (mem_total * 0.8 - mem_used_zram) / rate_zram
|
||||
if t_zram < 0.01:
|
||||
t_zram = 0.01
|
||||
|
||||
@ -972,3 +1235,4 @@ while True:
|
||||
sleep(t)
|
||||
except KeyboardInterrupt:
|
||||
exit()
|
||||
|
||||
|
57
nohang.conf
57
nohang.conf
@ -24,7 +24,7 @@ print_mem_check_results = True
|
||||
Допустимые значения: True и False
|
||||
(В этой ветке по дефолту True)
|
||||
|
||||
print_sleep_periods = True
|
||||
print_sleep_periods = False
|
||||
|
||||
#####################################################################
|
||||
|
||||
@ -69,11 +69,11 @@ self_oom_score_adj = -1000
|
||||
|
||||
В дефолтных настройках на данной интенсивности демон работает
|
||||
достаточно хорошо, успешно справляясь с резкими скачками потребления
|
||||
памяти.
|
||||
памяти.
|
||||
|
||||
rate_mem = 6
|
||||
rate_swap = 3
|
||||
rate_zram = 1
|
||||
rate_mem = 6000000
|
||||
rate_swap = 3000000
|
||||
rate_zram = 1000000
|
||||
|
||||
#####################################################################
|
||||
|
||||
@ -115,6 +115,11 @@ zram_max_sigkill = 60 %
|
||||
|
||||
Значение должно быть целым числом из диапазона [0; 1000]
|
||||
|
||||
Процессы из black_list (см ниже) получат сигнал вне зависимости
|
||||
от значения их oom_score.
|
||||
|
||||
Может min_badness с учетом списков?
|
||||
|
||||
oom_score_min = 20
|
||||
|
||||
Минимальная задержка после отправки соответствующих сигналов
|
||||
@ -136,11 +141,11 @@ min_delay_after_sigkill = 3
|
||||
|
||||
Требует root прав.
|
||||
|
||||
decrease_oom_score_adj = True
|
||||
decrease_oom_score_adj = False
|
||||
|
||||
Допустимые значения - целые числа из диапазона [0; 1000]
|
||||
|
||||
oom_score_adj_max = 30
|
||||
oom_score_adj_max = 20
|
||||
|
||||
#####################################################################
|
||||
|
||||
@ -170,3 +175,41 @@ notify_options =
|
||||
|
||||
display = :0
|
||||
|
||||
#####################################################################
|
||||
|
||||
VII. BLACK, WHITE, AVOID AND PREFER LISTS
|
||||
|
||||
Можно задать списки с помощью Perl-compatible regular expressions.
|
||||
|
||||
Включение этой опции замедляет поиск жертвы, так как
|
||||
имена всех процессов сравниваются с regexp паттернами всех
|
||||
списков.
|
||||
|
||||
use_regexp_lists = False
|
||||
|
||||
Процессы из белого списка не получат сигнал.
|
||||
|
||||
white_list = ^(Xorg|sshd)$
|
||||
|
||||
При нехватке памяти все процессы из черного списка получат сигнал.
|
||||
|
||||
black_list = ^()$
|
||||
|
||||
Список предпочтительных для убийства процессов.
|
||||
Badness процессов из prefer_list будет умножено на
|
||||
prefer_factor перед выбором жертвы. На самом деле формула
|
||||
для нахождения badness такая:
|
||||
badness = (oom_score + 1) * prefer_factor
|
||||
|
||||
prefer_factor и avoid_factor должны быть положительными числами.
|
||||
|
||||
prefer_list = ^()$
|
||||
prefer_factor = 2
|
||||
|
||||
Список нежелательных для убийства процессов.
|
||||
Badness процессов из avoid_list будет поделено на
|
||||
avoid_factor перед выбором жертвы.
|
||||
|
||||
avoid_list = ^()$
|
||||
avoid_factor = 2
|
||||
|
||||
|
8
purge.sh
8
purge.sh
@ -1,7 +1,7 @@
|
||||
#!/bin/bash -v
|
||||
systemctl stop nohang
|
||||
systemctl disable nohang
|
||||
rm -f /usr/local/share/man/man1/nohang.1.gz
|
||||
rm -f /etc/systemd/system/nohang.service
|
||||
rm -rf /etc/nohang
|
||||
rm -f /usr/local/bin/nohang
|
||||
rm /usr/local/share/man/man1/nohang.1.gz
|
||||
rm /etc/systemd/system/nohang.service
|
||||
rm -r /etc/nohang
|
||||
rm /usr/local/bin/nohang
|
||||
|
Loading…
Reference in New Issue
Block a user