Skip to content

Commit

Permalink
find proccess with largest rss (#300)
Browse files Browse the repository at this point in the history
* show the cmdline of the process which was sent SIGKILL or SIGTERMIGTERM

* add cmdline to struct procinfo

* add test code

* add 'get-cmdline' to args

* add env EARLYOOM_CMDLINE in notify_ext()

* delete the flag -get-cmdline; fix some log message

* delete get_cmdline from struct poll_loop_args_t

* add env EARLYOOM_CMDLINE to MANPAGE.md

* add get_cmdline to the end of function is_larger

* add build.sh

* static build with version

* To get the latest tag using git command

* add flag '--sort-by-rss': find process with the largest rss (default oom_score)

* reset Makefile and delete build.sh

* delete ignore-root-user from MANPAGE.md

* delete duplicate code

* make --avoid / --prefer work with --sort-by-rss

* add VMRSS_PREFER and VMRSS_AVOID to support prefer_regex and avoid_regex
  • Loading branch information
RanHuang authored Oct 11, 2023
1 parent dc86399 commit 90f1a67
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 17 deletions.
3 changes: 3 additions & 0 deletions MANPAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ that might have occurred due to the processes attaining a high oom_score.
Use this option with caution as other processes might be sacrificed in place of the ignored
processes when earlyoom determines to kill processes.

### \-\-sort-by-rss
find process with the largest rss (default oom_score)

#### \-\-dryrun
dry run (do not kill any processes)

Expand Down
58 changes: 42 additions & 16 deletions kill.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
// Processes matching "--avoid REGEX" get BADNESS_AVOID added to their badness
#define BADNESS_AVOID -300

// Processes matching "--prefer REGEX" get VMRSS_PREFER added to their VmRSSkiB
#define VMRSS_PREFER 3145728
// Processes matching "--avoid REGEX" get VMRSS_AVOID added to their VmRSSkiB
#define VMRSS_AVOID -3145728

// Buffer size for UID/GID/PID string conversion
#define UID_BUFSIZ 128
// At most 1 notification per second when --dryrun is active
Expand Down Expand Up @@ -289,42 +294,63 @@ bool is_larger(const poll_loop_args_t* args, const procinfo_t* victim, procinfo_
cur->badness = res;
}

{
long long res = get_vm_rss_kib(cur->pid);
if (res < 0) {
debug("pid %d: error reading rss: %s\n", cur->pid, strerror((int)-res));
return false;
}
cur->VmRSSkiB = res;
}

if ((args->prefer_regex || args->avoid_regex || args->ignore_regex)) {
int res = get_comm(cur->pid, cur->name, sizeof(cur->name));
if (res < 0) {
debug("pid %d: error reading process name: %s\n", cur->pid, strerror(-res));
return false;
}
if (args->prefer_regex && regexec(args->prefer_regex, cur->name, (size_t)0, NULL, 0) == 0) {
cur->badness += BADNESS_PREFER;
if (args->sort_by_rss) {
cur->VmRSSkiB += VMRSS_PREFER;
} else {
cur->badness += BADNESS_PREFER;
}
}
if (args->avoid_regex && regexec(args->avoid_regex, cur->name, (size_t)0, NULL, 0) == 0) {
cur->badness += BADNESS_AVOID;
if (args->sort_by_rss) {
cur->VmRSSkiB += VMRSS_AVOID;
} else {
cur->badness += BADNESS_AVOID;
}
}
if (args->ignore_regex && regexec(args->ignore_regex, cur->name, (size_t)0, NULL, 0) == 0) {
return false;
}
}

if (cur->badness < victim->badness) {
if (cur->VmRSSkiB == 0) {
// Kernel threads have zero rss
return false;
}

{
long long res = get_vm_rss_kib(cur->pid);
if (res < 0) {
debug("pid %d: error reading rss: %s\n", cur->pid, strerror((int)-res));
if (args->sort_by_rss) {
/* find process with the largest rss */
if (cur->VmRSSkiB < victim->VmRSSkiB) {
return false;
}
cur->VmRSSkiB = res;
}

if (cur->VmRSSkiB == 0) {
// Kernel threads have zero rss
return false;
}
if (cur->badness == victim->badness && cur->VmRSSkiB <= victim->VmRSSkiB) {
return false;
if (cur->VmRSSkiB == victim->VmRSSkiB && cur->badness <= victim->badness) {
return false;
}
} else {
/* find process with the largest oom_score */
if (cur->badness < victim->badness) {
return false;
}

if (cur->badness == victim->badness && cur->VmRSSkiB <= victim->VmRSSkiB) {
return false;
}
}

// Skip processes with oom_score_adj = -1000, like the
Expand Down Expand Up @@ -371,7 +397,7 @@ void debug_print_procinfo(const procinfo_t* cur)
}

/*
* Find the process with the largest oom_score.
* Find the process with the largest oom_score or rss(when flag --sort-by-rss is set).
*/
procinfo_t find_largest_process(const poll_loop_args_t* args)
{
Expand Down
2 changes: 2 additions & 0 deletions kill.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ typedef struct {
bool kill_process_group;
/* do not kill processes owned by root */
bool ignore_root_user;
/* find process with the largest rss */
bool sort_by_rss;
/* prefer/avoid killing these processes. NULL = no-op. */
regex_t* prefer_regex;
regex_t* avoid_regex;
Expand Down
8 changes: 8 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum {
LONG_OPT_IGNORE,
LONG_OPT_IGNORE_ROOT,
LONG_OPT_USE_SYSLOG,
LONG_OPT_SORT_BY_RSS,
};

static int set_oom_score_adj(int);
Expand Down Expand Up @@ -89,6 +90,7 @@ int main(int argc, char* argv[])
.swap_kill_percent = 5,
.report_interval_ms = 1000,
.ignore_root_user = false,
.sort_by_rss = false,
/* omitted fields are set to zero */
};
int set_my_priority = 0;
Expand Down Expand Up @@ -131,6 +133,7 @@ int main(int argc, char* argv[])
{ "ignore", required_argument, NULL, LONG_OPT_IGNORE },
{ "dryrun", no_argument, NULL, LONG_OPT_DRYRUN },
{ "ignore-root-user", no_argument, NULL, LONG_OPT_IGNORE_ROOT },
{ "sort-by-rss", no_argument, NULL, LONG_OPT_SORT_BY_RSS },
{ "syslog", no_argument, NULL, LONG_OPT_USE_SYSLOG },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, NULL, 0 } /* end-of-array marker */
Expand Down Expand Up @@ -224,6 +227,10 @@ int main(int argc, char* argv[])
args.ignore_root_user = true;
fprintf(stderr, "Processes owned by root will not be killed\n");
break;
case LONG_OPT_SORT_BY_RSS:
args.sort_by_rss = true;
fprintf(stderr, "Find process with the largest rss\n");
break;
case LONG_OPT_PREFER:
prefer_cmds = optarg;
break;
Expand Down Expand Up @@ -264,6 +271,7 @@ int main(int argc, char* argv[])
" -p set niceness of earlyoom to -20 and oom_score_adj to\n"
" -100\n"
" --ignore-root-user do not kill processes owned by root\n"
" --sort-by-rss find process with the largest rss (default oom_score)\n"
" --prefer REGEX prefer to kill processes matching REGEX\n"
" --avoid REGEX avoid killing processes matching REGEX\n"
" --ignore REGEX ignore processes matching REGEX\n"
Expand Down
3 changes: 2 additions & 1 deletion testsuite_cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ func TestCli(t *testing.T) {
// We use {"-r=0"} instead of {"-r", "0"} so runEarlyoom() can detect that there will be no output
{args: []string{"-r=0"}, code: -1, stderrContains: startupMsg, stdoutEmpty: true},
{args: []string{"-r", "0.1"}, code: -1, stderrContains: startupMsg, stdoutContains: memReport},
// Test --avoid, --prefer and -ignore-root-user
// Test --avoid, --prefer, --ignore-root-user and --sort-by-rss
{args: []string{"--avoid", "MyProcess1"}, code: -1, stderrContains: "Will avoid killing", stdoutContains: memReport},
{args: []string{"--prefer", "MyProcess2"}, code: -1, stderrContains: "Preferring to kill", stdoutContains: memReport},
{args: []string{"--ignore-root-user"}, code: -1, stderrContains: "Processes owned by root will not be killed", stdoutContains: memReport},
{args: []string{"--sort-by-rss"}, code: -1, stderrContains: "Find process with the largest rss", stdoutContains: memReport},
{args: []string{"-i"}, code: -1, stderrContains: "Option -i is ignored"},
// Extra arguments should error out
{args: []string{"xyz"}, code: 13, stderrContains: "extra argument not understood", stdoutEmpty: true},
Expand Down

0 comments on commit 90f1a67

Please sign in to comment.