summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuren Baghdasaryan <surenb@google.com>2018-04-13 13:53:43 -0700
committerSuren Baghdasaryan <surenb@google.com>2018-04-17 01:42:06 +0000
commitffdc4ddb2544352f7061668007acfb53fc589557 (patch)
tree6a1ddeb147ff4b934397211a9cc647397acc5f64
parent9926e57ee89a1d4de296ee1cb7113bdb215ef79d (diff)
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 d273b6630d47d6bb32996bcc87e01a73240cb228)
-rw-r--r--lmkd/README.md5
-rw-r--r--lmkd/lmkd.c105
2 files changed, 85 insertions, 25 deletions
diff --git a/lmkd/README.md b/lmkd/README.md
index ba2e83d06..656a6ea0a 100644
--- a/lmkd/README.md
+++ b/lmkd/README.md
@@ -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)
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 2bf201cee..ec55f908b 100644
--- a/lmkd/lmkd.c
+++ b/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) {
+ 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("Ignoring pressure since %" PRId64
- " swap pages are available ",
- mi.field.free_swap);
+ 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);