add --check-config

This commit is contained in:
Alexey Avramov 2019-07-14 10:30:25 +09:00
parent cfea9eef8a
commit 35a7e03db9
3 changed files with 205 additions and 190 deletions

View File

@ -120,7 +120,7 @@ $ sudo systemctl enable nohang
``` ```
./nohang -h ./nohang -h
usage: nohang [-h] [-v] [-t] [-p] [-c CONFIG] usage: nohang [-h] [-v] [-p] [-c CONFIG]
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@ -130,6 +130,8 @@ optional arguments:
-c CONFIG, --config CONFIG -c CONFIG, --config CONFIG
path to the config file, default values: path to the config file, default values:
./nohang.conf, /etc/nohang/nohang.conf ./nohang.conf, /etc/nohang/nohang.conf
-cc CONFIG, --check-config CONFIG
ckeck and print config
``` ```
## How to configure nohang ## How to configure nohang
@ -274,34 +276,6 @@ Process with highest badness (found in 55 ms):
</details> </details>
## Logging ## Logging
To view the latest entries in the log (for systemd users): To view the latest entries in the log (for systemd users):
@ -314,14 +288,6 @@ See also `man journalctl`.
You can also enable `separate_log` in the config to logging in `/var/log/nohang/nohang.log`. You can also enable `separate_log` in the config to logging in `/var/log/nohang/nohang.log`.
## Additional tools: oom-sort, psi-top, psi-monitor, i-memhog ## Additional tools: oom-sort, psi-top, psi-monitor, i-memhog

348
nohang
View File

