特性来源

ALMK: adaptive lowmemorykiller,是Qualcomm针对安卓LMK的优化,当系统lmk还没有杀进程时,如果发现有过高的vmpressure,就有可能会造成卡顿,此时杀掉某个进程是个比较好的选择。

代码分析

msm kernel3.18 lowmemorykiller.c 主体函数如下:

static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
{
...
for (i = 0; i < array_size; i++) {
minfree = lowmem_minfree[i];
if (other_free < minfree && other_file < minfree) {
min_score_adj = lowmem_adj[i];
break;
}
}
ret = adjust_minadj(&min_score_adj);
...
}

在minfree的范围判断后加入了min_score_adj的调整,代码如下:

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;
}

enable_adaptive_lmk是特性开关。

shift_adj用作入口首要条件,>0才能进入,这个会在vm pressure中set,等下来看。

同时,lmk所选择的min_score_adj要>adj_max_shift才能working,比如如果系统内存在minfree之上时,此时的adjust_minadj就是VMPRESSURE_ADJUST_ENCROACH.

下面的代码就是如何用vmpressure探测系统thrashing:

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) + zcache_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) + zcache_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);
}
}

这段代码里的90,95有code style问题,在vmpressure.c有如下级别定义:

static const unsigned int vmpressure_level_med = 60;
static const unsigned int vmpressure_level_critical = 95;

这里的95就表明系统基本上page thrashing了,要释放内存。至于90可以理解为incoming状态,提前发现问题,也符合lmk思想。

对于95以上的,shift_adj直接置1了。

对于90-94之间的,要满足一定条件才能触发,很明显,相比lowmem_scan,这里就把空进程的minfree换成了vmpressure_file_min。

为了保证在空进程时系统thrashing也能杀进程,一般vmpressure_file_min要高于minfree max。