summaryrefslogtreecommitdiffstats
path: root/lmkd
diff options
context:
space:
mode:
authorSuren Baghdasaryan <surenb@google.com>2018-04-13 13:53:43 -0700
committerSuren Baghdasaryan <surenb@google.com>2018-04-15 16:02:36 +0000
commitc09b53db7bdc312ed81d7d82cb634b59a0e825bf (patch)
treefc3d531d198811720362c6bad631e9f9c4576366 /lmkd
parent5176b4b37ab17d23ab1069d3394acb28f0a946a3 (diff)
downloadsystem_core-c09b53db7bdc312ed81d7d82cb634b59a0e825bf.tar.gz
system_core-c09b53db7bdc312ed81d7d82cb634b59a0e825bf.tar.bz2
system_core-c09b53db7bdc312ed81d7d82cb634b59a0e825bf.zip
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 Merged-In: I6b51972951026854a079fcda33d6786b7ed035e4 Change-Id: I6b51972951026854a079fcda33d6786b7ed035e4 Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Diffstat (limited to 'lmkd')
-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 5eb3fbe15..151e1dc7b 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -109,6 +109,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 {
@@ -972,11 +973,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];
for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
struct proc *procp;
@@ -1071,9 +1071,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,
@@ -1114,11 +1119,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);
}
@@ -1167,39 +1201,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);
}
}
}
@@ -1409,6 +1462,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);
if (!init()) {
if (!use_inkernel_interface) {