From 495db5c643a57be470a480642348af56028acde3 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 26 Sep 2022 20:26:20 -0700 Subject: [PATCH] lmkd: measure free swap as available and easily reclaimable memory In the case of ZRAM, SwapFree does not represent the actual free swap amount because swap space is taken from the free memory or reclaimed. Therefore use free memory and easily reclaimable memory as an approximation of how much free swap system can use. Use SwapFree as a measure of how much swap space the system will consider using. Min of those two measurements is used to decide how much usable swap the system still has. Bug: 238495258 Signed-off-by: Suren Baghdasaryan Change-Id: Ia7b0cc4a744d14c0d6e52603795917cf5824ea15 --- lmkd.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lmkd.cpp b/lmkd.cpp index 2ee4253..d25545f 100644 --- a/lmkd.cpp +++ b/lmkd.cpp @@ -450,6 +450,7 @@ union meminfo { /* fields below are calculated rather than read from the file */ int64_t nr_file_pages; int64_t total_gpu_kb; + int64_t easy_available; } field; int64_t arr[MI_FIELD_COUNT]; }; @@ -1876,10 +1877,19 @@ static int meminfo_parse(union meminfo *mi) { mi->field.nr_file_pages = mi->field.cached + mi->field.swap_cached + mi->field.buffers; mi->field.total_gpu_kb = read_gpu_total_kb(); + mi->field.easy_available = mi->field.nr_free_pages + mi->field.inactive_file; return 0; } +// In the case of ZRAM, mi->field.free_swap can't be used directly because swap space is taken +// from the free memory or reclaimed. Use the lowest of free_swap and easily available memory to +// measure free swap because they represent how much swap space the system will consider to use +// and how much it can actually use. +static inline int64_t get_free_swap(union meminfo *mi) { + return std::min(mi->field.free_swap, mi->field.easy_available); +} + /* /proc/vmstat parsing routines */ static bool vmstat_parse_line(char *line, union vmstat *vs) { char *cp; @@ -2388,7 +2398,7 @@ static int kill_one_process(struct proc* procp, int min_oom_score, struct kill_i kill_st.oom_score = procp->oomadj; kill_st.min_oom_score = min_oom_score; kill_st.free_mem_kb = mi->field.nr_free_pages * page_k; - kill_st.free_swap_kb = mi->field.free_swap * page_k; + kill_st.free_swap_kb = get_free_swap(mi) * page_k; stats_write_lmk_kill_occurred(&kill_st, mem_st); ctrl_data_write_lmk_kill_occurred((pid_t)pid, uid); @@ -2564,7 +2574,7 @@ void calc_zone_watermarks(struct zoneinfo *zi, struct zone_watermarks *watermark } static int calc_swap_utilization(union meminfo *mi) { - int64_t swap_used = mi->field.total_swap - mi->field.free_swap; + int64_t swap_used = mi->field.total_swap - get_free_swap(mi); int64_t total_swappable = mi->field.active_anon + mi->field.inactive_anon + mi->field.shmem + swap_used; return total_swappable > 0 ? (swap_used * 100) / total_swappable : 0; @@ -2657,7 +2667,7 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_ /* Check free swap levels */ if (swap_free_low_percentage) { swap_low_threshold = mi.field.total_swap * swap_free_low_percentage / 100; - swap_is_low = mi.field.free_swap < swap_low_threshold; + swap_is_low = get_free_swap(&mi) < swap_low_threshold; } else { swap_low_threshold = 0; } @@ -2770,7 +2780,7 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_ kill_reason = LOW_SWAP_AND_THRASHING; snprintf(kill_desc, sizeof(kill_desc), "device is low on swap (%" PRId64 "kB < %" PRId64 "kB) and thrashing (%" PRId64 "%%)", - mi.field.free_swap * page_k, swap_low_threshold * page_k, thrashing); + get_free_swap(&mi) * page_k, swap_low_threshold * page_k, thrashing); /* Do not kill perceptible apps unless below min watermark or heavily thrashing */ if (wmark > WMARK_MIN && thrashing < thrashing_critical_pct) { min_score_adj = PERCEPTIBLE_APP_ADJ + 1; @@ -2781,7 +2791,7 @@ static void mp_event_psi(int data, uint32_t events, struct polling_params *poll_ kill_reason = LOW_MEM_AND_SWAP; snprintf(kill_desc, sizeof(kill_desc), "%s watermark is breached and swap is low (%" PRId64 "kB < %" PRId64 "kB)", wmark < WMARK_LOW ? "min" : "low", - mi.field.free_swap * page_k, swap_low_threshold * page_k); + get_free_swap(&mi) * page_k, swap_low_threshold * page_k); /* Do not kill perceptible apps unless below min watermark or heavily thrashing */ if (wmark > WMARK_MIN && thrashing < thrashing_critical_pct) { min_score_adj = PERCEPTIBLE_APP_ADJ + 1; @@ -3060,7 +3070,7 @@ static void mp_event_common(int data, uint32_t events, struct polling_params *po // If we still have enough swap space available, check if we want to // ignore/downgrade pressure events. - if (mi.field.free_swap >= + if (get_free_swap(&mi) >= mi.field.total_swap * swap_free_low_percentage / 100) { // If the pressure is larger than downgrade_pressure lmk will not // kill any process, since enough memory is available.