simple_lmk: Use vmpressure notifier to trigger kills

Using kswapd's scan depth to trigger task kills is inconsistent and
unreliable. When memory pressure quickly spikes, the kswapd scan depth
trigger fails to kick off Simple LMK fast enough, causing severe lag.
Additionally, kswapd could stop scanning prematurely before reaching the
desired scan depth to trigger Simple LMK, which could also cause stalls.

To remedy this, use the vmpressure framework instead, since it provides
more consistent and accurate readings on memory pressure. This is not
very tunable though, so remove CONFIG_ANDROID_SIMPLE_LMK_AGGRESSION.
Triggering Simple LMK to kill when the reported memory pressure is 100
should yield good results on all setups.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
fourteen
Sultan Alsawaf 5 years ago committed by Jenna
parent d760fac84a
commit 3489929420
  1. 22
      drivers/android/Kconfig
  2. 24
      drivers/android/simple_lmk.c
  3. 4
      include/linux/simple_lmk.h
  4. 2
      mm/vmscan.c

@ -67,28 +67,6 @@ config ANDROID_SIMPLE_LMK
if ANDROID_SIMPLE_LMK
config ANDROID_SIMPLE_LMK_AGGRESSION
int "Reclaim frequency selection"
range 1 3
default 1
help
This value determines how frequently Simple LMK will perform memory
reclaims. A lower value corresponds to less frequent reclaims, which
maximizes memory usage. The range of values has a logarithmic
correlation; 2 is twice as aggressive as 1, and 3 is twice as
aggressive as 2, which makes 3 four times as aggressive as 1.
The aggression is set as a factor of kswapd's scan depth. This means
that a system with more memory will have a more expensive aggression
factor compared to a system with less memory. For example, setting an
aggression factor of 1 with 4 GiB of memory would be like setting a
factor of 2 with 8 GiB of memory; the more memory a system has, the
more expensive it is to use a lower value.
Choosing a value of 1 here works well with systems that have 4 GiB of
memory. If the default doesn't work well, then this value should be
tweaked based on empirical results using different values.
config ANDROID_SIMPLE_LMK_MINFREE
int "Minimum MiB of memory to free per reclaim"
range 8 512

@ -10,6 +10,7 @@
#include <linux/moduleparam.h>
#include <linux/oom.h>
#include <linux/sort.h>
#include <linux/vmpressure.h>
#include <uapi/linux/sched/types.h>
/* The minimum number of pages to free per reclaim */
@ -267,13 +268,6 @@ static int simple_lmk_reclaim_thread(void *data)
return 0;
}
void simple_lmk_decide_reclaim(int kswapd_priority)
{
if (kswapd_priority == CONFIG_ANDROID_SIMPLE_LMK_AGGRESSION &&
!atomic_cmpxchg_acquire(&needs_reclaim, 0, 1))
wake_up(&oom_waitq);
}
void simple_lmk_mm_freed(struct mm_struct *mm)
{
int i;
@ -291,6 +285,20 @@ void simple_lmk_mm_freed(struct mm_struct *mm)
read_unlock(&mm_free_lock);
}
static int simple_lmk_vmpressure_cb(struct notifier_block *nb,
unsigned long pressure, void *data)
{
if (pressure == 100 && !atomic_cmpxchg_acquire(&needs_reclaim, 0, 1))
wake_up(&oom_waitq);
return NOTIFY_OK;
}
static struct notifier_block vmpressure_notif = {
.notifier_call = simple_lmk_vmpressure_cb,
.priority = INT_MAX
};
/* Initialize Simple LMK when lmkd in Android writes to the minfree parameter */
static int simple_lmk_init_set(const char *val, const struct kernel_param *kp)
{
@ -301,7 +309,9 @@ static int simple_lmk_init_set(const char *val, const struct kernel_param *kp)
thread = kthread_run(simple_lmk_reclaim_thread, NULL,
"simple_lmkd");
BUG_ON(IS_ERR(thread));
BUG_ON(vmpressure_notifier_register(&vmpressure_notif));
}
return 0;
}

@ -8,12 +8,8 @@
struct mm_struct;
#ifdef CONFIG_ANDROID_SIMPLE_LMK
void simple_lmk_decide_reclaim(int kswapd_priority);
void simple_lmk_mm_freed(struct mm_struct *mm);
#else
static inline void simple_lmk_decide_reclaim(int kswapd_priority)
{
}
static inline void simple_lmk_mm_freed(struct mm_struct *mm)
{
}

@ -50,7 +50,6 @@
#include <linux/printk.h>
#include <linux/dax.h>
#include <linux/psi.h>
#include <linux/simple_lmk.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@ -3625,7 +3624,6 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
unsigned long nr_reclaimed = sc.nr_reclaimed;
bool raise_priority = true;
simple_lmk_decide_reclaim(sc.priority);
sc.reclaim_idx = classzone_idx;
/*

Loading…
Cancel
Save