@ -16,6 +16,180 @@ from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP
# define functions # define functions
def check_config():
"""
"""
log('#' * 79)
log('0. Common zram settings')
log(' ignore_zram: {}'.format(ignore_zram))
log('1. Thresholds below which a signal should be sent to the victim')
log(' mem_min_sigterm: {} MiB, {} %'.format(
round(mem_min_sigterm_mb), round(mem_min_sigterm_percent, 1)))
log(' mem_min_sigkill: {} MiB, {} %'.format(
round(mem_min_sigkill_mb), round(mem_min_sigkill_percent, 1)))
log(' swap_min_sigterm: {}'.format(swap_min_sigterm))
log(' swap_min_sigkill: {}'.format(swap_min_sigkill))
log(' zram_max_sigterm: {} MiB, {} %'.format(
round(zram_max_sigterm_mb), round(zram_max_sigterm_percent, 1)))
log(' zram_max_sigkill: {} MiB, {} %'.format(
round(zram_max_sigkill_mb), round(zram_max_sigkill_percent, 1)))
log('2. Response on PSI memory metrics')
log(' ignore_psi: {}'.format(ignore_psi))
log(' psi_path: {}'.format(psi_path))
log(' psi_metrics: {}'.format(psi_metrics))
log(' sigterm_psi_threshold: {}'.format(sigterm_psi_threshold))
log(' sigkill_psi_threshold: {}'.format(sigkill_psi_threshold))
log(' psi_excess_duration: {} sec'.format(psi_excess_duration))
log(' psi_post_action_delay: {} sec'.format(psi_post_action_delay))
log('3. The frequency of checking the amount of available memory')
log(' rate_mem: {}'.format(rate_mem))
log(' rate_swap: {}'.format(rate_swap))
log(' rate_zram: {}'.format(rate_zram))
log(' max_sleep: {} sec'.format(max_sleep))
log(' min_sleep: {} sec'.format(min_sleep))
log(' over_sleep: {} sec'.format(over_sleep))
log('4. The prevention of killing innocent victims')
log(' min_badness: {}'.format(min_badness))
log(' min_delay_after_sigterm: {} sec'.format(min_delay_after_sigterm))
log(' post_zombie_delay: {} sec'.format(post_zombie_delay))
log(' victim_cache_time: {} sec'.format(victim_cache_time))
log(' decrease_oom_score_adj: {}'.format(decrease_oom_score_adj))
log(' oom_score_adj_max: {}'.format(oom_score_adj_max))
log('5. Impact on the badness of processes')
log('5.1. Matching process names with RE patterns')
if len(badness_adj_re_name_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_name_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.2. Matching CGroup_v1-line with RE patterns')
if len(badness_adj_re_cgroup_v1_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_cgroup_v1_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.3. Matching CGroup_v2-line with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_cgroup_v1_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.4. Matching eUIDs with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_uid_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.5. Matching realpath with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_realpath_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.6. Matching cmdlines with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_cmdline_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.7. Matching environ with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_environ_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('6. Customize corrective actions')
if len(soft_actions_list) > 0:
log(' Match by: regexp: command: ')
for i in soft_actions_list:
log(' {} {} {}'.format(i[0], i[1], i[2]))
else:
log(' (not set)')
log('7. GUI notifications')
log(' gui_notifications: {}'.format(gui_notifications))
log(' gui_low_memory_warnings: {}'.format(gui_low_memory_warnings))
log(' warning_exe: {}'.format(warning_exe))
log(' mem_min_warnings: {} MiB, {} %'.format(
round(mem_min_warnings_mb), round(mem_min_warnings_percent, 1)))
log(' swap_min_warnings: {}'.format(swap_min_warnings))
log(' zram_max_warnings: {} MiB, {} %'.format(
round(zram_max_warnings_mb), round(zram_max_warnings_percent, 1)))
log(' psi_avg_warnings: {}'.format(psi_avg_warnings))
log(' min_time_between_warnings: {} sec'.format(
min_time_between_warnings))
log('8. Verbosity')
log(' print_config: {}'.format(print_config))
log(' print_mem_check_results: {}'.format(print_mem_check_results))
log(' min_mem_report_interval: {} sec'.format(min_mem_report_interval))
log(' print_sleep_periods: {}'.format(print_sleep_periods))
log(' print_total_stat: {}'.format(print_total_stat))
log(' print_proc_table: {}'.format(print_proc_table))
log(' extra_table_info: {}'.format(extra_table_info))
log(' print_victim_info: {}'.format(print_victim_info))
log(' print_victim_cmdline: {}'.format(print_victim_cmdline))
log(' max_ancestry_depth: {}'.format(max_ancestry_depth))
log(' debug_gui_notifications: {}'.format(debug_gui_notifications))
log(' separate_log: {}'.format(separate_log))
log(' psi_debug: {}'.format(psi_debug))
log('9. Misc')
log(' max_post_sigterm_victim_lifetime: {} sec'.format(
max_post_sigterm_victim_lifetime))
log(' post_kill_exe: {}'.format(post_kill_exe))
log(' forbid_negative_badness: {}'.format(
forbid_negative_badness))
# log(': {}'.format())
log('#' * 79)
if check_config_flag:
log('config is OK')
exit()
def encoder(string): def encoder(string):
""" """
""" """
@ -2032,7 +2206,7 @@ v_dict = dict()
start_time = time() start_time = time()
help_mess = """usage: nohang [-h] [-v] [-t] [-p] [-c CONFIG] help_mess = """usage: nohang [-h] [-v] [-p] [-c CONFIG] [-cc CONFIG]
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@ -2041,7 +2215,9 @@ optional arguments:
print table of processes with their badness values print table of processes with their badness values
-c CONFIG, --config CONFIG -c CONFIG, --config CONFIG
path to the config file, default values: path to the config file, default values:
./nohang.conf, /etc/nohang/nohang.conf""" ./nohang.conf, /etc/nohang/nohang.conf
-cc CONFIG, --check-config CONFIG
ckeck and print config"""
SC_CLK_TCK = os.sysconf(os.sysconf_names['SC_CLK_TCK']) SC_CLK_TCK = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
@ -2098,16 +2274,26 @@ pid_list = get_pid_list()
print_proc_table_flag = False print_proc_table_flag = False
if len(argv) == 1: check_config_flag = False
if os.path.exists('./nohang.conf'):
if os.path.exists('./nohang.conf'):
config = os.getcwd() + '/nohang.conf' config = os.getcwd() + '/nohang.conf'
else: else:
config = '/etc/nohang/nohang.conf' config = '/etc/nohang/nohang.conf'
if len(argv) == 1:
pass
elif len(argv) == 2: elif len(argv) == 2:
if argv[1] == '--help' or argv[1] == '-h': if argv[1] == '--help' or argv[1] == '-h':
print(help_mess) print(help_mess)
exit() exit()
elif argv[1] == '--check-config' or argv[1] == '-cc':
check_config_flag = True
elif argv[1] == '--version' or argv[1] == '-v': elif argv[1] == '--version' or argv[1] == '-v':
print_version() print_version()
elif argv[1] == '--print-proc-table' or argv[1] == '-p': elif argv[1] == '--print-proc-table' or argv[1] == '-p':
@ -2119,14 +2305,15 @@ elif len(argv) == 2:
else: else:
errprint('Unknown option: {}'.format(argv[1])) errprint('Unknown option: {}'.format(argv[1]))
exit(1) exit(1)
elif len(argv) == 3: elif len(argv) == 3:
if argv[1] == '--config' or argv[1] == '-c': if argv[1] == '--config' or argv[1] == '-c':
config = argv[2] config = argv[2]
elif argv[1] == '--check-config' or argv[1] == '-cc':
config = argv[2]
check_config_flag = True
else: else:
errprint('Unknown option: {}'.format(argv[1])) errprint('Unknown option: {}'.format(argv[1]))
exit(1) exit(1)
else: else:
errprint('Invalid CLI input: too many options') errprint('Invalid CLI input: too many options')
exit(1) exit(1)
@ -2179,7 +2366,7 @@ except ValueError:
# print('It is not Linux 4.5+') # print('It is not Linux 4.5+')
log('Config: ' + config) log('config: ' + config)
########################################################################## ##########################################################################
@ -2888,164 +3075,23 @@ else:
########################################################################## ##########################################################################
if print_config:
log('#' * 79)
log('0. Common zram settings')
log(' ignore_zram: {}'.format(ignore_zram))
log('1. Thresholds below which a signal should be sent to the victim')
log(' mem_min_sigterm: {} MiB, {} %'.format(
round(mem_min_sigterm_mb), round(mem_min_sigterm_percent, 1)))
log(' mem_min_sigkill: {} MiB, {} %'.format(
round(mem_min_sigkill_mb), round(mem_min_sigkill_percent, 1)))
log(' swap_min_sigterm: {}'.format(swap_min_sigterm))
log(' swap_min_sigkill: {}'.format(swap_min_sigkill))
log(' zram_max_sigterm: {} MiB, {} %'.format( if print_config or check_config_flag:
round(zram_max_sigterm_mb), round(zram_max_sigterm_percent, 1))) check_config()
log(' zram_max_sigkill: {} MiB, {} %'.format(
round(zram_max_sigkill_mb), round(zram_max_sigkill_percent, 1)))
log('2. Response on PSI memory metrics')
log(' ignore_psi: {}'.format(ignore_psi))
log(' psi_path: {}'.format(psi_path))
log(' psi_metrics: {}'.format(psi_metrics))
log(' sigterm_psi_threshold: {}'.format(sigterm_psi_threshold))
log(' sigkill_psi_threshold: {}'.format(sigkill_psi_threshold))
log(' psi_excess_duration: {} sec'.format(psi_excess_duration))
log(' psi_post_action_delay: {} sec'.format(psi_post_action_delay))
log('3. The frequency of checking the amount of available memory')
log(' rate_mem: {}'.format(rate_mem))
log(' rate_swap: {}'.format(rate_swap))
log(' rate_zram: {}'.format(rate_zram))
log(' max_sleep: {} sec'.format(max_sleep))
log(' min_sleep: {} sec'.format(min_sleep))
log(' over_sleep: {} sec'.format(over_sleep))
log('4. The prevention of killing innocent victims')
log(' min_badness: {}'.format(min_badness))
log(' min_delay_after_sigterm: {} sec'.format(min_delay_after_sigterm))
log(' post_zombie_delay: {} sec'.format(post_zombie_delay))
log(' victim_cache_time: {} sec'.format(victim_cache_time))
log(' decrease_oom_score_adj: {}'.format(decrease_oom_score_adj))
log(' oom_score_adj_max: {}'.format(oom_score_adj_max))
log('5. Impact on the badness of processes')
log('5.1. Matching process names with RE patterns')
if len(badness_adj_re_name_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_name_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.2. Matching CGroup_v1-line with RE patterns')
if len(badness_adj_re_cgroup_v1_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_cgroup_v1_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.3. Matching CGroup_v2-line with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_cgroup_v1_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.4. Matching eUIDs with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_uid_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.5. Matching realpath with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_realpath_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.6. Matching cmdlines with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_cmdline_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('5.7. Matching environ with RE patterns')
if len(badness_adj_re_cgroup_v2_list) > 0:
log(' regexp: badness_adj:')
for i in badness_adj_re_environ_list:
log(' {} {}'.format(i[1], i[0]))
else:
log(' (not set)')
log('6. Customize corrective actions')
if len(soft_actions_list) > 0:
log(' Match by: regexp: command: ')
for i in soft_actions_list:
log(' {} {} {}'.format(i[0], i[1], i[2]))
else:
log(' (not set)')
log('7. GUI notifications')
log(' gui_notifications: {}'.format(gui_notifications))
log(' gui_low_memory_warnings: {}'.format(gui_low_memory_warnings))
log(' warning_exe: {}'.format(warning_exe))
log(' mem_min_warnings: {} MiB, {} %'.format(
round(mem_min_warnings_mb), round(mem_min_warnings_percent, 1)))
log(' swap_min_warnings: {}'.format(swap_min_warnings))
log(' zram_max_warnings: {} MiB, {} %'.format(
round(zram_max_warnings_mb), round(zram_max_warnings_percent, 1)))
log(' psi_avg_warnings: {}'.format(psi_avg_warnings))
log(' min_time_between_warnings: {} sec'.format(
min_time_between_warnings))
log('8. Verbosity')
log(' print_config: {}'.format(print_config))
log(' print_mem_check_results: {}'.format(print_mem_check_results))
log(' min_mem_report_interval: {} sec'.format(min_mem_report_interval))
log(' print_sleep_periods: {}'.format(print_sleep_periods))
log(' print_total_stat: {}'.format(print_total_stat))
log(' print_proc_table: {}'.format(print_proc_table))
log(' extra_table_info: {}'.format(extra_table_info))
log(' print_victim_info: {}'.format(print_victim_info))
log(' print_victim_cmdline: {}'.format(print_victim_cmdline))
log(' max_ancestry_depth: {}'.format(max_ancestry_depth))
log(' debug_gui_notifications: {}'.format(debug_gui_notifications))
log(' separate_log: {}'.format(separate_log))
log(' psi_debug: {}'.format(psi_debug))
log('9. Misc')
log(' max_post_sigterm_victim_lifetime: {} sec'.format(
max_post_sigterm_victim_lifetime))
log(' post_kill_exe: {}'.format(post_kill_exe))
log(' forbid_negative_badness: {}'.format(
forbid_negative_badness))
# log(': {}'.format())
log('#' * 79)
########################################################################## ##########################################################################

View File

@ -45,6 +45,9 @@ Nohang is a highly configurable daemon for Linux which is able to correctly prev
path to the config file, default values: path to the config file, default values:
./nohang.conf, /etc/nohang/nohang.conf ./nohang.conf, /etc/nohang/nohang.conf
-cc CONFIG, --check-config CONFIG
ckeck and print config
.SH HOW TO CONFIGURE .SH HOW TO CONFIGURE
The program can be configured by editing the config file. The program can be configured by editing the config file.