Skip to content

Commit

Permalink
Replace get_vm_rss_kib with parse_proc_pid_stat and delete it
Browse files Browse the repository at this point in the history
It's slower, but we get the ppid from it, which we will need
for detecting kernel threads.

Benchmark_get_vm_rss_kib-4         	  178054	      6920 ns/op
Benchmark_parse_proc_pid_stat-4    	  107766	     11614 ns/op
  • Loading branch information
rfjakob committed Apr 8, 2024
1 parent 18c283f commit 27509d9
Show file tree
Hide file tree
Showing 6 changed files with 17 additions and 85 deletions.
9 changes: 5 additions & 4 deletions kill.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,13 @@ bool is_larger(const poll_loop_args_t* args, const procinfo_t* victim, procinfo_
}

{
long long res = get_vm_rss_kib(cur->pid);
if (res < 0) {
debug("%s: pid %d: error reading rss: %s\n", __func__, cur->pid, strerror((int)-res));
bool res = parse_proc_pid_stat(&cur->stat, cur->pid);
if (!res) {
debug("%s: pid %d: error reading stat\n", __func__, cur->pid);
return false;
}
cur->VmRSSkiB = res;
const long page_size = sysconf(_SC_PAGESIZE);
cur->VmRSSkiB = cur->stat.rss * page_size / 1024;
}

if ((args->prefer_regex || args->avoid_regex || args->ignore_regex)) {
Expand Down
33 changes: 0 additions & 33 deletions meminfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,39 +269,6 @@ int get_uid(int pid)
return (int)st.st_uid;
}

// Read VmRSS from /proc/[pid]/statm and convert to kiB.
// Returns the value (>= 0) or -errno on error.
long long get_vm_rss_kib(int pid)
{
long long vm_rss_kib = -1;
char path[PATH_LEN] = { 0 };

// Read VmRSS from /proc/[pid]/statm (in pages)
snprintf(path, sizeof(path), "%s/%d/statm", procdir_path, pid);
FILE* f = fopen(path, "r");
if (f == NULL) {
return -errno;
}
int matches = fscanf(f, "%*u %lld", &vm_rss_kib);
fclose(f);
if (matches < 1) {
return -ENODATA;
}

// Read and cache page size
static long page_size;
if (page_size == 0) {
page_size = sysconf(_SC_PAGESIZE);
if (page_size <= 0) {
fatal(1, "could not read page size\n");
}
}

// Convert to kiB
vm_rss_kib = vm_rss_kib * page_size / 1024;
return vm_rss_kib;
}

/* Print a status line like
* mem avail: 5259 MiB (67 %), swap free: 0 MiB (0 %)"
* as an informational message to stdout (default), or
Expand Down
3 changes: 2 additions & 1 deletion meminfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define PATH_LEN 256

#include <stdbool.h>
#include "proc_pid.h"

typedef struct {
// Values from /proc/meminfo, in KiB
Expand All @@ -28,6 +29,7 @@ typedef struct procinfo {
int badness;
int oom_score_adj;
long long VmRSSkiB;
pid_stat_t stat;
char name[PATH_LEN];
char cmdline[PATH_LEN];
} procinfo_t;
Expand All @@ -37,7 +39,6 @@ bool is_alive(int pid);
void print_mem_stats(int (*out_func)(const char* fmt, ...), const meminfo_t m);
int get_oom_score(int pid);
int get_oom_score_adj(const int pid, int* out);
long long get_vm_rss_kib(int pid);
int get_comm(int pid, char* out, size_t outlen);
int get_uid(int pid);
int get_cmdline(int pid, char* out, size_t outlen);
Expand Down
4 changes: 0 additions & 4 deletions testsuite_c_wrappers.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ func get_oom_score_adj(pid int, out *int) int {
return int(res)
}

func get_vm_rss_kib(pid int) int {
return int(C.get_vm_rss_kib(C.int(pid)))
}

func get_comm(pid int) (int, string) {
cstr := C.CString(strings.Repeat("\000", 256))
res := C.get_comm(C.int(pid), cstr, 256)
Expand Down
13 changes: 10 additions & 3 deletions testsuite_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"syscall"
"testing"
"time"

linuxproc "github.com/c9s/goprocinfo/linux"
)

// #include "meminfo.h"
Expand Down Expand Up @@ -84,7 +86,12 @@ func runEarlyoom(t *testing.T, args ...string) exitVals {
}
}
timer.Stop()
rss := get_vm_rss_kib(cmd.Process.Pid)

stat, err := linuxproc.ReadProcessStat(fmt.Sprintf("/proc/%d/stat", cmd.Process.Pid))
if err != nil {
panic(err)
}
rss := int(stat.Rss)
fds := countFds(cmd.Process.Pid)
cmd.Process.Kill()
err = cmd.Wait()
Expand Down Expand Up @@ -199,8 +206,8 @@ func mockProc(t *testing.T, procs []mockProcProcess) {
// stat
//
// Real /proc/pid/stat string for gnome-shell
template := "549077 (%s) S 547891 549077 549077 0 -1 4194560 245592 104 342 5 108521 28953 0 1 20 0 %d 0 4816953 5260238848 65528 18446744073709551615 94179647238144 94179647245825 140730757359824 0 0 0 0 16781312 17656 0 0 0 17 1 0 0 0 0 0 94179647252976 94179647254904 94179672109056 140730757367876 140730757367897 140730757367897 140730757369827 0\n"
content = []byte(fmt.Sprintf(template, p.comm, p.num_threads))
template := "549077 (%s) S 547891 549077 549077 0 -1 4194560 245592 104 342 5 108521 28953 0 1 20 0 %d 0 4816953 5260238848 %d 18446744073709551615 94179647238144 94179647245825 140730757359824 0 0 0 0 16781312 17656 0 0 0 17 1 0 0 0 0 0 94179647252976 94179647254904 94179672109056 140730757367876 140730757367897 140730757367897 140730757369827 0\n"
content = []byte(fmt.Sprintf(template, p.comm, p.num_threads, rss))
if err := ioutil.WriteFile(pidDir+"/stat", content, 0444); err != nil {
t.Fatal(err)
}
Expand Down
40 changes: 0 additions & 40 deletions testsuite_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,19 +148,6 @@ func Test_fix_truncated_utf8(t *testing.T) {
}
}

func Test_get_vm_rss_kib(t *testing.T) {
pid := os.Getpid()
rss := get_vm_rss_kib(pid)
if rss <= 0 {
t.Fatalf("our rss can't be <= 0, but we got %d", rss)
}
// Error case
res := get_vm_rss_kib(INT32_MAX)
if res != -ENOENT {
t.Fail()
}
}

func Test_get_oom_score(t *testing.T) {
res := get_oom_score(os.Getpid())
// On systems with a lot of RAM, our process may actually have a score of
Expand Down Expand Up @@ -389,33 +376,6 @@ func Benchmark_get_oom_score_adj(b *testing.B) {
}
}

func Benchmark_get_vm_rss_kib(b *testing.B) {
enable_debug(false)

pid := os.Getpid()
for n := 0; n < b.N; n++ {
rss := get_vm_rss_kib(pid)
if rss <= 0 {
b.Fatalf("rss <= 0: %d", rss)
}
}
}

func Benchmark_get_comm(b *testing.B) {
enable_debug(false)

pid := os.Getpid()
for n := 0; n < b.N; n++ {
res, comm := get_comm(pid)
if len(comm) == 0 {
b.Fatalf("empty process name %q", comm)
}
if res != 0 {
b.Fatalf("error %d", res)
}
}
}

func Benchmark_get_cmdline(b *testing.B) {
enable_debug(false)

Expand Down

0 comments on commit 27509d9

Please sign in to comment.