choom: new command to adjust OOM-killer score value
Let's provide command line tool, man page with OOM description and bash-completion. It seems better than force end-users to use "echo" to /proc. Addresses: https://github.com/karelzak/util-linux/issues/609 Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
6ceb17c8a7
commit
8fa223daba
|
@ -71,6 +71,7 @@ ylwrap
|
|||
/cfdisk
|
||||
/chcpu
|
||||
/chfn
|
||||
/choom
|
||||
/chmem
|
||||
/chrt
|
||||
/chsh
|
||||
|
|
|
@ -8,11 +8,6 @@ cal
|
|||
- support another --reforms, see for example freebsd version
|
||||
https://github.com/freebsd/freebsd/blob/master/usr.bin/ncal/ncal.c#L72
|
||||
|
||||
choom
|
||||
-----
|
||||
- add new tool to set/get process OOM setting
|
||||
https://github.com/karelzak/util-linux/issues/609
|
||||
|
||||
column
|
||||
------
|
||||
- add option to NOT ignore empty lines
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
_choom_module()
|
||||
{
|
||||
local cur prev OPTS
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
case $prev in
|
||||
'-n'|'--adjust')
|
||||
COMPREPLY=( $(compgen -W "{-1000..1000}" -- $cur) )
|
||||
return 0
|
||||
;;
|
||||
'-p'|'--pid')
|
||||
local PIDS
|
||||
PIDS=$(cd /proc && echo [0-9]*)
|
||||
COMPREPLY=( $(compgen -W "$PIDS" -- $cur) )
|
||||
return 0
|
||||
;;
|
||||
'-h'|'--help'|'-V'|'--version')
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
OPTS="--adjust
|
||||
--pid
|
||||
--help
|
||||
--version"
|
||||
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
|
||||
return 0
|
||||
}
|
||||
complete -F _choom_module choom
|
|
@ -1664,6 +1664,10 @@ AC_ARG_ENABLE([ipcs],
|
|||
UL_BUILD_INIT([ipcs])
|
||||
AM_CONDITIONAL([BUILD_IPCS], [test "x$build_ipcs" = xyes])
|
||||
|
||||
UL_BUILD_INIT([choom], [check])
|
||||
UL_REQUIRES_LINUX([choom])
|
||||
AM_CONDITIONAL([BUILD_CHOOM], [test "x$build_choom" = xyes])
|
||||
|
||||
UL_BUILD_INIT([lsipc], [check])
|
||||
UL_REQUIRES_LINUX([lsipc])
|
||||
UL_REQUIRES_BUILD([lsipc], [libsmartcols])
|
||||
|
|
|
@ -20,6 +20,13 @@ flock_SOURCES = sys-utils/flock.c lib/monotonic.c lib/timer.c
|
|||
flock_LDADD = $(LDADD) libcommon.la $(REALTIME_LIBS)
|
||||
endif
|
||||
|
||||
#if BUILD_CHOOM
|
||||
usrbin_exec_PROGRAMS += choom
|
||||
dist_man_MANS += sys-utils/choom.1
|
||||
choom_SOURCES = sys-utils/choom.c
|
||||
choom_LDADD = $(LDADD) libcommon.la
|
||||
#endif
|
||||
|
||||
if BUILD_IPCMK
|
||||
usrbin_exec_PROGRAMS += ipcmk
|
||||
dist_man_MANS += sys-utils/ipcmk.1
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
.TH CHOOM 1 "April 2018" "util-linux" "User Commands"
|
||||
.SH NAME
|
||||
choom \- display and adjust OOM-killer score.
|
||||
.SH SYNOPSIS
|
||||
.B choom
|
||||
.RB \-p
|
||||
.IR pid
|
||||
.sp
|
||||
.B choom
|
||||
.RB \-p
|
||||
.IR pid
|
||||
.RB \-n
|
||||
.IR number
|
||||
.sp
|
||||
.B choom
|
||||
.RB \-n
|
||||
.IR number
|
||||
.IR command\ [ argument ...]
|
||||
|
||||
.SH DESCRIPTION
|
||||
The \fBchoom\fP command displays and adjusts Out-Of-Memory killer score setting.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-p ", " \-\-pid " \fIpid\fP
|
||||
Specifies process ID.
|
||||
.TP
|
||||
.BR \-n , " \-\-adjust " \fIvalue\fP
|
||||
Specify the adjust score value.
|
||||
.TP
|
||||
.BR \-h ", " \-\-help
|
||||
Display help text and exit.
|
||||
.TP
|
||||
.BR \-V ", " \-\-version
|
||||
Display version information and exit.
|
||||
.SH NOTES
|
||||
Linux kernel uses the badness heuristic to select which process gets killed in
|
||||
out of memory conditions.
|
||||
|
||||
The badness heuristic assigns a value to each candidate task ranging from 0
|
||||
(never kill) to 1000 (always kill) to determine which process is targeted. The
|
||||
units are roughly a proportion along that range of allowed memory the process
|
||||
may allocate from based on an estimation of its current memory and swap use.
|
||||
For example, if a task is using all allowed memory, its badness score will be
|
||||
1000. If it is using half of its allowed memory, its score will be 500.
|
||||
|
||||
There is an additional factor included in the badness score: the current memory
|
||||
and swap usage is discounted by 3% for root processes.
|
||||
|
||||
The amount of "allowed" memory depends on the context in which the oom killer
|
||||
was called. If it is due to the memory assigned to the allocating task's cpuset
|
||||
being exhausted, the allowed memory represents the set of mems assigned to that
|
||||
cpuset. If it is due to a mempolicy's node(s) being exhausted, the allowed
|
||||
memory represents the set of mempolicy nodes. If it is due to a memory
|
||||
limit (or swap limit) being reached, the allowed memory is that configured
|
||||
limit. Finally, if it is due to the entire system being out of memory, the
|
||||
allowed memory represents all allocatable resources.
|
||||
|
||||
The adjust score value is added to the badness score before it is used to
|
||||
determine which task to kill. Acceptable values range from -1000 to +1000.
|
||||
This allows userspace to polarize the preference for oom killing either by
|
||||
always preferring a certain task or completely disabling it. The lowest
|
||||
possible value, -1000, is equivalent to disabling oom killing entirely for that
|
||||
task since it will always report a badness score of 0.
|
||||
|
||||
Setting a adjust score value of +500, for example, is roughly equivalent to
|
||||
allowing the remainder of tasks sharing the same system, cpuset, mempolicy, or
|
||||
memory controller resources to use at least 50% more memory. A value of -500,
|
||||
on the other hand, would be roughly equivalent to discounting 50% of the task's
|
||||
allowed memory from being considered as scoring against the task.
|
||||
|
||||
.SH AUTHORS
|
||||
.nf
|
||||
Karel Zak <kzak@redhat.com>
|
||||
.fi
|
||||
.SH SEE ALSO
|
||||
.BR proc (5)
|
||||
.SH AVAILABILITY
|
||||
The \fBchoom\fP command is part of the util-linux package and is available from
|
||||
.UR https://\:www.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
|
||||
Linux Kernel Archive
|
||||
.UE .
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* choom - Change OOM score setting
|
||||
*
|
||||
* Copyright (C) 2018 Karel Zak <kzak@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it would be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/oom.h>
|
||||
|
||||
#include "nls.h"
|
||||
#include "c.h"
|
||||
#include "path.h"
|
||||
#include "strutils.h"
|
||||
#include "closestream.h"
|
||||
|
||||
static void __attribute__((__noreturn__)) usage(void)
|
||||
{
|
||||
FILE *out = stdout;
|
||||
fputs(USAGE_HEADER, out);
|
||||
fprintf(out,
|
||||
_(" %1$s [options] -p pid\n"
|
||||
" %1$s [options] -n number -p pid\n"
|
||||
" %1$s [options] -n number command [args...]]\n"),
|
||||
program_invocation_short_name);
|
||||
|
||||
fputs(USAGE_SEPARATOR, out);
|
||||
fputs(_("Display and adjust OOM-killer score.\n"), out);
|
||||
|
||||
fputs(USAGE_OPTIONS, out);
|
||||
fputs(_(" -n, --adjust <num> specify the adjust score value\n"), out);
|
||||
fputs(_(" -p, --pid <num> process ID\n"), out);
|
||||
fputs(USAGE_SEPARATOR, out);
|
||||
printf(USAGE_HELP_OPTIONS(24));
|
||||
printf(USAGE_MAN_TAIL("choom(1)"));
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int get_score(const pid_t pid)
|
||||
{
|
||||
return path_read_s32("/proc/%d/oom_score", (int) pid);
|
||||
}
|
||||
|
||||
static int get_score_adj(const pid_t pid)
|
||||
{
|
||||
return path_read_s32("/proc/%d/oom_score_adj", (int) pid);
|
||||
}
|
||||
|
||||
static int set_score_adj(const pid_t pid, int adj)
|
||||
{
|
||||
char buf[sizeof(stringify_value(OOM_SCORE_ADJ_MIN))];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", adj);
|
||||
|
||||
if (path_write_str(buf, "/proc/%d/oom_score_adj", (int) pid) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
int c, adj = 0, has_adj = 0;
|
||||
|
||||
static const struct option longopts[] = {
|
||||
{ "adjust", required_argument, NULL, 'n' },
|
||||
{ "pid", required_argument, NULL, 'p' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
atexit(close_stdout);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hn:p:V", longopts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'p':
|
||||
pid = strtos32_or_err(optarg, _("invalid PID argument"));
|
||||
break;
|
||||
case 'n':
|
||||
adj = strtos32_or_err(optarg, _("invalid adjust argument"));
|
||||
has_adj = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf(UTIL_LINUX_VERSION);
|
||||
return EXIT_SUCCESS;
|
||||
case 'h':
|
||||
usage();
|
||||
default:
|
||||
errtryhelp(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc && pid) {
|
||||
warnx(_("invalid argument: %s"), argv[optind]);
|
||||
errtryhelp(EXIT_FAILURE);
|
||||
}
|
||||
if (!pid && argc - optind < 1) {
|
||||
warnx(_("no PID or COMMAND specified"));
|
||||
errtryhelp(EXIT_FAILURE);
|
||||
}
|
||||
if (optind < argc && !has_adj) {
|
||||
warnx(_("no OOM score adjust value specified"));
|
||||
errtryhelp(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Show */
|
||||
if (!has_adj) {
|
||||
printf(_("pid %d's current OOM score: %d\n"), pid, get_score(pid));
|
||||
printf(_("pid %d's current OOM score adjust value: %d\n"), pid, get_score_adj(pid));
|
||||
|
||||
/* Change */
|
||||
} else if (pid) {
|
||||
int old = get_score_adj(pid);
|
||||
|
||||
if (set_score_adj(pid, adj))
|
||||
err(EXIT_FAILURE, _("failed to set score adjust value"));
|
||||
|
||||
printf(_("pid %d's OOM score adjust value changed from %d to %d\n"), pid, old, adj);
|
||||
|
||||
/* Start new process */
|
||||
} else {
|
||||
argv += optind;
|
||||
execvp(argv[0], argv);
|
||||
errexec(argv[0]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue