From 030bc91cb98385904b28a839d1e04bb4160a52d2 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Mon, 4 Apr 2022 15:06:07 -0400 Subject: oomd: calculate 'used' memory with MemAvailable instead of MemFree The calculation for used memory in oomd_system_context_acquire is given by MemTotal - MemFree from /proc/meminfo. This is too strict of a calculation because it does not consider memory that is still available for starting new applictions without swapping (MemAvailable). As a result, systemd-oomd can start to kill processes before it is necessary. This is more apparent on systems with low swap space. Instead, compute 'used' memory as MemTotal - MemAvailable in oomd_system_context_acquire and procfs_memory_get (which is used by oomd_cgroup_context_acquire). And, rename oomd_mem_free_below to oomd_mem_available_below for clarity. --- src/oom/oomd-manager.c | 4 ++-- src/oom/oomd-util.c | 22 +++++++++++----------- src/oom/oomd-util.h | 4 ++-- src/oom/test-oomd-util.c | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/oom') diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c index b0a81474cc..cbbf95a7e4 100644 --- a/src/oom/oomd-manager.c +++ b/src/oom/oomd-manager.c @@ -384,8 +384,8 @@ static int monitor_swap_contexts_handler(sd_event_source *s, uint64_t usec, void * is only used to decide which cgroups to kill (and even then only the resource usages of its descendent * nodes are the ones that matter). */ - /* Check amount of memory free and swap free so we don't free up swap when memory is still available. */ - if (oomd_mem_free_below(&m->system_context, 10000 - m->swap_used_limit_permyriad) && + /* Check amount of memory available and swap free so we don't free up swap when memory is still available. */ + if (oomd_mem_available_below(&m->system_context, 10000 - m->swap_used_limit_permyriad) && oomd_swap_free_below(&m->system_context, 10000 - m->swap_used_limit_permyriad)) { _cleanup_hashmap_free_ Hashmap *candidates = NULL; _cleanup_free_ char *selected = NULL; diff --git a/src/oom/oomd-util.c b/src/oom/oomd-util.c index a135824c53..d1ab528a0e 100644 --- a/src/oom/oomd-util.c +++ b/src/oom/oomd-util.c @@ -122,7 +122,7 @@ uint64_t oomd_pgscan_rate(const OomdCGroupContext *c) { return c->pgscan - last_pgscan; } -bool oomd_mem_free_below(const OomdSystemContext *ctx, int threshold_permyriad) { +bool oomd_mem_available_below(const OomdSystemContext *ctx, int threshold_permyriad) { uint64_t mem_threshold; assert(ctx); @@ -418,15 +418,15 @@ int oomd_system_context_acquire(const char *proc_meminfo_path, OomdSystemContext _cleanup_fclose_ FILE *f = NULL; unsigned field_filled = 0; OomdSystemContext ctx = {}; - uint64_t mem_free, swap_free; + uint64_t mem_available, swap_free; int r; enum { MEM_TOTAL = 1U << 0, - MEM_FREE = 1U << 1, + MEM_AVAILABLE = 1U << 1, SWAP_TOTAL = 1U << 2, SWAP_FREE = 1U << 3, - ALL = MEM_TOTAL|MEM_FREE|SWAP_TOTAL|SWAP_FREE, + ALL = MEM_TOTAL|MEM_AVAILABLE|SWAP_TOTAL|SWAP_FREE, }; assert(proc_meminfo_path); @@ -449,9 +449,9 @@ int oomd_system_context_acquire(const char *proc_meminfo_path, OomdSystemContext if ((word = startswith(line, "MemTotal:"))) { field_filled |= MEM_TOTAL; r = convert_meminfo_value_to_uint64_bytes(word, &ctx.mem_total); - } else if ((word = startswith(line, "MemFree:"))) { - field_filled |= MEM_FREE; - r = convert_meminfo_value_to_uint64_bytes(word, &mem_free); + } else if ((word = startswith(line, "MemAvailable:"))) { + field_filled |= MEM_AVAILABLE; + r = convert_meminfo_value_to_uint64_bytes(word, &mem_available); } else if ((word = startswith(line, "SwapTotal:"))) { field_filled |= SWAP_TOTAL; r = convert_meminfo_value_to_uint64_bytes(word, &ctx.swap_total); @@ -471,10 +471,10 @@ int oomd_system_context_acquire(const char *proc_meminfo_path, OomdSystemContext if (field_filled != ALL) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "%s is missing expected fields", proc_meminfo_path); - if (mem_free > ctx.mem_total) + if (mem_available > ctx.mem_total) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "MemFree (%" PRIu64 ") cannot be greater than MemTotal (%" PRIu64 ") %m", - mem_free, + "MemAvailable (%" PRIu64 ") cannot be greater than MemTotal (%" PRIu64 ") %m", + mem_available, ctx.mem_total); if (swap_free > ctx.swap_total) @@ -483,7 +483,7 @@ int oomd_system_context_acquire(const char *proc_meminfo_path, OomdSystemContext swap_free, ctx.swap_total); - ctx.mem_used = ctx.mem_total - mem_free; + ctx.mem_used = ctx.mem_total - mem_available; ctx.swap_used = ctx.swap_total - swap_free; *ret = ctx; diff --git a/src/oom/oomd-util.h b/src/oom/oomd-util.h index 6aada90344..de2298f3c9 100644 --- a/src/oom/oomd-util.h +++ b/src/oom/oomd-util.h @@ -60,8 +60,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(OomdCGroupContext*, oomd_cgroup_context_free); * Returns -ENOMEM for allocation errors. */ int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret); -/* Returns true if the amount of memory free is below the permyriad of memory specified by `threshold_permyriad`. */ -bool oomd_mem_free_below(const OomdSystemContext *ctx, int threshold_permyriad); +/* Returns true if the amount of memory available (see proc(5)) is below the permyriad of memory specified by `threshold_permyriad`. */ +bool oomd_mem_available_below(const OomdSystemContext *ctx, int threshold_permyriad); /* Returns true if the amount of swap free is below the permyriad of swap specified by `threshold_permyriad`. */ bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad); diff --git a/src/oom/test-oomd-util.c b/src/oom/test-oomd-util.c index 82a60ad880..19173edcda 100644 --- a/src/oom/test-oomd-util.c +++ b/src/oom/test-oomd-util.c @@ -282,7 +282,7 @@ static void test_oomd_system_context_acquire(void) { "SwapFree: 7604 kB\n", WRITE_STRING_FILE_CREATE) == 0); assert_se(oomd_system_context_acquire(path, &ctx) == 0); assert_se(ctx.mem_total == 33275142144); - assert_se(ctx.mem_used == 23157497856); + assert_se(ctx.mem_used == 10975404032); assert_se(ctx.swap_total == 8589930496); assert_se(ctx.swap_used == 8582144000); } @@ -341,7 +341,7 @@ static void test_oomd_mem_and_swap_free_below(void) { .swap_total = 20971512 * 1024U, .swap_used = 20971440 * 1024U, }; - assert_se(oomd_mem_free_below(&ctx, 2000) == false); + assert_se(oomd_mem_available_below(&ctx, 2000) == false); assert_se(oomd_swap_free_below(&ctx, 2000) == true); ctx = (OomdSystemContext) { @@ -350,7 +350,7 @@ static void test_oomd_mem_and_swap_free_below(void) { .swap_total = 20971512 * 1024U, .swap_used = 3310136 * 1024U, }; - assert_se(oomd_mem_free_below(&ctx, 2000) == true); + assert_se(oomd_mem_available_below(&ctx, 2000) == true); assert_se(oomd_swap_free_below(&ctx, 2000) == false); ctx = (OomdSystemContext) { @@ -359,7 +359,7 @@ static void test_oomd_mem_and_swap_free_below(void) { .swap_total = 0, .swap_used = 0, }; - assert_se(oomd_mem_free_below(&ctx, 2000) == false); + assert_se(oomd_mem_available_below(&ctx, 2000) == false); assert_se(oomd_swap_free_below(&ctx, 2000) == false); } -- cgit v1.2.1