lmkd: Introduce support for legacy kill algorithm that uses minfree levels
Add ability to switch to the algorithm used by lowmemorykiller driver
for determining when to kill. It uses minfree levels to decide at which
levels of free memory and file cache to kill a process. oom_adj_score
is also determined by comparing current memory resources against minfree
levels.
ro.lmk.use_minfree_levels property is introduces for switching into this
mode. By default it is disabled.
Bug: 77299493
Bug: 75322373
Change-Id: I6b51972951026854a079fcda33d6786b7ed035e4
Merged-In: I6b51972951026854a079fcda33d6786b7ed035e4
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
(cherry picked from commit d273b6630d
)
This commit is contained in:
parent
9926e57ee8
commit
ffdc4ddb25
2 changed files with 86 additions and 26 deletions
|
@ -29,6 +29,11 @@ properties:
|
|||
ro.config.low_ram: choose between low-memory vs high-performance
|
||||
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
|
||||
killed at low vmpressure level. Default = 1001
|
||||
(disabled)
|
||||
|
|
107
lmkd/lmkd.c
107
lmkd/lmkd.c
|
@ -111,6 +111,7 @@ static int64_t downgrade_pressure;
|
|||
static bool low_ram_device;
|
||||
static bool kill_heaviest_task;
|
||||
static unsigned long kill_timeout_ms;
|
||||
static bool use_minfree_levels;
|
||||
|
||||
/* data required to handle events */
|
||||
struct event_handler_info {
|
||||
|
@ -1019,11 +1020,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj,
|
|||
* Returns the size of the killed processes.
|
||||
*/
|
||||
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 killed_size;
|
||||
int pages_freed = 0;
|
||||
int min_score_adj = level_oomadj[level];
|
||||
|
||||
#ifdef LMKD_LOG_STATS
|
||||
if (enable_stats_log) {
|
||||
|
@ -1137,9 +1137,14 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
|||
int64_t mem_pressure;
|
||||
enum vmpressure_level lvl;
|
||||
union meminfo mi;
|
||||
union zoneinfo zi;
|
||||
static struct timeval last_report_tm;
|
||||
static unsigned long skip_count = 0;
|
||||
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 = {
|
||||
.filename = MEMCG_MEMORY_USAGE,
|
||||
.fd = -1,
|
||||
|
@ -1180,11 +1185,40 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
|||
skip_count = 0;
|
||||
}
|
||||
|
||||
if (meminfo_parse(&mi) < 0) {
|
||||
if (meminfo_parse(&mi) < 0 || zoneinfo_parse(&zi) < 0) {
|
||||
ALOGE("Failed to get free memory!");
|
||||
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) {
|
||||
record_low_pressure_levels(&mi);
|
||||
}
|
||||
|
@ -1233,39 +1267,58 @@ static void mp_event_common(int data, uint32_t events __unused) {
|
|||
do_kill:
|
||||
if (low_ram_device) {
|
||||
/* 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) {
|
||||
ALOGI("Nothing to kill");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* If pressure level is less than critical and enough free swap then ignore */
|
||||
if (level < VMPRESS_LEVEL_CRITICAL &&
|
||||
mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
|
||||
if (debug_process_killing) {
|
||||
ALOGI("Ignoring pressure since %" PRId64
|
||||
" swap pages are available ",
|
||||
mi.field.free_swap);
|
||||
int pages_freed;
|
||||
|
||||
if (!use_minfree_levels) {
|
||||
/* If pressure level is less than critical and enough free swap then ignore */
|
||||
if (level < VMPRESS_LEVEL_CRITICAL &&
|
||||
mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
|
||||
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 (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) {
|
||||
int pages_to_free = low_pressure_mem.max_nr_free_pages -
|
||||
mi.field.nr_free_pages;
|
||||
if (debug_process_killing) {
|
||||
ALOGI("Trying to free %d pages", pages_to_free);
|
||||
}
|
||||
pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
|
||||
if (pages_freed < pages_to_free) {
|
||||
if (debug_process_killing) {
|
||||
ALOGI("Trying to free %d pages", pages_to_free);
|
||||
}
|
||||
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);
|
||||
ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed);
|
||||
}
|
||||
} else {
|
||||
gettimeofday(&last_report_tm, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1475,6 +1528,8 @@ int main(int argc __unused, char **argv __unused) {
|
|||
low_ram_device = property_get_bool("ro.config.low_ram", false);
|
||||
kill_timeout_ms =
|
||||
(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
|
||||
statslog_init(&log_ctx, &enable_stats_log);
|
||||
|
|
Loading…
Reference in a new issue