lmkd: Introduce support for legacy kill algorithm that uses minfree levels
am: ffdc4ddb25 Change-Id: Ic18a67fe5cbdf541f1b6c439e2b7f0488d4d1dcf
This commit is contained in:
commit
49319cb426
|
|
@ -29,6 +29,11 @@ properties:
|
||||||
ro.config.low_ram: choose between low-memory vs high-performance
|
ro.config.low_ram: choose between low-memory vs high-performance
|
||||||
device. Default = false.
|
device. Default = false.
|
||||||
|
|
||||||
|
ro.lmk.use_minfree_levels: use free memory and file cache thresholds for
|
||||||
|
making decisions when to kill. This mode works
|
||||||
|
the same way kernel lowmemorykiller driver used
|
||||||
|
to work. Default = false
|
||||||
|
|
||||||
ro.lmk.low: min oom_adj score for processes eligible to be
|
ro.lmk.low: min oom_adj score for processes eligible to be
|
||||||
killed at low vmpressure level. Default = 1001
|
killed at low vmpressure level. Default = 1001
|
||||||
(disabled)
|
(disabled)
|
||||||
|
|
|
||||||
107
lmkd.c
107
lmkd.c
|
|
@ -113,6 +113,7 @@ static int64_t downgrade_pressure;
|
||||||
static bool low_ram_device;
|
static bool low_ram_device;
|
||||||
static bool kill_heaviest_task;
|
static bool kill_heaviest_task;
|
||||||
static unsigned long kill_timeout_ms;
|
static unsigned long kill_timeout_ms;
|
||||||
|
static bool use_minfree_levels;
|
||||||
|
|
||||||
/* data required to handle events */
|
/* data required to handle events */
|
||||||
struct event_handler_info {
|
struct event_handler_info {
|
||||||
|
|
@ -1046,11 +1047,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj,
|
||||||
* Returns the size of the killed processes.
|
* Returns the size of the killed processes.
|
||||||
*/
|
*/
|
||||||
static int find_and_kill_processes(enum vmpressure_level level,
|
static int find_and_kill_processes(enum vmpressure_level level,
|
||||||
int pages_to_free) {
|
int min_score_adj, int pages_to_free) {
|
||||||
int i;
|
int i;
|
||||||
int killed_size;
|
int killed_size;
|
||||||
int pages_freed = 0;
|
int pages_freed = 0;
|
||||||
int min_score_adj = level_oomadj[level];
|
|
||||||
|
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
if (enable_stats_log) {
|
if (enable_stats_log) {
|
||||||
|
|
@ -1164,9 +1164,14 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
||||||
int64_t mem_pressure;
|
int64_t mem_pressure;
|
||||||
enum vmpressure_level lvl;
|
enum vmpressure_level lvl;
|
||||||
union meminfo mi;
|
union meminfo mi;
|
||||||
|
union zoneinfo zi;
|
||||||
static struct timeval last_report_tm;
|
static struct timeval last_report_tm;
|
||||||
static unsigned long skip_count = 0;
|
static unsigned long skip_count = 0;
|
||||||
enum vmpressure_level level = (enum vmpressure_level)data;
|
enum vmpressure_level level = (enum vmpressure_level)data;
|
||||||
|
long other_free = 0, other_file = 0;
|
||||||
|
int min_score_adj;
|
||||||
|
int pages_to_free = 0;
|
||||||
|
int minfree = 0;
|
||||||
static struct reread_data mem_usage_file_data = {
|
static struct reread_data mem_usage_file_data = {
|
||||||
.filename = MEMCG_MEMORY_USAGE,
|
.filename = MEMCG_MEMORY_USAGE,
|
||||||
.fd = -1,
|
.fd = -1,
|
||||||
|
|
@ -1207,11 +1212,40 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
||||||
skip_count = 0;
|
skip_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meminfo_parse(&mi) < 0) {
|
if (meminfo_parse(&mi) < 0 || zoneinfo_parse(&zi) < 0) {
|
||||||
ALOGE("Failed to get free memory!");
|
ALOGE("Failed to get free memory!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_minfree_levels) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
other_free = mi.field.nr_free_pages - zi.field.totalreserve_pages;
|
||||||
|
if (mi.field.nr_file_pages > (mi.field.shmem + mi.field.unevictable + mi.field.swap_cached)) {
|
||||||
|
other_file = (mi.field.nr_file_pages - mi.field.shmem -
|
||||||
|
mi.field.unevictable - mi.field.swap_cached);
|
||||||
|
} else {
|
||||||
|
other_file = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
min_score_adj = OOM_SCORE_ADJ_MAX + 1;
|
||||||
|
for (i = 0; i < lowmem_targets_size; i++) {
|
||||||
|
minfree = lowmem_minfree[i];
|
||||||
|
if (other_free < minfree && other_file < minfree) {
|
||||||
|
min_score_adj = lowmem_adj[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min_score_adj == OOM_SCORE_ADJ_MAX + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Free up enough pages to push over the highest minfree level */
|
||||||
|
pages_to_free = lowmem_minfree[lowmem_targets_size - 1] -
|
||||||
|
((other_free < other_file) ? other_free : other_file);
|
||||||
|
goto do_kill;
|
||||||
|
}
|
||||||
|
|
||||||
if (level == VMPRESS_LEVEL_LOW) {
|
if (level == VMPRESS_LEVEL_LOW) {
|
||||||
record_low_pressure_levels(&mi);
|
record_low_pressure_levels(&mi);
|
||||||
}
|
}
|
||||||
|
|
@ -1260,39 +1294,58 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
||||||
do_kill:
|
do_kill:
|
||||||
if (low_ram_device) {
|
if (low_ram_device) {
|
||||||
/* For Go devices kill only one task */
|
/* For Go devices kill only one task */
|
||||||
if (find_and_kill_processes(level, 0) == 0) {
|
if (find_and_kill_processes(level, level_oomadj[level], 0) == 0) {
|
||||||
if (debug_process_killing) {
|
if (debug_process_killing) {
|
||||||
ALOGI("Nothing to kill");
|
ALOGI("Nothing to kill");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* If pressure level is less than critical and enough free swap then ignore */
|
int pages_freed;
|
||||||
if (level < VMPRESS_LEVEL_CRITICAL &&
|
|
||||||
mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
|
if (!use_minfree_levels) {
|
||||||
if (debug_process_killing) {
|
/* If pressure level is less than critical and enough free swap then ignore */
|
||||||
ALOGI("Ignoring pressure since %" PRId64
|
if (level < VMPRESS_LEVEL_CRITICAL &&
|
||||||
" swap pages are available ",
|
mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
|
||||||
mi.field.free_swap);
|
if (debug_process_killing) {
|
||||||
|
ALOGI("Ignoring pressure since %" PRId64
|
||||||
|
" swap pages are available ",
|
||||||
|
mi.field.free_swap);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Free up enough memory to downgrate the memory pressure to low level */
|
||||||
|
if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) {
|
||||||
|
pages_to_free = low_pressure_mem.max_nr_free_pages -
|
||||||
|
mi.field.nr_free_pages;
|
||||||
|
} else {
|
||||||
|
if (debug_process_killing) {
|
||||||
|
ALOGI("Ignoring pressure since more memory is "
|
||||||
|
"available (%" PRId64 ") than watermark (%" PRId64 ")",
|
||||||
|
mi.field.nr_free_pages, low_pressure_mem.max_nr_free_pages);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
min_score_adj = level_oomadj[level];
|
||||||
|
} else {
|
||||||
|
if (debug_process_killing) {
|
||||||
|
ALOGI("Killing because cache %ldkB is below "
|
||||||
|
"limit %ldkB for oom_adj %d\n"
|
||||||
|
" Free memory is %ldkB %s reserved",
|
||||||
|
other_file * page_k, minfree * page_k, min_score_adj,
|
||||||
|
other_free * page_k, other_free >= 0 ? "above" : "below");
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free up enough memory to downgrate the memory pressure to low level */
|
if (debug_process_killing) {
|
||||||
if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) {
|
ALOGI("Trying to free %d pages", pages_to_free);
|
||||||
int pages_to_free = low_pressure_mem.max_nr_free_pages -
|
}
|
||||||
mi.field.nr_free_pages;
|
pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
|
||||||
|
if (pages_freed < pages_to_free) {
|
||||||
if (debug_process_killing) {
|
if (debug_process_killing) {
|
||||||
ALOGI("Trying to free %d pages", pages_to_free);
|
ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed);
|
||||||
}
|
|
||||||
int pages_freed = find_and_kill_processes(level, pages_to_free);
|
|
||||||
if (pages_freed < pages_to_free) {
|
|
||||||
if (debug_process_killing) {
|
|
||||||
ALOGI("Unable to free enough memory (pages freed=%d)",
|
|
||||||
pages_freed);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gettimeofday(&last_report_tm, NULL);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
gettimeofday(&last_report_tm, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1502,6 +1555,8 @@ int main(int argc __unused, char **argv __unused) {
|
||||||
low_ram_device = property_get_bool("ro.config.low_ram", false);
|
low_ram_device = property_get_bool("ro.config.low_ram", false);
|
||||||
kill_timeout_ms =
|
kill_timeout_ms =
|
||||||
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
|
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
|
||||||
|
use_minfree_levels =
|
||||||
|
property_get_bool("ro.lmk.use_minfree_levels", false);
|
||||||
|
|
||||||
#ifdef LMKD_LOG_STATS
|
#ifdef LMKD_LOG_STATS
|
||||||
statslog_init(&log_ctx, &enable_stats_log);
|
statslog_init(&log_ctx, &enable_stats_log);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue