fix comments, fix low mem warns

This commit is contained in:
Alexey Avramov 2018-11-29 03:14:48 +09:00
parent 2096628d21
commit 55f4d1fa18

537
nohang
View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""A daemon that prevents OOM in linux systems.""" """A daemon that prevents OOM in Linux systems."""
import os import os
import signal import signal
from operator import itemgetter from operator import itemgetter
@ -22,21 +22,9 @@ conf_err_mess = '\nSet up the path to the valid conf' \
'ig file with -c/--config option!\nExit' 'ig file with -c/--config option!\nExit'
# означает, что при задани zram disksize = 10000M доступная память
# уменьшится на 42M
# найден экспериментально, требует уточнения с разными ядрами и архитектурами
# на небольших дисксайзах (до гигабайта) может быть больше, до 0.0045
# создатель модуля zram утверждает, что zram_disksize_factor доожен быть 0.001
# ("zram uses about 0.1% of the size of the disk"
# - https://www.kernel.org/doc/Documentation/blockdev/zram.txt),
# но это утверждение противоречит опытным данным
# zram_disksize_factor = deltaMemAvailavle / disksize
# found experimentally
zram_disksize_factor = 0.0042
########################################################################## ##########################################################################
# function definition section # function definition section
@ -137,7 +125,7 @@ def conf_parse_bool(param):
def func_decrease_oom_score_adj(oom_score_adj_max): def func_decrease_oom_score_adj(oom_score_adj_max):
""" """
Pls, put description here... Stupid function, must be removed or remaked
""" """
for i in os.listdir('/proc'): for i in os.listdir('/proc'):
if i.isdigit() is not True: if i.isdigit() is not True:
@ -185,9 +173,8 @@ def just_percent_swap(num):
return str(round(num * 100, 1)).rjust(5, ' ') return str(round(num * 100, 1)).rjust(5, ' ')
# KiB to MiB, right alignment
def human(num, lenth): def human(num, lenth):
"""Convert Kib values to Mib values with right alignment""" """Convert KiB values to MiB values with right alignment"""
return str(round(num / 1024)).rjust(lenth, ' ') return str(round(num / 1024)).rjust(lenth, ' ')
@ -238,8 +225,6 @@ def pid_to_name(pid):
def send_notify_warn(): def send_notify_warn():
""" """
Look for process with maximum 'badness' and warn user with notification. Look for process with maximum 'badness' and warn user with notification.
""" """
# find process with max badness # find process with max badness
fat_tuple = fattest() fat_tuple = fattest()
@ -268,8 +253,7 @@ def send_notify_warn():
'--pid', pid, '--name', name]) '--pid', pid, '--name', name])
else: # Or by regular user else: # Or by regular user
# send notification to user that runs this nohang # send notification to user that runs this nohang
Popen(['notify-send', '--icon=dialog-warning', Popen(['notify-send', '--icon=dialog-warning', '{}'.format(title), '{}'.format(body)])
'Low memory: {}'.format(title), '{}'.format(body)])
def send_notify(signal, name, pid): def send_notify(signal, name, pid):
@ -294,7 +278,8 @@ def send_notify(signal, name, pid):
'{}'.format(title), '{}'.format(body)]) '{}'.format(title), '{}'.format(body)])
else: else:
# send notification to user that runs this nohang # send notification to user that runs this nohang
Popen(['notify-send', '--icon=dialog-warning', '{}'.format(title), '{}'.format(body)]) Popen(['notify-send', '--icon=dialog-warning',
'{}'.format(title), '{}'.format(body)])
def send_notify_etc(pid, name, command): def send_notify_etc(pid, name, command):
@ -341,9 +326,7 @@ def sleep_after_send_signal(signal):
def find_victim_and_send_signal(signal): def find_victim_and_send_signal(signal):
""" """
Please describe this. Find victim with highest badness and send SIGTERM/SIGKILL
thanks
""" """
if decrease_oom_score_adj and root: if decrease_oom_score_adj and root:
func_decrease_oom_score_adj(oom_score_adj_max) func_decrease_oom_score_adj(oom_score_adj_max)
@ -442,27 +425,34 @@ def find_victim_and_send_signal(signal):
try: try:
os.kill(int(pid), signal) os.kill(int(pid), signal)
response_time = time() - time0 response_time = time() - time0
send_result = 'OK; response time: {} ms'.format(round(response_time * 1000)) send_result = 'OK; response time: {} ms'.format(
round(response_time * 1000))
if gui_notifications: if gui_notifications:
send_notify(signal, name, pid) send_notify(signal, name, pid)
except FileNotFoundError: except FileNotFoundError:
response_time = time() - time0 response_time = time() - time0
send_result = 'no such process; response time: {} ms'.format(round(response_time * 1000)) send_result = 'no such process; response time: {} ms'.format(
round(response_time * 1000))
except ProcessLookupError: except ProcessLookupError:
response_time = time() - time0 response_time = time() - time0
send_result = 'no such process; response time: {} ms'.format(round(response_time * 1000)) send_result = 'no such process; response time: {} ms'.format(
round(response_time * 1000))
# Pls correct line length =) preventing_oom_message = ' Finding the process with the highes' \
preventing_oom_message = ' Finding the process with the highest badness\n Victim is {}, pid: {}, badness: {}, VmRSS: {} MiB, VmSwap: {} MiB\n Sending {} to the victim; {}'.format(name, pid, victim_badness, vm_rss, vm_swap, sig_dict[signal], send_result) 't badness\n Victim is {}, pid: {}, badness: {}, VmRS' \
'S: {} MiB, VmSwap: {} MiB\n Sending {} to the victim; {}'.format(
name, pid, victim_badness, vm_rss, vm_swap, sig_dict[signal],
send_result)
print(mem_info) print(mem_info)
print(preventing_oom_message) print(preventing_oom_message)
else: else:
response_time = time() - time0 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_is_too_small = ' victim badness {} < min_badness {}; nothing to do; response time: {} ms'.format(
victim_badness, min_badness, round(response_time * 1000))
print(victim_badness_is_too_small) print(victim_badness_is_too_small)
@ -487,8 +477,13 @@ def sleep_after_check_mem():
try: try:
if print_sleep_periods: if print_sleep_periods:
print('sleep', round(t, 2), ' (t_mem={}, t_swap={}, t_zram={})'.format( print(
round(t_mem, 2), round(t_swap, 2), round(t_zram, 2))) 'sleep', round(
t, 2), ' (t_mem={}, t_swap={}, t_zram={})'.format(
round(
t_mem, 2), round(
t_swap, 2), round(
t_zram, 2)))
sleep(t) sleep(t)
except KeyboardInterrupt: except KeyboardInterrupt:
exit() exit()
@ -544,9 +539,68 @@ def fattest():
return (name, pid) return (name, pid)
def calculate_percent(arg_key):
"""
parse conf dict
Calculate mem_min_KEY_percent.
Try use this one)
arg_key: str key for config_dict
returns int mem_min_percent or NoneType if got some error
"""
if arg_key in config_dict:
mem_min = config_dict[arg_key]
if mem_min.endswith('%'):
# truncate percents, so we have a number
mem_min_percent = mem_min[:-1].strip()
# then 'float test'
mem_min_percent = string_to_float_convert_test(mem_min_percent)
if mem_min_percent is None:
print('Invalid {} value, not float\nExit'.format(arg_key))
exit()
# Final validations...
if mem_min_percent < 0 or mem_min_percent > 100:
print(
'{}, as percents value, out of range [0; 100]\nExit'.format(arg_key))
exit()
# mem_min_sigterm_percent is clean and valid float percentage. Can
# translate into Kb
mem_min_kb = mem_min_percent / 100 * mem_total
mem_min_mb = round(mem_min_kb / 1024)
elif mem_min.endswith('M'):
mem_min_mb = string_to_float_convert_test(mem_min[:-1].strip())
if mem_min_mb is None:
print('Invalid {} value, not float\nExit'.format(arg_key))
exit()
mem_min_kb = mem_min_mb * 1024
if mem_min_kb > mem_total:
print(
'{} value can not be greater then MemTotal ({} MiB)\nExit'.format(
arg_key, round(
mem_total / 1024)))
exit()
mem_min_percent = mem_min_kb / mem_total * 100
else:
print('Invalid {} units in config.\n Exit'.format(arg_key))
mem_min_percent = None
else:
print('{} not in config\nExit'.format(arg_key))
mem_min_percent = None
return mem_min_kb, mem_min_mb, mem_min_percent
########################################################################## ##########################################################################
# поиск позиций и mem_total
# find mem_total
# find positions of SwapFree and SwapTotal in /proc/meminfo
with open('/proc/meminfo') as file: with open('/proc/meminfo') as file:
mem_list = file.readlines() mem_list = file.readlines()
@ -556,7 +610,7 @@ for s in mem_list:
mem_list_names.append(s.split(':')[0]) mem_list_names.append(s.split(':')[0])
if mem_list_names[2] != 'MemAvailable': if mem_list_names[2] != 'MemAvailable':
print('Your Linux kernel is too old, Linux 3.14+ requie\nExit') print('Your Linux kernel is too old, Linux 3.14+ requied\nExit')
exit() exit()
swap_total_index = mem_list_names.index('SwapTotal') swap_total_index = mem_list_names.index('SwapTotal')
@ -564,10 +618,11 @@ swap_free_index = swap_total_index + 1
mem_total = int(mem_list[0].split(':')[1].strip(' kB\n')) mem_total = int(mem_list[0].split(':')[1].strip(' kB\n'))
# Get names from /proc/*/status to be able to get VmRSS and VmSwap values
with open('/proc/self/status') as file: with open('/proc/self/status') as file:
status_list = file.readlines() status_list = file.readlines()
# Get names from /proc/*/status to be able to get VmRSS and VmSwap values
status_names = [] status_names = []
for s in status_list: for s in status_list:
status_names.append(s.split(':')[0]) status_names.append(s.split(':')[0])
@ -575,8 +630,10 @@ for s in status_list:
vm_rss_index = status_names.index('VmRSS') vm_rss_index = status_names.index('VmRSS')
vm_swap_index = status_names.index('VmSwap') vm_swap_index = status_names.index('VmSwap')
########################################################################## ##########################################################################
# Configurations # Configurations
# Cmd argparse # Cmd argparse
@ -617,8 +674,10 @@ else:
print('The path to the config:', config) print('The path to the config:', config)
########################################################################## ##########################################################################
# parsing the config with obtaining the parameters dictionary # parsing the config with obtaining the parameters dictionary
# conf_parameters_dict # conf_parameters_dict
@ -630,7 +689,8 @@ try:
# dictionary with config options # dictionary with config options
config_dict = dict() config_dict = dict()
# dictionary with names and commands for the parameter execute_the_command # dictionary with names and commands for the parameter
# execute_the_command
etc_dict = dict() etc_dict = dict()
for line in f: for line in f:
@ -651,7 +711,8 @@ try:
etc_name = a[0].strip() etc_name = a[0].strip()
etc_command = a[1].strip() etc_command = a[1].strip()
if len(etc_name) > 15: if len(etc_name) > 15:
print('Invalid config, the length of the process name must not exceed 15 characters\nExit') print(
'Invalid config, the length of the process name must not exceed 15 characters\nExit')
exit() exit()
etc_dict[etc_name] = etc_command etc_dict[etc_name] = etc_command
@ -668,23 +729,42 @@ except IndexError:
print('IndexError', conf_err_mess) print('IndexError', conf_err_mess)
exit() exit()
########################################################################## ##########################################################################
# extracting parameters from the dictionary # extracting parameters from the dictionary
# check for all necessary parameters # check for all necessary parameters
# validation of all parameters # validation of all parameters
print_config = conf_parse_bool('print_config') print_config = conf_parse_bool('print_config')
print_mem_check_results = conf_parse_bool('print_mem_check_results') print_mem_check_results = conf_parse_bool('print_mem_check_results')
print_sleep_periods = conf_parse_bool('print_sleep_periods') print_sleep_periods = conf_parse_bool('print_sleep_periods')
realtime_ionice = conf_parse_bool('realtime_ionice') realtime_ionice = conf_parse_bool('realtime_ionice')
mlockall = conf_parse_bool('mlockall')
gui_low_memory_warnings = conf_parse_bool('gui_low_memory_warnings')
gui_notifications = conf_parse_bool('gui_notifications')
decrease_oom_score_adj = conf_parse_bool('decrease_oom_score_adj')
regex_matching = conf_parse_bool('regex_matching')
execute_the_command = conf_parse_bool('execute_the_command')
prefer_regex = conf_parse_string('prefer_regex')
avoid_regex = conf_parse_string('avoid_regex')
mem_min_sigterm_kb, mem_min_sigterm_mb, mem_min_sigterm_percent = calculate_percent(
'mem_min_sigterm')
mem_min_sigkill_kb, mem_min_sigkill_mb, mem_min_sigkill_percent = calculate_percent(
'mem_min_sigkill')
zram_max_sigterm_kb, zram_max_sigterm_mb, zram_max_sigterm_percent = calculate_percent(
'zram_max_sigterm')
zram_max_sigkill_kb, zram_max_sigkill_mb, zram_max_sigkill_percent = calculate_percent(
'zram_max_sigkill')
mem_min_warnings_kb, mem_min_warnings_mb, mem_min_warnings_percent = calculate_percent(
'mem_min_warnings')
zram_max_warnings_kb, zram_max_warnings_mb, zram_max_warnings_percent = calculate_percent(
'zram_max_warnings')
if 'realtime_ionice_classdata' in config_dict: if 'realtime_ionice_classdata' in config_dict:
@ -706,9 +786,6 @@ else:
exit() exit()
mlockall = conf_parse_bool('mlockall')
if 'niceness' in config_dict: if 'niceness' in config_dict:
niceness = string_to_int_convert_test(config_dict['niceness']) niceness = string_to_int_convert_test(config_dict['niceness'])
if niceness is None: if niceness is None:
@ -775,143 +852,6 @@ else:
exit() exit()
def calculate_percent(arg_key):
"""
Calculate mem_min_KEY_percent.
Try use this one)
arg_key: str key for config_dict
returns int mem_min_percent or NoneType if got some error
"""
global mem_total
global string_to_float_convert_test
global config_dict
if arg_key in config_dict:
mem_min = config_dict[arg_key]
if mem_min.endswith('%'):
# truncate percents, so we have a number
mem_min_percent = mem_min[:-1].strip()
# then 'float test'
mem_min_percent = string_to_float_convert_test(mem_min_percent)
if mem_min_percent is None:
print('Invalid {} value, not float\nExit'.format(arg_key))
exit()
# Final validations...
if mem_min_percent < 0 or mem_min_percent > 100:
print('{}, as percents value, out of range [0; 100]\nExit'.format(arg_key))
exit()
# mem_min_sigterm_percent is clean and valid float percentage. Can translate into Kb
mem_min_kb = mem_min_percent / 100 * mem_total
mem_min_mb = round(mem_min_kb / 1024)
elif mem_min.endswith('M'):
mem_min_mb = string_to_float_convert_test(mem_min[:-1].strip())
if mem_min_mb is None:
print('Invalid {} value, not float\nExit'.format(arg_key))
exit()
mem_min_kb = mem_min_mb * 1024
if mem_min_kb > mem_total:
print('{} value can not be greater then MemTotal ({} MiB)\nExit'.format(arg_key, round(mem_total / 1024)))
exit()
mem_min_percent = mem_min_kb / mem_total * 100
else:
print('Invalid {} units in config.\n Exit'.format(arg_key))
mem_min_percent = None
else:
print('{} not in config\nExit'.format(arg_key))
mem_min_percent = None
return mem_min_kb, mem_min_mb, mem_min_percent
# if 'mem_min_sigterm' in config_dict:
# mem_min_sigterm = config_dict['mem_min_sigterm']
# if mem_min_sigterm.endswith('%'):
# # truncate percents, so we have a number
# mem_min_sigterm_percent = mem_min_sigterm[:-1].strip()
# # then 'float test'
# mem_min_sigterm_percent = string_to_float_convert_test(mem_min_sigterm_percent)
# if mem_min_sigterm_percent is None:
# print('Invalid mem_min_sigterm value, not float\nExit')
# exit()
# # Final validations...
# if mem_min_sigterm_percent < 0 or mem_min_sigterm_percent > 100:
# print('mem_min_sigterm, as percents value, out of range [0; 100]\nExit')
# exit()
# # mem_min_sigterm_percent is clean and valid float percentage. Can translate into Kb
# mem_min_sigterm_kb = mem_min_sigterm_percent / 100 * mem_total
# mem_min_sigterm_mb = round(mem_min_sigterm_kb / 1024)
# elif mem_min_sigterm.endswith('M'):
# mem_min_sigterm_mb = string_to_float_convert_test(mem_min_sigterm[:-1].strip())
# if mem_min_sigterm_mb is None:
# print('Invalid mem_min_sigterm value, not float\nExit')
# exit()
# mem_min_sigterm_kb = mem_min_sigterm_mb * 1024
# if mem_min_sigterm_kb > mem_total:
# print('mem_min_sigterm value can not be greater then MemTotal ({} MiB)\nExit'.format(round(mem_total / 1024)))
# exit()
# mem_min_sigterm_percent = mem_min_sigterm_kb / mem_total * 100
# else:
# print('Invalid mem_min_sigterm units in config.\n Exit')
# exit()
# else:
# print('mem_min_sigterm not in config\nExit')
# exit()
# if 'mem_min_sigkill' in config_dict:
# mem_min_sigkill = config_dict['mem_min_sigkill']
# if mem_min_sigkill.endswith('%'):
# # truncate percent, so we have a number
# mem_min_sigkill_percent = mem_min_sigkill[:-1].strip()
# # then 'float test'
# mem_min_sigkill_percent = string_to_float_convert_test(mem_min_sigkill_percent)
# if mem_min_sigkill_percent is None:
# print('Invalid mem_min_sigkill value, not float\nExit')
# exit()
# # Final validation
# if mem_min_sigkill_percent < 0 or mem_min_sigkill_percent > 100:
# print('mem_min_sigkill, as a percentage, out of range [0; 100]\nExit')
# exit()
# # mem_min_sigterm_percent is clean and valid float percentage. Can translate into Kb
# mem_min_sigkill_kb = mem_min_sigkill_percent / 100 * mem_total
# mem_min_sigkill_mb = round(mem_min_sigkill_kb / 1024)
# elif mem_min_sigkill.endswith('M'):
# mem_min_sigkill_mb = string_to_float_convert_test(mem_min_sigkill[:-1].strip())
# if mem_min_sigkill_mb is None:
# print('Invalid mem_min_sigkill value, not float\nExit')
# exit()
# mem_min_sigkill_kb = mem_min_sigkill_mb * 1024
# if mem_min_sigkill_kb > mem_total:
# print('mem_min_sigkill value can not be greater then MemTotal ({} MiB)\nExit'.format(round(mem_total / 1024)))
# exit()
# mem_min_sigkill_percent = mem_min_sigkill_kb / mem_total * 100
# else:
# print('Invalid mem_min_sigkill units in config\nExit')
# exit()
# else:
# print('mem_min_sigkill not in config\nExit')
# exit()
mem_min_sigterm_kb, mem_min_sigterm_mb, mem_min_sigterm_percent = calculate_percent('mem_min_sigterm')
mem_min_sigkill_kb, mem_min_sigkill_mb, mem_min_sigkill_percent = calculate_percent('mem_min_sigkill')
# НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ! # НУЖНА ВАЛИДАЦИЯ НА МЕСТЕ!
if 'swap_min_sigterm' in config_dict: if 'swap_min_sigterm' in config_dict:
swap_min_sigterm = config_dict['swap_min_sigterm'] swap_min_sigterm = config_dict['swap_min_sigterm']
@ -928,89 +868,6 @@ else:
exit() exit()
zram_max_sigterm_kb, zram_max_sigterm_mb, zram_max_sigterm_percent = calculate_percent('zram_max_sigterm')
zram_max_sigkill_kb, zram_max_sigkill_mb, zram_max_sigkill_percent = calculate_percent('zram_max_sigkill')
# if 'zram_max_sigterm' in config_dict:
# zram_max_sigterm = config_dict['zram_max_sigterm']
# if zram_max_sigterm.endswith('%'):
# # отбрасываем процент, получаем число
# zram_max_sigterm_percent = zram_max_sigterm[:-1].strip()
# # далее флоат тест
# zram_max_sigterm_percent = string_to_float_convert_test(zram_max_sigterm_percent)
# if zram_max_sigterm_percent is None:
# print('Invalid zram_max_sigterm value, not float\nExit')
# exit()
# # окончательная валидация
# if zram_max_sigterm_percent < 0 or zram_max_sigterm_percent > 100:
# print('zram_max_sigterm, выраженный в процентах, должен быть быть в диапазоне [0; 100]\nExit')
# exit()
# # zram_max_sigterm_percent это теперь чистое валидное флоат число процентов, можно переводить в кб
# zram_max_sigterm_kb = zram_max_sigterm_percent / 100 * mem_total
# zram_max_sigterm_mb = round(zram_max_sigterm_kb / 1024)
# elif zram_max_sigterm.endswith('M'):
# zram_max_sigterm_mb = string_to_float_convert_test(zram_max_sigterm[:-1].strip())
# if zram_max_sigterm_mb is None:
# print('Invalid zram_max_sigterm value, not float\nExit')
# exit()
# zram_max_sigterm_kb = zram_max_sigterm_mb * 1024
# if zram_max_sigterm_kb > mem_total:
# print('zram_max_sigterm value не должен быть больше MemTotal ({} MiB)\nExit'.format(round(mem_total / 1024)))
# exit()
# zram_max_sigterm_percent = zram_max_sigterm_kb / mem_total * 100
# else:
# print('Конфиг инвалид, для zram_max_sigterm неверно указаны единицы измерения\nExit')
# exit()
# else:
# print('zram_max_sigterm not in config\nExit')
# exit()
# if 'zram_max_sigkill' in config_dict:
# zram_max_sigkill = config_dict['zram_max_sigkill']
# if zram_max_sigkill.endswith('%'):
# # отбрасываем процент, получаем число
# zram_max_sigkill_percent = zram_max_sigkill[:-1].strip()
# # далее флоат тест
# zram_max_sigkill_percent = string_to_float_convert_test(zram_max_sigkill_percent)
# if zram_max_sigkill_percent is None:
# print('Invalid zram_max_sigkill value, not float\nExit')
# exit()
# # окончательная валидация
# if zram_max_sigkill_percent < 0 or zram_max_sigkill_percent > 100:
# print('zram_max_sigkill, выраженный в процентах, должен быть быть в диапазоне [0; 100]\nExit')
# exit()
# # zram_max_sigkill_percent это теперь чистое валидное флоат число процентов, можно переводить в кб
# zram_max_sigkill_kb = zram_max_sigkill_percent / 100 * mem_total
# zram_max_sigkill_mb = round(zram_max_sigkill_kb / 1024)
# elif zram_max_sigkill.endswith('M'):
# zram_max_sigkill_mb = string_to_float_convert_test(zram_max_sigkill[:-1].strip())
# if zram_max_sigkill_mb is None:
# print('Invalid zram_max_sigkill value, not float\nExit')
# exit()
# zram_max_sigkill_kb = zram_max_sigkill_mb * 1024
# if zram_max_sigkill_kb > mem_total:
# print('zram_max_sigkill value не должен быть больше MemTotal ({} MiB)\nExit'.format(round(mem_total / 1024)))
# exit()
# zram_max_sigkill_percent = zram_max_sigkill_kb / mem_total * 100
# else:
# print('Конфиг инвалид, для zram_max_sigkill неверно указаны единицы измерения\nExit')
# exit()
# else:
# print('zram_max_sigkill not in config\nExit')
# exit()
if 'min_delay_after_sigterm' in config_dict: if 'min_delay_after_sigterm' in config_dict:
min_delay_after_sigterm = string_to_float_convert_test( min_delay_after_sigterm = string_to_float_convert_test(
config_dict['min_delay_after_sigterm']) config_dict['min_delay_after_sigterm'])
@ -1053,9 +910,6 @@ else:
exit() exit()
decrease_oom_score_adj = conf_parse_bool('decrease_oom_score_adj')
if 'oom_score_adj_max' in config_dict: if 'oom_score_adj_max' in config_dict:
oom_score_adj_max = string_to_int_convert_test( oom_score_adj_max = string_to_int_convert_test(
config_dict['oom_score_adj_max']) config_dict['oom_score_adj_max'])
@ -1070,12 +924,6 @@ else:
exit() exit()
regex_matching = conf_parse_bool('regex_matching')
prefer_regex = conf_parse_string('prefer_regex')
if 'prefer_factor' in config_dict: if 'prefer_factor' in config_dict:
prefer_factor = string_to_float_convert_test(config_dict['prefer_factor']) prefer_factor = string_to_float_convert_test(config_dict['prefer_factor'])
if prefer_factor is None: if prefer_factor is None:
@ -1089,9 +937,6 @@ else:
exit() exit()
avoid_regex = conf_parse_string('avoid_regex')
if 'avoid_factor' in config_dict: if 'avoid_factor' in config_dict:
avoid_factor = string_to_float_convert_test(config_dict['avoid_factor']) avoid_factor = string_to_float_convert_test(config_dict['avoid_factor'])
if avoid_factor is None: if avoid_factor is None:
@ -1105,11 +950,6 @@ else:
exit() exit()
gui_low_memory_warnings = conf_parse_bool('gui_low_memory_warnings')
gui_notifications = conf_parse_bool('gui_notifications')
if 'min_time_between_warnings' in config_dict: if 'min_time_between_warnings' in config_dict:
min_time_between_warnings = string_to_float_convert_test( min_time_between_warnings = string_to_float_convert_test(
config_dict['min_time_between_warnings']) config_dict['min_time_between_warnings'])
@ -1124,48 +964,6 @@ else:
exit() exit()
mem_min_warnings_kb, mem_min_warnings_mb, mem_min_warnings_percent = calculate_percent('mem_min_warnings')
# if 'mem_min_warnings' in config_dict:
# mem_min_warnings = config_dict['mem_min_warnings']
# if mem_min_warnings.endswith('%'):
# # отбрасываем процент, получаем число
# mem_min_warnings_percent = mem_min_warnings[:-1].strip()
# # далее флоат тест
# mem_min_warnings_percent = string_to_float_convert_test(mem_min_warnings_percent)
# if mem_min_warnings_percent is None:
# print('Invalid mem_min_warnings value, not float\nExit')
# exit()
# # окончательная валидация
# if mem_min_warnings_percent < 0 or mem_min_warnings_percent > 100:
# print('mem_min_warnings, выраженный в процентах, должен быть быть в диапазоне [0; 100]\nExit')
# exit()
# # mem_min_warnings_percent это теперь чистое валидное флоат число процентов, можно переводить в кб
# mem_min_warnings_kb = mem_min_warnings_percent / 100 * mem_total
# mem_min_warnings_mb = round(mem_min_warnings_kb / 1024)
# elif mem_min_warnings.endswith('M'):
# mem_min_warnings_mb = string_to_float_convert_test(mem_min_warnings[:-1].strip())
# if mem_min_warnings_mb is None:
# print('Invalid mem_min_warnings value, not float\nExit')
# exit()
# mem_min_warnings_kb = mem_min_warnings_mb * 1024
# if mem_min_warnings_kb > mem_total:
# print('mem_min_warnings value не должен быть больше MemTotal ({} MiB)\nExit'.format(round(mem_total / 1024)))
# exit()
# mem_min_warnings_percent = mem_min_warnings_kb / mem_total * 100
# else:
# print('Конфиг инвалид, для mem_min_warnings неверно указаны единицы измерения\nExit')
# exit()
# else:
# print('mem_min_warnings not in config\nExit')
# exit()
# НА МЕСТЕ!!! # НА МЕСТЕ!!!
if 'swap_min_warnings' in config_dict: if 'swap_min_warnings' in config_dict:
swap_min_warnings = config_dict['swap_min_warnings'] swap_min_warnings = config_dict['swap_min_warnings']
@ -1174,60 +972,16 @@ else:
exit() exit()
zram_max_warnings_kb, zram_max_warnings_mb, zram_max_warnings_percent = calculate_percent('zram_max_warnings')
# if 'zram_max_warnings' in config_dict:
# zram_max_warnings = config_dict['zram_max_warnings']
# if zram_max_warnings.endswith('%'):
# # отбрасываем процент, получаем число
# zram_max_warnings_percent = zram_max_warnings[:-1].strip()
# # далее флоат тест
# zram_max_warnings_percent = string_to_float_convert_test(zram_max_warnings_percent)
# if zram_max_warnings_percent is None:
# print('Invalid zram_max_warnings value, not float\nExit')
# exit()
# # окончательная валидация
# if zram_max_warnings_percent < 0 or zram_max_warnings_percent > 100:
# print('zram_max_warnings, выраженный в процентах, должен быть быть в диапазоне [0; 100]\nExit')
# exit()
# # zram_max_warnings_percent это теперь чистое валидное флоат число процентов, можно переводить в кб
# zram_max_warnings_kb = zram_max_warnings_percent / 100 * mem_total
# zram_max_warnings_mb = round(zram_max_warnings_kb / 1024)
# elif zram_max_warnings.endswith('M'):
# zram_max_warnings_mb = string_to_float_convert_test(zram_max_warnings[:-1].strip())
# if zram_max_warnings_mb is None:
# print('Invalid zram_max_warnings value, not float\nExit')
# exit()
# zram_max_warnings_kb = zram_max_warnings_mb * 1024
# if zram_max_warnings_kb > mem_total:
# print('zram_max_warnings value не должен быть больше MemTotal ({} MiB)\nExit'.format(round(mem_total / 1024)))
# exit()
# zram_max_warnings_percent = zram_max_warnings_kb / mem_total * 100
# else:
# print('Конфиг инвалид, для zram_max_warnings неверно указаны единицы измерения\nExit')
# exit()
# else:
# print('zram_max_warnings not in config\nExit')
# exit()
execute_the_command = conf_parse_bool('execute_the_command')
########################################################################## ##########################################################################
# Get Kibibytes levels # Get Kibibytes levels
# Returns Kilobytes value if absolute value was set in config, # Returns Kibibytes value if absolute value was set in config,
# or tuple with percentage # or tuple with percentage
def sig_level_to_kb_swap(string): def sig_level_to_kb_swap(string):
"""Returns Kilobytes value if abs val was set in config, or tuple with %""" """Returns Kibibytes value if abs val was set in config, or tuple with %"""
if string.endswith('%'): if string.endswith('%'):
return float(string[:-1].strip()), True return float(string[:-1].strip()), True
elif string.endswith('M'): elif string.endswith('M'):
@ -1271,6 +1025,9 @@ else:
# self-defense # self-defense
# возожно стоит убрать поддержку mlockall и ionice
# Increase priority # Increase priority
try: try:
os.nice(niceness) os.nice(niceness)
@ -1285,11 +1042,9 @@ try:
file.write('{}\n'.format(oom_score_adj)) file.write('{}\n'.format(oom_score_adj))
oom_score_adj_result = 'OK' oom_score_adj_result = 'OK'
except PermissionError: except PermissionError:
pass
oom_score_adj_result = 'Fail' oom_score_adj_result = 'Fail'
except OSError: except OSError:
oom_score_adj_result = 'Fail' oom_score_adj_result = 'Fail'
pass
# Deny process swapping # Deny process swapping
if mlockall: if mlockall:
@ -1324,7 +1079,8 @@ if root and realtime_ionice:
if print_config: if print_config:
print('\n1. Memory levels to respond to as an OOM threat\n[displaying these options need fix]\n') print(
'\n1. Memory levels to respond to as an OOM threat\n[displaying these options need fix]\n')
print('mem_min_sigterm: {} MiB, {} %'.format( print('mem_min_sigterm: {} MiB, {} %'.format(
round(mem_min_sigterm_mb), round(mem_min_sigterm_percent, 1))) round(mem_min_sigterm_mb), round(mem_min_sigterm_percent, 1)))
@ -1386,7 +1142,8 @@ if print_config:
print('zram_max_warnings: {} MiB, {} %'.format( print('zram_max_warnings: {} MiB, {} %'.format(
round(zram_max_warnings_mb), round(zram_max_warnings_percent, 1))) round(zram_max_warnings_mb), round(zram_max_warnings_percent, 1)))
print('\n7. Preventing the slowing down of the program\n[displaying these options need fix]\n') print(
'\n7. Preventing the slowing down of the program\n[displaying these options need fix]\n')
print('mlockall: {} ({})'.format(mlockall, mla_res)) print('mlockall: {} ({})'.format(mlockall, mla_res))
print('niceness: {} ({})'.format( print('niceness: {} ({})'.format(
niceness, niceness_result niceness, niceness_result
@ -1433,6 +1190,9 @@ warn_timer = 0
print('Monitoring started!') print('Monitoring started!')
########################################################################## ##########################################################################
@ -1461,6 +1221,7 @@ while True:
if swap_warn_is_percent: if swap_warn_is_percent:
swap_min_warnings_kb = swap_total * swap_min_warnings_percent / 100.0 swap_min_warnings_kb = swap_total * swap_min_warnings_percent / 100.0
# find MemUsedZram # find MemUsedZram
disksize_sum = 0 disksize_sum = 0
mem_used_total_sum = 0 mem_used_total_sum = 0
@ -1469,10 +1230,24 @@ while True:
stat = zram_stat(dev) stat = zram_stat(dev)
disksize_sum += int(stat[0]) disksize_sum += int(stat[0])
mem_used_total_sum += int(stat[1]) mem_used_total_sum += int(stat[1])
# Означает, что при задани zram disksize = 10000M доступная память
# уменьшится на 42 MiB.
# Найден экспериментально, требует уточнения с разными ядрами и архитектурами.
# На небольших дисксайзах (до гигабайта) может быть больше, до 0.0045.
# Создатель модуля zram утверждает, что zram_disksize_factor доожен быть 0.001
# ("zram uses about 0.1% of the size of the disk"
# - https://www.kernel.org/doc/Documentation/blockdev/zram.txt),
# но это утверждение противоречит опытным данным.
# zram_disksize_factor = deltaMemAvailavle / disksize
# found experimentally
zram_disksize_factor = 0.0042
mem_used_zram = ( mem_used_zram = (
mem_used_total_sum + disksize_sum * zram_disksize_factor mem_used_total_sum + disksize_sum * zram_disksize_factor
) / 1024.0 ) / 1024.0
if print_mem_check_results: if print_mem_check_results:
# Calculate 'swap-column' width # Calculate 'swap-column' width
@ -1512,6 +1287,7 @@ while True:
else: else:
# СТОИТ ПЕЧАТАТЬ СВОП ТОЛЬКО ПРИ SwapTotal > 0 # СТОИТ ПЕЧАТАТЬ СВОП ТОЛЬКО ПРИ SwapTotal > 0
# нет, печатать так: SwapTotal = 0 KiB, ignore swapspace
swap_sigterm_pc = '-' swap_sigterm_pc = '-'
# Limits overdrafting checks # Limits overdrafting checks
@ -1592,7 +1368,8 @@ while True:
# LOW MEMORY WARNINGS # LOW MEMORY WARNINGS
elif gui_low_memory_warnings: elif gui_low_memory_warnings:
if mem_available <= mem_min_warnings_kb and swap_free <= swap_min_warnings_kb + 0.1 or mem_used_zram >= zram_max_warnings_kb: if mem_available <= mem_min_warnings_kb and swap_free <= swap_min_warnings_kb + \
0.1 or mem_used_zram >= zram_max_warnings_kb:
warn_time_delta = time() - warn_time_now warn_time_delta = time() - warn_time_now
warn_time_now = time() warn_time_now = time()
warn_timer += warn_time_delta warn_timer += warn_time_delta
@ -1603,7 +1380,5 @@ while True:
# SLEEP BETWEEN MEM CHECKS # SLEEP BETWEEN MEM CHECKS
else: else:
stdout.flush() stdout.flush()
sleep_after_check_mem() sleep_after_check_mem()