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 <surenb@google.com>
Change-Id: Ia7b0cc4a744d14c0d6e52603795917cf5824ea15
This commit is contained in:
Suren Baghdasaryan 2022-09-26 20:26:20 -07:00
parent ba9ea6e3d6
commit 495db5c643
1 changed files with 16 additions and 6 deletions

View File

@ -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.