Skip to content

Commit

Permalink
Dump /proc/[pid]/statm for all processes in print_mem_stats()
Browse files Browse the repository at this point in the history
It can be usefull to see statm info about all processes
in the system during earlyoom killing. In some cases this
may allow tracking of "heavy" processes that haven't been killed
but are still present in system.
  • Loading branch information
mRrvz committed Dec 2, 2024
1 parent d38e29b commit d7d89d6
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 19 deletions.
20 changes: 1 addition & 19 deletions kill.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "kill.h"
#include "meminfo.h"
#include "msg.h"
#include "utils.h"

// Processes matching "--prefer REGEX" get OOM_SCORE_PREFER added to their oom_score
#define OOM_SCORE_PREFER 300
Expand All @@ -34,25 +35,6 @@
// At most 1 notification per second when --dryrun is active
#define NOTIFY_RATELIMIT 1

static bool isnumeric(char* str)
{
int i = 0;

// Empty string is not numeric
if (str[0] == 0)
return false;

while (1) {
if (str[i] == 0) // End of string
return true;

if (isdigit(str[i]) == 0)
return false;

i++;
}
}

static void notify_dbus(const char* summary, const char* body)
{
int pid = fork();
Expand Down
99 changes: 99 additions & 0 deletions meminfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#include "globals.h"
#include "meminfo.h"
#include "msg.h"
#include "proc_pid.h"
#include "utils.h"

/* Parse the contents of /proc/meminfo (in buf), return value of "name"
* (example: "MemTotal:")
Expand Down Expand Up @@ -269,6 +271,101 @@ int get_uid(int pid)
return (int)st.st_uid;
}

static int get_process_statm(char *buf, size_t buf_size, int pid)
{
char path[PATH_LEN] = { 0 };
snprintf(path, sizeof(path), "%s/%d/statm", procdir_path, pid);

FILE *f = fopen(path, "r");
if (!f) {
debug("%s: failed to open file '%s': %s\n", __func__, path, strerror(errno));
return -EINVAL;
}

char *res = fgets(buf, (int)buf_size, f);
fclose(f);
if (!res) {
debug("%s: failed to read statm info for pid=%d\n", __func__, pid);
return -EINVAL;
}

return 0;
}

static void dump_all_process_meminfo(int __attribute__((format(printf, 1, 2))) (*out_func)(const char* fmt, ...))
{
DIR *procdir = opendir(procdir_path);
if (procdir == NULL) {
fatal(5, "%s: could not open /proc: %s", __func__, strerror(errno));
}

static size_t page_size;
if (page_size == 0) {
page_size = (size_t)sysconf(_SC_PAGESIZE);
if (page_size == 0) {
fatal(1, "could not read page size\n");
}
}

char *statm = calloc(1, page_size);
if (!statm) {
debug("%s: failed to allocate memory\n", __func__);
return;
}

out_func("===========================\n");
out_func("Dump all processes statm info. More details: Documentation/filesystems/proc.txt\n");
out_func("%%proc (%%pid): %%size %%resident %%shared %%trs %%trs %%drs %%dt\n");

while (1) {
errno = 0;
struct dirent *d = readdir(procdir);
if (d == NULL) {
if (errno != 0)
warn("%s: readdir error: %s\n", __func__, strerror(errno));
break;
}

// proc contains lots of directories not related to processes,
// skip them
if (!isnumeric(d->d_name))
continue;

errno = 0;
int pid = (int)strtol(d->d_name, NULL, 10);
if (errno != 0) {
warn("%s: strtol() failed: %s\n", __func__, strerror(errno));
continue;
}

// Skip kthreads
pid_stat_t stat;
if (!parse_proc_pid_stat(&stat, pid))
continue;

if (stat.rss <= 0)
continue;

int ret = get_process_statm(statm, page_size, pid);
if (ret < 0)
continue;

char name[PATH_LEN] = { 0 };
ret = get_comm(pid, name, sizeof(name));
if (ret < 0) {
debug("pid %d: error reading process name: %s\n", pid, strerror(-ret));
continue;
}

out_func("%s (%d): %s", name, pid, statm);
}

free(statm);
closedir(procdir);

out_func("===========================\n");
}

/* Print a status line like
* mem avail: 5259 MiB (67 %), swap free: 0 MiB (0 %)"
* as an informational message to stdout (default), or
Expand All @@ -283,4 +380,6 @@ void print_mem_stats(int __attribute__((format(printf, 1, 2))) (*out_func)(const
m.SwapFreeKiB / 1024,
m.SwapTotalKiB / 1024,
m.SwapFreePercent);

dump_all_process_meminfo(out_func);
}
22 changes: 22 additions & 0 deletions utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <ctype.h>

#include "utils.h"

int isnumeric(char* str)
{
int i = 0;

// Empty string is not numeric
if (str[0] == 0)
return 0;

while (1) {
if (str[i] == 0) // End of string
return 1;

if (isdigit(str[i]) == 0)
return 0;

i++;
}
}
6 changes: 6 additions & 0 deletions utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __UTILS_H__
#define __UTILS_H__

int isnumeric(char* str);

#endif

0 comments on commit d7d89d6

Please sign in to comment.