implement modify badness by matching with RE pattern

This commit is contained in:
Alexey Avramov 2018-12-10 02:01:26 +09:00
parent 3830179a68
commit 842ea7be35
3 changed files with 115 additions and 32 deletions

123
nohang
View File

@ -7,6 +7,8 @@ from argparse import ArgumentParser
from sys import stdout
from signal import SIGKILL, SIGTERM
start_time = time()
sig_dict = {SIGKILL: 'SIGKILL',
SIGTERM: 'SIGTERM'}
@ -357,16 +359,8 @@ def find_victim_and_send_signal(signal):
pid_badness_list = []
# not implemented, in progress
prefer_re_cmdline = ''
avoid_re_cmdline = ''
prefer_cmd_factor = 1
prefer_cmd_factor = 1
if regex_matching:
for pid in os.listdir('/proc'):
# только директории, имена которых состоят только из цифр, за исключением /proc/1/
if pid[0].isdecimal() is False or pid == '1':
@ -376,29 +370,40 @@ def find_victim_and_send_signal(signal):
badness = int(rline1('/proc/' + pid + '/oom_score'))
name = pid_to_name(pid)
cmdline = pid_to_cmdline(pid)
#uid = pid_to_uid(pid)
# skip kthreads
if cmdline == '':
continue
#print([pid], [name], [cmdline])
if re.search(avoid_regex, name) is not None:
if search(avoid_regex, name) is not None:
badness = int(badness / avoid_factor)
print(' Name matches with avoid_regex \033[33m{}\033[0m: \033[33m{}\033[0m, CmdLine: {}'.format(
avoid_regex, name, cmdline))
if re.search(prefer_regex, name) is not None:
if search(prefer_regex, name) is not None:
badness = int((badness + 1) * prefer_factor)
print(' Name matches with prefer_regex \033[33m{}\033[0m: \033[33m{}\033[0m, CmdLine: {}'.format(
prefer_regex, name, cmdline))
if re.search(avoid_re_cmdline, cmdline) is not None:
badness = int(badness / avoid_factor)
if search(avoid_re_cmdline, cmdline) is not None:
badness = int(badness / avoid_cmd_factor)
print(' Cmdline matches with avoid_re_cmdline \033[33m{}\033[0m: \033[33m{}\033[0m, Name: {}'.format(
avoid_re_cmdline, cmdline, name))
if re.search(prefer_re_cmdline, cmdline) is not None:
if search(prefer_re_cmdline, cmdline) is not None:
badness = int((badness + 1) * prefer_cmd_factor)
print(' Cmdline matches with prefer_re_cmdline \033[33m{}\033[0m: \033[33m{}\033[0m, Name: {}'.format(
prefer_re_cmdline, cmdline, name))
except FileNotFoundError:
@ -409,7 +414,6 @@ def find_victim_and_send_signal(signal):
else:
for pid in os.listdir('/proc'):
@ -433,6 +437,7 @@ def find_victim_and_send_signal(signal):
if victim_badness >= min_badness: # Try to send signal to found victim
pid = pid_tuple_list[0]
name = pid_to_name(pid)
# Get VmRSS and VmSwap and cmdline of victim process and try to send signal
@ -448,12 +453,12 @@ def find_victim_and_send_signal(signal):
if n is vm_swap_index:
vm_swap = kib_to_mib(int(line.split('\t')[1][:-4]))
break
with open('/proc/' + pid + '/cmdline') as file:
try:
cmdline = file.readlines()[0].replace('\x00', ' ')
except IndexError:
cmdline = ''
except FileNotFoundError:
pass
except ProcessLookupError:
@ -503,11 +508,12 @@ def find_victim_and_send_signal(signal):
response_time = time() - time0
victim_badness_is_too_small = ' victim badness {} < min_badness {}; nothing to do; response time: {} ms'.format(
victim_badness, min_badness, round(response_time * 1000))
victim_badness,
min_badness,
round(response_time * 1000))
print(victim_badness_is_too_small)
stdout.flush()
sleep_after_send_signal(signal)
@ -528,13 +534,12 @@ def sleep_after_check_mem():
try:
if print_sleep_periods:
print(
'sleep', round(
t, 2), ' (t_mem={}, t_swap={}, t_zram={})'.format(
round(
t_mem, 2), round(
t_swap, 2), round(
t_zram, 2)))
print('sleep', round(t, 2),
' (t_mem={}, t_swap={}, t_zram={})'.format(
round(t_mem, 2),
round(t_swap, 2),
round(t_zram, 2)))
stdout.flush()
sleep(t)
except KeyboardInterrupt:
exit()
@ -816,6 +821,13 @@ execute_the_command = conf_parse_bool('execute_the_command')
prefer_regex = conf_parse_string('prefer_regex')
avoid_regex = conf_parse_string('avoid_regex')
prefer_re_cmdline = conf_parse_string('prefer_re_cmdline')
avoid_re_cmdline = conf_parse_string('avoid_re_cmdline')
mem_min_sigterm_kb, mem_min_sigterm_mb, mem_min_sigterm_percent = calculate_percent(
'mem_min_sigterm')
@ -1016,6 +1028,57 @@ else:
exit()
if 'prefer_cmd_factor' in config_dict:
prefer_cmd_factor = string_to_float_convert_test(config_dict['prefer_cmd_factor'])
if prefer_cmd_factor is None:
print('Invalid prefer_cmd_factor value, not float\nExit')
exit()
if prefer_cmd_factor < 1 and prefer_cmd_factor > 1000:
print('prefer_cmd_factor value out of range [1; 1000]\nExit')
exit()
else:
print('prefer_cmd_factor not in config\nExit')
exit()
if 'avoid_cmd_factor' in config_dict:
avoid_cmd_factor = string_to_float_convert_test(config_dict['avoid_cmd_factor'])
if avoid_cmd_factor is None:
print('Invalid avoid_cmd_factor value, not float\nExit')
exit()
if avoid_cmd_factor < 1 and avoid_cmd_factor > 1000:
print('avoid_cmd_factor value out of range [1; 1000]\nExit')
exit()
else:
print('avoid_cmd_factor not in config\nExit')
exit()
if 'min_time_between_warnings' in config_dict:
min_time_between_warnings = string_to_float_convert_test(
config_dict['min_time_between_warnings'])
@ -1253,10 +1316,14 @@ warn_time_now = 0
warn_time_delta = 1000
warn_timer = 0
x = time() - start_time
print(
'The duration of startup:', round(
x * 1000, 1), 'ms')
print('Monitoring started!')
stdout.flush()
##########################################################################

