diff options
| -rw-r--r-- | drivers/staging/android/lowmemorykiller.c | 105 | ||||
| -rw-r--r-- | include/trace/events/almk.h | 84 |
2 files changed, 188 insertions, 1 deletions
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 11535e3065ac..e60421299164 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -47,6 +47,10 @@ #include <linux/swap.h> #include <linux/fs.h> #include <linux/cpuset.h> +#include <linux/vmpressure.h> + +#define CREATE_TRACE_POINTS +#include <trace/events/almk.h> #ifdef CONFIG_HIGHMEM #define _ZONE ZONE_HIGHMEM @@ -91,6 +95,95 @@ static unsigned long lowmem_count(struct shrinker *s, global_page_state(NR_INACTIVE_FILE); } +static atomic_t shift_adj = ATOMIC_INIT(0); +static short adj_max_shift = 353; + +/* User knob to enable/disable adaptive lmk feature */ +static int enable_adaptive_lmk; +module_param_named(enable_adaptive_lmk, enable_adaptive_lmk, int, + S_IRUGO | S_IWUSR); + +/* + * This parameter controls the behaviour of LMK when vmpressure is in + * the range of 90-94. Adaptive lmk triggers based on number of file + * pages wrt vmpressure_file_min, when vmpressure is in the range of + * 90-94. Usually this is a pseudo minfree value, higher than the + * highest configured value in minfree array. + */ +static int vmpressure_file_min; +module_param_named(vmpressure_file_min, vmpressure_file_min, int, + S_IRUGO | S_IWUSR); + +enum { + VMPRESSURE_NO_ADJUST = 0, + VMPRESSURE_ADJUST_ENCROACH, + VMPRESSURE_ADJUST_NORMAL, +}; + +int adjust_minadj(short *min_score_adj) +{ + int ret = VMPRESSURE_NO_ADJUST; + + if (!enable_adaptive_lmk) + return 0; + + if (atomic_read(&shift_adj) && + (*min_score_adj > adj_max_shift)) { + if (*min_score_adj == OOM_SCORE_ADJ_MAX + 1) + ret = VMPRESSURE_ADJUST_ENCROACH; + else + ret = VMPRESSURE_ADJUST_NORMAL; + *min_score_adj = adj_max_shift; + } + atomic_set(&shift_adj, 0); + + return ret; +} + +static int lmk_vmpressure_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + int other_free, other_file; + unsigned long pressure = action; + int array_size = ARRAY_SIZE(lowmem_adj); + + if (!enable_adaptive_lmk) + return 0; + + if (pressure >= 95) { + other_file = global_page_state(NR_FILE_PAGES) - + global_page_state(NR_SHMEM) - + total_swapcache_pages(); + other_free = global_page_state(NR_FREE_PAGES); + + atomic_set(&shift_adj, 1); + trace_almk_vmpressure(pressure, other_free, other_file); + } else if (pressure >= 90) { + if (lowmem_adj_size < array_size) + array_size = lowmem_adj_size; + if (lowmem_minfree_size < array_size) + array_size = lowmem_minfree_size; + + other_file = global_page_state(NR_FILE_PAGES) - + global_page_state(NR_SHMEM) - + total_swapcache_pages(); + + other_free = global_page_state(NR_FREE_PAGES); + + if ((other_free < lowmem_minfree[array_size - 1]) && + (other_file < vmpressure_file_min)) { + atomic_set(&shift_adj, 1); + trace_almk_vmpressure(pressure, other_free, other_file); + } + } + + return 0; +} + +static struct notifier_block lmk_vmpr_nb = { + .notifier_call = lmk_vmpressure_notifier, +}; + static int test_task_flag(struct task_struct *p, int flag) { struct task_struct *t = p; @@ -285,6 +378,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) unsigned long rem = 0; int tasksize; int i; + int ret = 0; short min_score_adj = OOM_SCORE_ADJ_MAX + 1; int minfree = 0; int selected_tasksize = 0; @@ -320,11 +414,14 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) } } + ret = adjust_minadj(&min_score_adj); + lowmem_print(3, "lowmem_scan %lu, %x, ofree %d %d, ma %hd\n", sc->nr_to_scan, sc->gfp_mask, other_free, other_file, min_score_adj); if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) { + trace_almk_shrink(0, ret, other_free, other_file, 0); lowmem_print(5, "lowmem_scan %lu, %x, return 0\n", sc->nr_to_scan, sc->gfp_mask); mutex_unlock(&scan_mutex); @@ -432,8 +529,13 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) rcu_read_unlock(); /* give the system time to free up the memory */ msleep_interruptible(20); - } else + trace_almk_shrink(selected_tasksize, ret, + other_free, other_file, + selected_oom_score_adj); + } else { + trace_almk_shrink(1, ret, other_free, other_file, 0); rcu_read_unlock(); + } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); @@ -450,6 +552,7 @@ static struct shrinker lowmem_shrinker = { static int __init lowmem_init(void) { register_shrinker(&lowmem_shrinker); + vmpressure_notifier_register(&lmk_vmpr_nb); return 0; } device_initcall(lowmem_init); diff --git a/include/trace/events/almk.h b/include/trace/events/almk.h new file mode 100644 index 000000000000..85d712d48f50 --- /dev/null +++ b/include/trace/events/almk.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM almk + +#if !defined(_TRACE_EVENT_ALMK_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EVENT_ALMK_H + +#include <linux/tracepoint.h> +#include <linux/types.h> + +TRACE_EVENT(almk_vmpressure, + + TP_PROTO(unsigned long pressure, + int other_free, + int other_file), + + TP_ARGS(pressure, other_free, other_file), + + TP_STRUCT__entry( + __field(unsigned long, pressure) + __field(int, other_free) + __field(int, other_file) + ), + + TP_fast_assign( + __entry->pressure = pressure; + __entry->other_free = other_free; + __entry->other_file = other_file; + ), + + TP_printk("%lu, %d, %d", + __entry->pressure, __entry->other_free, + __entry->other_file) +); + +TRACE_EVENT(almk_shrink, + + TP_PROTO(int tsize, + int vmp, + int other_free, + int other_file, + short adj), + + TP_ARGS(tsize, vmp, other_free, other_file, adj), + + TP_STRUCT__entry( + __field(int, tsize) + __field(int, vmp) + __field(int, other_free) + __field(int, other_file) + __field(short, adj) + ), + + TP_fast_assign( + __entry->tsize = tsize; + __entry->vmp = vmp; + __entry->other_free = other_free; + __entry->other_file = other_file; + __entry->adj = adj; + ), + + TP_printk("%d, %d, %d, %d, %d", + __entry->tsize, + __entry->vmp, + __entry->other_free, + __entry->other_file, + __entry->adj) +); + +#endif + +#include <trace/define_trace.h> + |
