diff --git a/kill.c b/kill.c index 6b1b89f..5f0e4ab 100644 --- a/kill.c +++ b/kill.c @@ -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)) { diff --git a/meminfo.c b/meminfo.c index e176336..25936e1 100644 --- a/meminfo.c +++ b/meminfo.c @@ -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 diff --git a/meminfo.h b/meminfo.h index c17e7f1..7dd1b22 100644 --- a/meminfo.h +++ b/meminfo.h @@ -5,6 +5,7 @@ #define PATH_LEN 256 #include +#include "proc_pid.h" typedef struct { // Values from /proc/meminfo, in KiB @@ -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; @@ -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); diff --git a/testsuite_c_wrappers.go b/testsuite_c_wrappers.go index 68c6f9b..bf4ffb6 100644 --- a/testsuite_c_wrappers.go +++ b/testsuite_c_wrappers.go @@ -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) diff --git a/testsuite_helpers.go b/testsuite_helpers.go index b926ac8..97d3294 100644 --- a/testsuite_helpers.go +++ b/testsuite_helpers.go @@ -11,6 +11,8 @@ import ( "syscall" "testing" "time" + + linuxproc "github.com/c9s/goprocinfo/linux" ) // #include "meminfo.h" @@ -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() @@ -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) } diff --git a/testsuite_unit_test.go b/testsuite_unit_test.go index 65b7c80..13cb771 100644 --- a/testsuite_unit_test.go +++ b/testsuite_unit_test.go @@ -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 @@ -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)