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
usage: nohang [-h] [-v] [-t] [-p] [-c CONFIG]
usage: nohang [-h] [-v] [-p] [-c CONFIG]
optional arguments:
-h, --help show this help message and exit
@ -130,6 +130,8 @@ optional arguments:
-c CONFIG, --config CONFIG
path to the config file, default values:
./nohang.conf, /etc/nohang/nohang.conf
-cc CONFIG, --check-config CONFIG
ckeck and print config
```
## How to configure nohang
@ -274,34 +276,6 @@ Process with highest badness (found in 55 ms):
</details>
## Logging
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`.
## Additional tools: oom-sort, psi-top, psi-monitor, i-memhog

352
nohang
View File

@ -16,6 +16,180 @@ from signal import signal, SIGKILL, SIGTERM, SIGINT, SIGQUIT, SIGHUP
# 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):
"""
"""
@ -2032,7 +2206,7 @@ v_dict = dict()
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:
-h, --help show this help message and exit
@ -2041,7 +2215,9 @@ optional arguments:
print table of processes with their badness values
-c CONFIG, --config CONFIG
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'])
@ -2098,16 +2274,26 @@ pid_list = get_pid_list()
print_proc_table_flag = False
if len(argv) == 1:
if os.path.exists('./nohang.conf'):
config = os.getcwd() + '/nohang.conf'
else:
config = '/etc/nohang/nohang.conf'
check_config_flag = False
if os.path.exists('./nohang.conf'):
config = os.getcwd() + '/nohang.conf'
else:
config = '/etc/nohang/nohang.conf'
if len(argv) == 1:
pass
elif len(argv) == 2:
if argv[1] == '--help' or argv[1] == '-h':
print(help_mess)
exit()
elif argv[1] == '--check-config' or argv[1] == '-cc':
check_config_flag = True
elif argv[1] == '--version' or argv[1] == '-v':
print_version()
elif argv[1] == '--print-proc-table' or argv[1] == '-p':
@ -2119,14 +2305,15 @@ elif len(argv) == 2:
else:
errprint('Unknown option: {}'.format(argv[1]))
exit(1)
elif len(argv) == 3:
if argv[1] == '--config' or argv[1] == '-c':
config = argv[2]
elif argv[1] == '--check-config' or argv[1] == '-cc':
config = argv[2]
check_config_flag = True
else:
errprint('Unknown option: {}'.format(argv[1]))
exit(1)
else:
errprint('Invalid CLI input: too many options')
exit(1)
@ -2179,7 +2366,7 @@ except ValueError:
# 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(
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)))
if print_config or check_config_flag:
check_config()
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:
./nohang.conf, /etc/nohang/nohang.conf
-cc CONFIG, --check-config CONFIG
ckeck and print config
.SH HOW TO CONFIGURE
The program can be configured by editing the config file.