From 459d76296d3d0a0b59ee1e2e48ad2271429de916 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 5 Feb 2023 19:02:22 +0100 Subject: [PATCH] Introduce UserMemTotal and calculate MemAvailablePercent based on it Shmem/tmpfs may block a large part of RAM. This memory cannot be freed by killing processes. Before this change, we could get into a situation where earlyoom kills *every* process, but still cannot achieve the desired MemAvailablePercent. Fixes: https://github.com/rfjakob/earlyoom/pull/274 Fixes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1012870 --- main.c | 6 +++--- meminfo.c | 18 +++++++++--------- meminfo.h | 7 +++++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/main.c b/main.c index ae4e53d..5806256 100644 --- a/main.c +++ b/main.c @@ -341,8 +341,8 @@ int main(int argc, char* argv[]) } // Print memory limits - fprintf(stderr, "mem total: %4lld MiB, swap total: %4lld MiB\n", - m.MemTotalKiB / 1024, m.SwapTotalKiB / 1024); + fprintf(stderr, "user mem total: %4lld MiB, swap total: %4lld MiB\n", + m.UserMemTotalKiB / 1024, m.SwapTotalKiB / 1024); fprintf(stderr, "sending SIGTERM when mem <= " PRIPCT " and swap <= " PRIPCT ",\n", args.mem_term_percent, args.swap_term_percent); fprintf(stderr, " SIGKILL when mem <= " PRIPCT " and swap <= " PRIPCT "\n", @@ -404,7 +404,7 @@ static unsigned sleep_time_ms(const poll_loop_args_t* args, const meminfo_t* m) const unsigned min_sleep = 100; const unsigned max_sleep = 1000; - long long mem_headroom_kib = (long long)((m->MemAvailablePercent - args->mem_term_percent) * (double)m->MemTotalKiB / 100); + long long mem_headroom_kib = (long long)((m->MemAvailablePercent - args->mem_term_percent) * (double)m->UserMemTotalKiB / 100); if (mem_headroom_kib < 0) { mem_headroom_kib = 0; } diff --git a/meminfo.c b/meminfo.c index 2dedfb2..16d0186 100644 --- a/meminfo.c +++ b/meminfo.c @@ -95,7 +95,7 @@ meminfo_t parse_meminfo() m.MemTotalKiB = get_entry_fatal("MemTotal:", buf); m.SwapTotalKiB = get_entry_fatal("SwapTotal:", buf); m.AnonPagesKiB = get_entry_fatal("AnonPages:", buf); - long long SwapFree = get_entry_fatal("SwapFree:", buf); + m.SwapFreeKiB = get_entry_fatal("SwapFree:", buf); m.MemAvailableKiB = get_entry("MemAvailable:", buf); if (m.MemAvailableKiB < 0) { @@ -107,11 +107,13 @@ meminfo_t parse_meminfo() } } + // Calculated values + m.UserMemTotalKiB = m.MemAvailableKiB + m.AnonPagesKiB; + // Calculate percentages - m.MemAvailablePercent = (double)m.MemAvailableKiB * 100 / (double)m.MemTotalKiB; - m.AnonPagesPercent = (double)m.AnonPagesKiB * 100 / (double)m.MemTotalKiB; + m.MemAvailablePercent = (double)m.MemAvailableKiB * 100 / (double)m.UserMemTotalKiB; if (m.SwapTotalKiB > 0) { - m.SwapFreePercent = (double)SwapFree * 100 / (double)m.SwapTotalKiB; + m.SwapFreePercent = (double)m.SwapFreeKiB * 100 / (double)m.SwapTotalKiB; } else { m.SwapFreePercent = 0; } @@ -302,13 +304,11 @@ long long get_vm_rss_kib(int pid) */ void print_mem_stats(int __attribute__((format(printf, 1, 2))) (*out_func)(const char* fmt, ...), const meminfo_t m) { - out_func("mem avail: %5lld of %5lld MiB (" PRIPCT "), swap free: %4lld of %4lld MiB (" PRIPCT "), anon: %5lld MiB (" PRIPCT ")\n", + out_func("mem avail: %5lld of %5lld MiB (" PRIPCT "), swap free: %4lld of %4lld MiB (" PRIPCT ")\n", m.MemAvailableKiB / 1024, - m.MemTotalKiB / 1024, + m.UserMemTotalKiB / 1024, m.MemAvailablePercent, m.SwapFreeKiB / 1024, m.SwapTotalKiB / 1024, - m.SwapFreePercent, - m.AnonPagesKiB / 1024, - m.AnonPagesPercent); + m.SwapFreePercent); } diff --git a/meminfo.h b/meminfo.h index 8f4420a..035b686 100644 --- a/meminfo.h +++ b/meminfo.h @@ -7,16 +7,19 @@ #include typedef struct { - // Values from /proc/meminfo, in KiB or converted to MiB. + // Values from /proc/meminfo, in KiB long long MemTotalKiB; long long MemAvailableKiB; long long SwapTotalKiB; long long SwapFreeKiB; long long AnonPagesKiB; + // Calculated values + // UserMemTotalKiB = MemAvailableKiB + AnonPagesKiB. + // Represents the total amount of memory that may be used by user processes. + long long UserMemTotalKiB; // Calculated percentages double MemAvailablePercent; // percent of total memory that is available double SwapFreePercent; // percent of total swap that is free - double AnonPagesPercent; // percent of total memory that is used by processes } meminfo_t; typedef struct procinfo {