From 41d0b333942b35b39d5e6d6dbf46438f15966469 Mon Sep 17 00:00:00 2001 From: Michal Bloch Date: Mon, 7 Oct 2019 16:42:46 +0200 Subject: [PATCH] Port vmpressure-lowmem-handler.c Change-Id: I21fe594cd921aea9943f82bb968e3759d8226fcf --- src/common/memory-common.h | 10 + src/memory/memcontrol.c | 22 +++ src/memory/vmpressure-lowmem-handler.c | 348 +++++++++++++++++++++++++++------ 3 files changed, 315 insertions(+), 65 deletions(-) diff --git a/src/common/memory-common.h b/src/common/memory-common.h index 0781a82..872b87e 100644 --- a/src/common/memory-common.h +++ b/src/common/memory-common.h @@ -72,6 +72,11 @@ enum lowmem_control_type { #define MEMCG_DEFAULT_EVENT_LEVEL "low" #define MEMCG_DEFAULT_USE_HIERARCHY 0 +#define MEMCG_LOW_RATIO 0.8 +#define MEMCG_MEDIUM_RATIO 0.96 +#define MEMCG_FOREGROUND_LEAVE_RATIO 0.25 + + #define LOWMEM_ROOT_CGROUP "/sys/fs/cgroup/memory" #define LOWMEM_APPS_CGROUP LOWMEM_ROOT_CGROUP"/Apps" #define LOWMEM_BGLOCKED_CGROUP LOWMEM_ROOT_CGROUP"/Apps/BgLocked" @@ -88,6 +93,7 @@ enum lowmem_control_type { #define MEMCG_SWAPNESS_PATH "memory.swappiness" #define MEMPS_LOG_PATH "/var/log" +#define MEMPS_LOG_FILE MEMPS_LOG_PATH"/memps" struct memcg_info { /* name of memory cgroup */ @@ -105,6 +111,7 @@ struct memcg_info { unsigned int threshold[LOWMEM_MAX_LEVEL]; unsigned int threshold_leave; int evfd; + int swappiness; }; struct memcg { @@ -121,6 +128,9 @@ struct lowmem_control_data { int args[2]; }; +void memcg_info_set_limit(struct memcg_info *memcg_info, float ratio, + unsigned int totalram); +void memcg_info_set_swappiness(struct memcg_info *mi, int swappiness); void memcg_init(struct memcg *memcg); /** diff --git a/src/memory/memcontrol.c b/src/memory/memcontrol.c index 5a2d622..72eb99f 100644 --- a/src/memory/memcontrol.c +++ b/src/memory/memcontrol.c @@ -45,6 +45,28 @@ #define BUF_MAX 1023 +void memcg_info_set_limit(struct memcg_info *mi, float ratio, + unsigned int totalram) +{ + if (!mi) + return; + + mi->limit = (float)totalram * ratio; + mi->limit_ratio = ratio; + mi->threshold[LOWMEM_LOW] = (unsigned int)(mi->limit * MEMCG_LOW_RATIO); + mi->threshold[LOWMEM_MEDIUM] = (unsigned int)(mi->limit * MEMCG_MEDIUM_RATIO); + mi->threshold_leave = (float)mi->limit * MEMCG_FOREGROUND_LEAVE_RATIO; + mi->oomleave = mi->limit - mi->threshold_leave; +} + +void memcg_info_set_swappiness(struct memcg_info *mi, int swappiness) +{ + if (!mi) + return; + + mi->swappiness = swappiness; +} + void memcg_init(struct memcg *memcg) { memcg->use_hierarchy = MEMCG_DEFAULT_USE_HIERARCHY; diff --git a/src/memory/vmpressure-lowmem-handler.c b/src/memory/vmpressure-lowmem-handler.c index 12ab16f..9a7cfec 100644 --- a/src/memory/vmpressure-lowmem-handler.c +++ b/src/memory/vmpressure-lowmem-handler.c @@ -70,6 +70,7 @@ #define LOWMEM_NO_LIMIT 0 #define LOWMEM_THRES_INIT 0 +#define MEMPS_EXEC_PATH "usr/bin/memps" #define MEMCG_MOVE_CHARGE_PATH "memory.move_charge_at_immigrate" #define MEMCG_EVENTFD_MEMORY_PRESSURE "memory.pressure_level" #define MEM_CONF_FILE RD_CONFIG_FILE(memory) @@ -82,7 +83,9 @@ #define BUF_MAX 1024 #define MAX_VICTIMS_BETWEEN_CHECK 3 +#define MAX_PROACTIVE_LOW_VICTIMS 2 #define MAX_PROACTIVE_HIGH_VICTIMS 4 +#define FOREGROUND_VICTIMS 1 #define OOM_TIMER_INTERVAL 2 #define OOM_KILLER_PRIORITY -20 #define MAX_MEMPS_LOGS 50 @@ -264,8 +267,9 @@ static void medium_act(void); static size_t cur_mem_state = LOWMEM_NORMAL; static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS; static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK; +static int default_swappiness = -1; -static unsigned long long totalram; +static unsigned long totalram; static unsigned long ktotalram; static struct module_ops memory_modules_ops; @@ -274,6 +278,7 @@ static bool oom_popup_enable; static bool oom_popup; static bool memcg_swap_status; static bool bg_reclaim; +static int fragmentation_size; static struct memcg_info gmi[MEMCG_MAX] = { {LOWMEM_ROOT_CGROUP, "/", MEMCG_ROOT,}, @@ -332,18 +337,12 @@ static int lowmem_launch_oompopup(void) static inline void get_total_memory(void) { struct sysinfo si; - unsigned long long total_memory; - if (totalram) return; if (!sysinfo(&si)) { - total_memory = (unsigned long long)si.totalram * si.mem_unit; - totalram = total_memory; - - /* ktotalram can cover up to 4TB */ - total_memory = BYTE_TO_KBYTE(totalram); - ktotalram = (total_memory >= ULONG_MAX) ? ULONG_MAX : total_memory; + totalram = si.totalram; + ktotalram = BYTE_TO_KBYTE(totalram); } } @@ -415,6 +414,28 @@ static int memps_file_select(const struct dirent *entry) return strstr(entry->d_name, "memps") ? 1 : 0; } +static char *strrstr(const char *str, const char *token) +{ + int len = strlen(token); + const char *p = str + strlen(str); + + while (str <= --p) + if (p[0] == token[0] && strncmp(p, token, len) == 0) + return (char *)p; + + return NULL; +} + +static int timesort(const struct dirent **a, const struct dirent **b) +{ + long long time1, time2; + + time1 = atoll(strtok(strrstr((*a)->d_name, "_"), "_")); + time2 = atoll(strtok(strrstr((*b)->d_name, "_"), "_")); + + return (time1 - time2); +} + int clear_logs(void *data) { struct dirent **namelist; @@ -435,7 +456,7 @@ int clear_logs(void *data) return RESOURCED_ERROR_INVALID_PARAMETER; } - n = scandir(dir, &namelist, memps_file_select, alphasort); + n = scandir(dir, &namelist, memps_file_select, timesort); _D("num of log files %d", n); if (n < MAX_MEMPS_LOGS) { while (n--) @@ -470,11 +491,11 @@ int clear_logs(void *data) void make_memps_log(char *file, pid_t pid, char *victim_name) { - _cleanup_fclose_ FILE *f = NULL; time_t now; struct tm cur_tm; char new_log[BUF_MAX]; static pid_t old_pid; + int oom_score_adj = 0, ret; if (old_pid == pid) return; @@ -488,22 +509,34 @@ void make_memps_log(char *file, pid_t pid, char *victim_name) } snprintf(new_log, sizeof(new_log), - "%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", file, victim_name, - pid, (1900 + cur_tm.tm_year), 1 + cur_tm.tm_mon, - cur_tm.tm_mday, cur_tm.tm_hour, cur_tm.tm_min, - cur_tm.tm_sec); - - f = fopen(new_log, "w"); - if (!f) { - _E("fail to create memps log %s", new_log); - return; - } + "%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", file, victim_name, + pid, (1900 + cur_tm.tm_year), 1 + cur_tm.tm_mon, + cur_tm.tm_mday, cur_tm.tm_hour, cur_tm.tm_min, + cur_tm.tm_sec); + + ret = proc_get_oom_score_adj(pid, &oom_score_adj); + if (ret || oom_score_adj > OOMADJ_BACKGRD_LOCKED) { - proc_print_meninfo(f); + _cleanup_fclose_ FILE *f = NULL; + + f = fopen(new_log, "w"); + if (!f) { + _E("fail to create memps log %s", new_log); + return; + } + proc_print_meninfo(f); + + } else { + + const char *argv[4] = {"/usr/bin/memps", "-f", NULL, NULL}; + + argv[2] = new_log; + exec_cmd(ARRAY_SIZE(argv), argv); + } } static int lowmem_kill_victim(const struct task_info *tsk, - int flags, unsigned int *victim_size) + int flags, int memps_log, unsigned int *victim_size) { pid_t pid; int ret; @@ -520,21 +553,26 @@ static int lowmem_kill_victim(const struct task_info *tsk, if (ret == RESOURCED_ERROR_FAIL) return RESOURCED_ERROR_FAIL; - if (!strcmp("crash-worker", appname) || + if (!strcmp("memps", appname) || + !strcmp("crash-worker", appname) || !strcmp("system-syspopup", appname)) { _E("%s(%d) was selected, skip it", appname, pid); return RESOURCED_ERROR_FAIL; } + if (!memps_log) + make_memps_log(MEMPS_LOG_FILE, pid, appname); + + pai = find_app_info(pid); if (pai) { resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST, pid, NULL, NULL, PROC_TYPE_NONE); - if (tsk->oom_score_adj < OOMADJ_BACKGRD_LOCKED) { + if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) { sigterm = 1; - } else if (tsk->oom_score_adj == OOMADJ_BACKGRD_LOCKED) { + } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED && tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) { int app_flag = pai->flags; sigterm = app_flag & PROC_SIGTERM; } @@ -555,13 +593,15 @@ static int lowmem_kill_victim(const struct task_info *tsk, tsk->size, sigterm); *victim_size = tsk->size; - if (tsk->oom_score_adj > OOMADJ_FOREGRD_UNLOCKED) + if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED) return RESOURCED_ERROR_NONE; if (oom_popup_enable && !oom_popup) { lowmem_launch_oompopup(); oom_popup = true; } + if (memps_log) + make_memps_log(MEMPS_LOG_FILE, pid, appname); return RESOURCED_ERROR_NONE; } @@ -571,7 +611,11 @@ static int lowmem_check_kill_continued(struct task_info *tsk, int flags) { unsigned int available; - if (tsk->oom_score_adj > OOMADJ_BACKGRD_PERCEPTIBLE) + /* + * Processes with the priority higher than perceptible are killed + * only when the available memory is less than dynamic oom threshold. + */ + if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE) return LOWMEM_RECLAIM_CONT; if ((flags & (OOM_FORCE|OOM_SINGLE_SHOT)) || !(flags & OOM_REVISE)) { @@ -597,8 +641,8 @@ static int compare_victims(const struct task_info *ta, const struct task_info *t assert(ta != NULL); assert(tb != NULL); - if (ta->oom_score_adj != tb->oom_score_adj) - return tb->oom_score_adj - ta->oom_score_adj; + if (ta->oom_score_lru != tb->oom_score_lru) + return tb->oom_score_lru - ta->oom_score_lru; /* * Get memory usage for tasks with the same oom score. @@ -612,6 +656,24 @@ static int compare_victims(const struct task_info *ta, const struct task_info *t return (int)(tb->size) - (int)(ta->size); } +static int compare_victims_point(const struct task_info *ta, const struct task_info *tb) +{ + unsigned int pa, pb; + + assert(ta != NULL); + assert(tb != NULL); + /* + * followed by kernel badness point calculation using heuristic. + * oom_score_adj is normalized by its unit, which varies -1000 ~ 1000. + * Since we only consider tasks with oom_score_adj larger than 0 + * as victim candidates, point always has positive value. + */ + pa = ta->oom_score_lru * (ktotalram / 1000) + ta->size; + pb = tb->oom_score_lru * (ktotalram / 1000) + tb->size; + + return pb - pa; +} + static void lowmem_free_task_info_array(GArray *array) { int i; @@ -627,14 +689,18 @@ static void lowmem_free_task_info_array(GArray *array) g_array_free(array, true); } -static unsigned int is_memory_recovered(unsigned int *avail, unsigned int *thres) +static inline int is_dynamic_process_killer(int flags) +{ + return (flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK); +} + +static unsigned int is_memory_recovered(unsigned int *avail, unsigned int thres) { unsigned int available = proc_get_mem_available(); - unsigned int leave_threshold = memcg_root->threshold_leave; unsigned int should_be_freed = 0; - if (available < leave_threshold) - should_be_freed = leave_threshold - available; + if (available < thres) + should_be_freed = thres - available; /* * free THRESHOLD_MARGIN more than real should be freed, * because launching app is consuming up the memory. @@ -643,12 +709,70 @@ static unsigned int is_memory_recovered(unsigned int *avail, unsigned int *thres should_be_freed += THRESHOLD_MARGIN; *avail = available; - *thres = leave_threshold; _I("should_be_freed = %u MB", should_be_freed); return should_be_freed; } +static int lowmem_get_pids_proc(GArray *pids, bool add_app) +{ + DIR *dp; + struct dirent *dentry; + + dp = opendir("/proc"); + if (!dp) { + _E("fail to open /proc"); + return RESOURCED_ERROR_FAIL; + } + while ((dentry = readdir(dp)) != NULL) { + struct task_info tsk; + pid_t pid = 0, pgid = 0; + int oom = 0; + + if (!isdigit(dentry->d_name[0])) + continue; + + pid = (pid_t)atoi(dentry->d_name); + if (pid < 1) + /* skip invalid pids or kernel processes */ + continue; + + pgid = getpgid(pid); + if (pgid < 1) + continue; + + if (proc_get_oom_score_adj(pid, &oom) < 0) { + _D("pid(%d) was already terminated", pid); + continue; + } + + /* + * Check whether this array includes applications or not. + * If it doesn't require to get applications + * and pid has been already included in pai, + * skip to append. + */ + if (!add_app && find_app_info(pid)) + continue; + + /* + * Currently, for tasks in the memory cgroup, + * do not consider multiple tasks with one pgid. + */ + tsk.pid = pid; + tsk.pgid = pgid; + tsk.oom_score_adj = oom; + tsk.oom_score_lru = oom; + tsk.pids = NULL; + tsk.size = lowmem_get_task_mem_usage_rss(&tsk); + + g_array_append_val(pids, tsk); + } + + closedir(dp); + return RESOURCED_ERROR_NONE; +} + /** * @brief Terminate up to max_victims processes after finding them from pai. It depends on proc_app_info lists @@ -671,7 +795,6 @@ static int lowmem_kill_victims(int max_victims, int i, ret, victim = 0; unsigned int victim_size = 0; unsigned int total_victim_size = 0; - unsigned int total_task_size = 0; int status = LOWMEM_RECLAIM_NONE; GArray *candidates = NULL; GSList *iter, *iterchild; @@ -700,6 +823,17 @@ static int lowmem_kill_victims(int max_victims, ti.pgid = getpgid(ti.pid); ti.oom_score_adj = oom_score_adj; + /* + * Before oom_score_adj of favourite (oom_score = 270) applications is + * independent of lru_state, now we consider lru_state, while + * killing favourite process. + */ + + if (oom_score_adj == OOMADJ_FAVORITE && pai->lru_state >= PROC_BACKGROUND) + ti.oom_score_lru = OOMADJ_FAVORITE + OOMADJ_FAVORITE_APP_INCREASE * pai->lru_state; + else + ti.oom_score_lru = oom_score_adj; + if (pai->childs) { ti.pids = g_array_new(false, false, sizeof(pid_t)); g_array_append_val(ti.pids, ti.pid); @@ -710,9 +844,7 @@ static int lowmem_kill_victims(int max_victims, } else ti.pids = NULL; - ti.size = lowmem_get_task_mem_usage_rss(&ti); g_array_append_val(candidates, ti); - total_task_size += ti.size; } proc_app_list_close(); @@ -720,7 +852,26 @@ static int lowmem_kill_victims(int max_victims, if (!candidates->len) goto leave; - g_array_sort(candidates, (GCompareFunc)compare_victims); + for (i = 0; i < candidates->len; i++) { + struct task_info *tsk; + + tsk = &g_array_index(candidates, struct task_info, i); + tsk->size = lowmem_get_task_mem_usage_rss(tsk); + } + + /* + * In case of start_oom == OOMADJ_SU, + * we're going to try to kill some of processes in /proc + * to handle low memory situation. + * It can find malicious system process even though it has low oom score. + */ + if (start_oom == OOMADJ_SU) + lowmem_get_pids_proc(candidates, false); + + if (start_oom <= OOMADJ_BACKGRD_LOCKED || start_oom >= OOMADJ_BACKGRD_OLD) + g_array_sort(candidates, (GCompareFunc)compare_victims_point); + else + g_array_sort(candidates, (GCompareFunc)compare_victims); for (i = 0; i < candidates->len; i++) { struct task_info *tsk; @@ -757,7 +908,7 @@ static int lowmem_kill_victims(int max_victims, _I("select victims from proc_app_list pid(%d)\n", tsk->pid); - ret = lowmem_kill_victim(tsk, flags, &victim_size); + ret = lowmem_kill_victim(tsk, flags, i, &victim_size); if (ret != RESOURCED_ERROR_NONE) continue; victim++; @@ -796,7 +947,7 @@ static void lowmem_handle_request(struct lowmem_control *ctl) int start_oom, end_oom; int count = 0, victim_cnt = 0; int status = LOWMEM_RECLAIM_NONE; - unsigned int available = 0, leave_threshold = 0; + unsigned int available = 0; unsigned int total_size = 0; unsigned int current_size = 0; unsigned int reclaim_size, shortfall = 0; @@ -815,7 +966,7 @@ retry: /* Prepare LMK to start doing it's job. Check preconditions. */ calualate_range_of_oom(lmk_type, &start_oom, &end_oom); lmk_start_threshold = memcg_root->threshold[LOWMEM_MEDIUM]; - shortfall = is_memory_recovered(&available, &leave_threshold); + shortfall = is_memory_recovered(&available, ctl->size); if (!shortfall || !reclaim_size) { status = LOWMEM_RECLAIM_DONE; @@ -859,13 +1010,32 @@ retry: (Make sluggish or kill same victims continuously) Thus, otherwise, just return in first operation and wait some period. */ - if ((count < ctl->count) && (ctl->flags & OOM_IN_DEPTH)) { + if (count < ctl->count) { if (lmk_type == LMK_OLDEST) { - /* We tried in inactive processes and didn't succeed, try immediately in active */ - _D("Inactive wasn't enough, lets try in Active."); + _D("Oldest wasn't enough, lets try in RECENTLY USED."); + lmk_type = LMK_RECENTLY_USE; + goto retry; + } else if (lmk_type == LMK_RECENTLY_USE) { + /* We tried in inactive processes and didn't succed, try immediatly in active */ + _D("Recenlty used wasn't enough, lets try in Active."); lmk_type = LMK_ACTIVE; + + /* + * In case of force reclaim, leave threshold is harger than original threshold as margin. + * So it should be reduced when trying to kill applications in ACTIVE group + * in order to prevent aggresive killing of perceptible applications. + */ + if ((ctl->flags & OOM_FORCE) && + (ctl->count - count > MAX_PROACTIVE_LOW_VICTIMS)) + ctl->count = MAX_PROACTIVE_LOW_VICTIMS; + goto retry; + } else if ((lmk_type == LMK_ACTIVE) && (ctl->flags & OOM_IN_DEPTH)) { + /* We tried in inactive processes and didn't succed, try immediatly in active */ + _D("Recenlty used wasn't enough, lets try in foreground."); + lmk_type = LMK_FOREGROUND; + ctl->count = FOREGROUND_VICTIMS; goto retry; - } else if (lmk_type == LMK_ACTIVE) { + } else if ((lmk_type == LMK_FOREGROUND) && (ctl->flags & OOM_IN_DEPTH)) { /* * We tried in INACTIVE and ACTIVE but still didn't succeed * so it's time to try in /proc. Before doing it wait some time. @@ -879,9 +1049,8 @@ retry: done: _E("Done: killed %d processes reclaimed: %u remaining: %u shortfall: %u status: %d\n", count, total_size, reclaim_size, shortfall, status); - /* After we finish reclaiming it's worth to remove oldest memps logs */ - if (status == LOWMEM_RECLAIM_DONE) + if (count) request_helper_worker(CLEAR_LOGS, MEMPS_LOG_PATH, clear_logs, NULL); ctl->status = status; } @@ -1297,6 +1466,9 @@ static int set_memory_config(const char *section_name, const struct parse_result } else if (!strncmp(result->name, "ThresholdLeave", strlen("ThresholdLeave")+1)) { int value = atoi(result->value); lowmem_memcg_set_leave_threshold(MEMCG_MEMORY, value); + } else if (!strncmp(result->name, "ForegroundRatio", strlen("ForegroundRatio")+1)) { + float ratio = atof(result->value); + memcg_info_set_limit(memcg_tree[MEMCG_APPS]->info, ratio, totalram); } else if (!strncmp(result->name, "NumMaxVictims", strlen("NumMaxVictims")+1)) { int value = atoi(result->value); num_max_victims = value; @@ -1318,6 +1490,18 @@ static int set_memory_config(const char *section_name, const struct parse_result event_level = strdup(result->value); if (!event_level) return RESOURCED_ERROR_OUT_OF_MEMORY; + } else if (!strncmp(result->name, "SWAPPINESS", strlen("SWAPPINESS")+1)) { + int value = atoi(result->value); + default_swappiness = value; + memcg_info_set_swappiness(memcg_tree[MEMCG_MEMORY]->info, value); + } else if (!strncmp(result->name, "APPCG_SWAPPINESS", strlen("APPCG_SWAPPINESS")+1)) { + int value = atoi(result->value); + memcg_info_set_swappiness(memcg_tree[MEMCG_APPS]->info, value); + } else if (!strncmp(result->name, "SWAPCG_SWAPPINESS", strlen("SWAPCG_SWAPPINESS")+1)) { + int value = atoi(result->value); + memcg_info_set_swappiness(memcg_tree[MEMCG_SWAP]->info, value); + } else if (!strncmp(result->name, "NumFragSize", strlen("NumFragSize")+1)) { + fragmentation_size = atoi(result->value); } return RESOURCED_ERROR_NONE; @@ -1470,6 +1654,7 @@ static int write_params_memcg_info(struct memcg_info *mi) unsigned int limit = mi->limit; const char *name = mi->name; int ret = RESOURCED_ERROR_NONE; + int swappiness = -1; _I("write memcg param for %s", name); /* enable cgroup move */ ret = cgroup_write_node_uint32(name, @@ -1477,6 +1662,24 @@ static int write_params_memcg_info(struct memcg_info *mi) if (ret) return ret; + /* + * write swapness if it has a meaningful value. + * if it has own swappiness value, set it to memcg at first. + * otherwise, check default_swappiness value and use it. + */ + if (mi->swappiness >= 0) + swappiness = mi->swappiness; + else if (default_swappiness >= 0) + swappiness = default_swappiness; + + if (swappiness >= 0) { + ret = cgroup_write_node_uint32(name, + MEMCG_SWAPNESS_PATH, swappiness); + if (ret) + _I("failed to write %s %d to %s the", + MEMCG_SWAPNESS_PATH, swappiness, name); + } + if (mi->limit_ratio == LOWMEM_NO_LIMIT) return ret; @@ -1771,9 +1974,7 @@ static int lowmem_press_setup_eventfd(void) if (!memcg_tree[i]->use_hierarchy) continue; - const int r = lowmem_press_register_eventfd(memcg_tree[i]->info); - if (r < 0) - return RESOURCED_ERROR_FAIL; + lowmem_press_register_eventfd(memcg_tree[i]->info); } return RESOURCED_ERROR_NONE; } @@ -1825,7 +2026,14 @@ bool lowmem_fragmentated(void) if (ret < 0) return false; - if (bi.page[PAGE_32K] + bi.page[PAGE_64K] + bi.page[PAGE_128K] == 0) { + /* + * The fragmentation_size is the minimum count of order-2 pages in "Normal" zone. + * If total buddy pages is smaller than fragmentation_size, + * resourced will detect kernel memory is fragmented. + * Default value is zero in low memory device. + */ + if (bi.page[PAGE_32K] + (bi.page[PAGE_64K] << 1) + (bi.page[PAGE_128K] << 2) + + (bi.page[PAGE_256K] << 3) < fragmentation_size) { _I("fragmentation detected, need to execute proactive oom killer"); return true; } @@ -1839,13 +2047,18 @@ static void lowmem_proactive_oom_killer(int flags, char *appid) before = proc_get_mem_available(); - /* If low memory state, just return and kill in oom killer */ - if (before < memcg_root->threshold[LOWMEM_MEDIUM]) + /* If memory state is medium or normal, just return and kill in oom killer */ + if (before < memcg_root->threshold[LOWMEM_MEDIUM] || before > proactive_leave) return; victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims; +#ifdef HEART_SUPPORT + /* + * This branch is used only when HEART module is compiled in and + * it's MEMORY module must be enabled. Otherwise this is skipped. + */ struct heart_memory_data *md = heart_memory_get_memdata(appid, DATA_LATEST); if (md) { unsigned int rss, after, size; @@ -1873,13 +2086,7 @@ static void lowmem_proactive_oom_killer(int flags, char *appid) return; } - - /* - * run proactive oom killer only when available is larger than - * proactive threshold - */ - if (!proactive_threshold || before >= proactive_threshold) - return; +#endif /* * When there is no history data for the launching app, @@ -1887,9 +2094,20 @@ static void lowmem_proactive_oom_killer(int flags, char *appid) * So, resourced feels proactive LMK is required, run oom killer based on dynamic * threshold. */ - if (!lowmem_fragmentated() && !(flags & PROC_LARGEMEMORY)) + if (lowmem_fragmentated()) + goto reclaim; + + /* + * run proactive oom killer only when available is larger than + * dynamic process threshold + */ + if (!proactive_threshold || before >= proactive_threshold) return; + if (!(flags & PROC_LARGEMEMORY)) + return; + +reclaim: /* * free THRESHOLD_MARGIN more than real should be freed, * because launching app is consuming up the memory. @@ -1897,7 +2115,6 @@ static void lowmem_proactive_oom_killer(int flags, char *appid) _D("Run threshold based proactive LMK: memory level to reach: %u\n", proactive_leave + THRESHOLD_MARGIN); lowmem_trigger_reclaim(0, victims, LMK_OLDEST, proactive_leave + THRESHOLD_MARGIN); - return; } unsigned int lowmem_get_proactive_thres(void) @@ -1908,9 +2125,10 @@ unsigned int lowmem_get_proactive_thres(void) static int lowmem_prelaunch_handler(void *data) { struct proc_status *ps = (struct proc_status *)data; + struct proc_app_info *pai = ps->pai; - if (!ps->pai) - return RESOURCED_ERROR_NO_DATA; + if (!pai || CHECK_BIT(pai->flags, PROC_SERVICEAPP)) + return RESOURCED_ERROR_NONE; lowmem_proactive_oom_killer(ps->pai->flags, ps->pai->appid); return RESOURCED_ERROR_NONE; -- 2.7.4