View File

@ -121,13 +121,14 @@ oom_score_adj_max = 30
#####################################################################
4. Impact on the badness of processes via matching their names
with regular expressions.
with regular expressions (using re.search()).
See https://en.wikipedia.org/wiki/Regular_expression and
https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions
Enabling this option slows down the search for the victim
because the names of all processes are compared with the
because the names or cmdlines of all processes
(except init and kthreads) are compared with the
specified regex patterns.
Valid values are True and False.
@ -138,10 +139,11 @@ regex_matching = False
be calculated by the following formula:
badness = (oom_score + 1) * prefer_factor
prefer_regex =
Matching with process names
RE pattern must not be empty!
# prefer_re_cmdline = ^/usr/lib/firefox # not implemented, in progress
prefer_regex = /usr/bin...
Valid values are floating-point numbers from the range [1; 1000].
@ -159,6 +161,18 @@ avoid_regex = ^(sshd|Xorg)$
avoid_factor = 3
Matching with cmdlines
prefer_re_cmdline = ^/usr/lib/firefox
avoid_re_cmdline = ^/usr/lib/virtualbox
prefer_cmd_factor = 3
avoid_cmd_factor = 3
#####################################################################
5. The execution of a specific command instead of sending the

View File

@ -104,3 +104,5 @@ if len(b) > 0:
], env={
display_key: display_value, dbus_key: dbus_value
}).wait(3)
else:
print('Low memory warnings: nobody logged in with GUI. Nothing to do.')