Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22dc27b9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "lmkd: Introduce support for legacy kill algorithm that uses minfree levels"

parents 5176b4b3 c09b53db
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -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)
+80 −25
Original line number Original line Diff line number Diff line
@@ -109,6 +109,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 {
@@ -972,11 +973,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];


    for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
    for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) {
        struct proc *procp;
        struct proc *procp;
@@ -1071,9 +1071,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,
@@ -1114,11 +1119,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);
    }
    }
@@ -1167,12 +1201,15 @@ 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 {
        int pages_freed;

        if (!use_minfree_levels) {
            /* If pressure level is less than critical and enough free swap then ignore */
            /* If pressure level is less than critical and enough free swap then ignore */
            if (level < VMPRESS_LEVEL_CRITICAL &&
            if (level < VMPRESS_LEVEL_CRITICAL &&
                mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
                mi.field.free_swap > low_pressure_mem.max_nr_free_pages) {
@@ -1183,26 +1220,42 @@ do_kill:
                }
                }
                return;
                return;
            }
            }

            /* Free up enough memory to downgrate the memory pressure to low level */
            /* 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) {
            if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) {
            int pages_to_free = low_pressure_mem.max_nr_free_pages -
                pages_to_free = low_pressure_mem.max_nr_free_pages -
                    mi.field.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");
            }
        }

        if (debug_process_killing) {
        if (debug_process_killing) {
            ALOGI("Trying to free %d pages", pages_to_free);
            ALOGI("Trying to free %d pages", pages_to_free);
        }
        }
            int pages_freed = find_and_kill_processes(level, pages_to_free);
        pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free);
        if (pages_freed < pages_to_free) {
        if (pages_freed < pages_to_free) {
            if (debug_process_killing) {
            if (debug_process_killing) {
                    ALOGI("Unable to free enough memory (pages freed=%d)",
                ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed);
                        pages_freed);
            }
            }
        } else {
        } else {
            gettimeofday(&last_report_tm, NULL);
            gettimeofday(&last_report_tm, NULL);
        }
        }
    }
    }
}
}
}


static bool init_mp_common(enum vmpressure_level level) {
static bool init_mp_common(enum vmpressure_level level) {
    int mpfd;
    int mpfd;
@@ -1409,6 +1462,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);


    if (!init()) {
    if (!init()) {
        if (!use_inkernel_interface) {
        if (!use_inkernel_interface) {