4 * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * @file vmpressure-lowmem-handler.c
22 * @desc lowmem handler using memcgroup
24 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
36 #include <sys/types.h>
39 #include <sys/sysinfo.h>
40 #include <sys/resource.h>
43 #include <eventsystem.h>
49 #include "lowmem-dbus.h"
50 #include "lowmem-monitor.h"
51 #include "lowmem-system.h"
52 #include "lowmem-limit.h"
53 #include "lowmem-governor.h"
54 #include "proc-common.h"
57 #include "resourced.h"
60 #include "config-parser.h"
62 #include "swap-common.h"
64 #include "memory-cgroup.h"
65 #include "heart-common.h"
66 #include "proc-main.h"
67 #include "dbus-handler.h"
69 #include "fd-handler.h"
70 #include "resourced-helper-worker.h"
71 #include "safe-kill.h"
72 #include "dedup-common.h"
74 #define MAX_VICTIMS_BETWEEN_CHECK 3
75 #define MAX_PROACTIVE_HIGH_VICTIMS 4
76 #define FOREGROUND_VICTIMS 1
77 #define OOM_KILLER_PRIORITY -20
78 #define THRESHOLD_MARGIN 10 /* MB */
80 #define MEM_SIZE_64 64 /* MB */
81 #define MEM_SIZE_256 256 /* MB */
82 #define MEM_SIZE_448 448 /* MB */
83 #define MEM_SIZE_512 512 /* MB */
84 #define MEM_SIZE_768 768 /* MB */
85 #define MEM_SIZE_1024 1024 /* MB */
86 #define MEM_SIZE_2048 2048 /* MB */
88 /* thresholds for 64M RAM*/
89 #define PROACTIVE_64_THRES 10 /* MB */
90 #define PROACTIVE_64_LEAVE 30 /* MB */
91 #define CGROUP_ROOT_64_THRES_DEDUP 16 /* MB */
92 #define CGROUP_ROOT_64_THRES_SWAP 15 /* MB */
93 #define CGROUP_ROOT_64_THRES_LOW 8 /* MB */
94 #define CGROUP_ROOT_64_THRES_MEDIUM 5 /* MB */
95 #define CGROUP_ROOT_64_THRES_LEAVE 8 /* MB */
96 #define CGROUP_ROOT_64_NUM_VICTIMS 1
98 /* thresholds for 256M RAM */
99 #define PROACTIVE_256_THRES 50 /* MB */
100 #define PROACTIVE_256_LEAVE 80 /* MB */
101 #define CGROUP_ROOT_256_THRES_DEDUP 60 /* MB */
102 #define CGROUP_ROOT_256_THRES_SWAP 40 /* MB */
103 #define CGROUP_ROOT_256_THRES_LOW 20 /* MB */
104 #define CGROUP_ROOT_256_THRES_MEDIUM 10 /* MB */
105 #define CGROUP_ROOT_256_THRES_LEAVE 20 /* MB */
106 #define CGROUP_ROOT_256_NUM_VICTIMS 2
108 /* threshold for 448M RAM */
109 #define PROACTIVE_448_THRES 80 /* MB */
110 #define PROACTIVE_448_LEAVE 100 /* MB */
111 #define CGROUP_ROOT_448_THRES_DEDUP 120 /* MB */
112 #define CGROUP_ROOT_448_THRES_SWAP 100 /* MB */
113 #define CGROUP_ROOT_448_THRES_LOW 60 /* MB */
114 #define CGROUP_ROOT_448_THRES_MEDIUM 50 /* MB */
115 #define CGROUP_ROOT_448_THRES_LEAVE 70 /* MB */
116 #define CGROUP_ROOT_448_NUM_VICTIMS 5
118 /* threshold for 512M RAM */
119 #define PROACTIVE_512_THRES 80 /* MB */
120 #define PROACTIVE_512_LEAVE 100 /* MB */
121 #define CGROUP_ROOT_512_THRES_DEDUP 140 /* MB */
122 #define CGROUP_ROOT_512_THRES_SWAP 100 /* MB */
123 #define CGROUP_ROOT_512_THRES_LOW 70 /* MB */
124 #define CGROUP_ROOT_512_THRES_MEDIUM 60 /* MB */
125 #define CGROUP_ROOT_512_THRES_LEAVE 80 /* MB */
126 #define CGROUP_ROOT_512_NUM_VICTIMS 5
128 /* threshold for 768 RAM */
129 #define PROACTIVE_768_THRES 100 /* MB */
130 #define PROACTIVE_768_LEAVE 130 /* MB */
131 #define CGROUP_ROOT_768_THRES_DEDUP 180 /* MB */
132 #define CGROUP_ROOT_768_THRES_SWAP 150 /* MB */
133 #define CGROUP_ROOT_768_THRES_LOW 90 /* MB */
134 #define CGROUP_ROOT_768_THRES_MEDIUM 80 /* MB */
135 #define CGROUP_ROOT_768_THRES_LEAVE 100 /* MB */
136 #define CGROUP_ROOT_768_NUM_VICTIMS 5
138 /* threshold for more than 1024M RAM */
139 #define PROACTIVE_1024_THRES 150 /* MB */
140 #define PROACTIVE_1024_LEAVE 230 /* MB */
141 #define CGROUP_ROOT_1024_THRES_DEDUP 400 /* MB */
142 #define CGROUP_ROOT_1024_THRES_SWAP 300 /* MB */
143 #define CGROUP_ROOT_1024_THRES_LOW 120 /* MB */
144 #define CGROUP_ROOT_1024_THRES_MEDIUM 100 /* MB */
145 #define CGROUP_ROOT_1024_THRES_LEAVE 150 /* MB */
146 #define CGROUP_ROOT_1024_NUM_VICTIMS 5
148 /* threshold for more than 2048M RAM */
149 #define PROACTIVE_2048_THRES 200 /* MB */
150 #define PROACTIVE_2048_LEAVE 500 /* MB */
151 #define CGROUP_ROOT_2048_THRES_DEDUP 400 /* MB */
152 #define CGROUP_ROOT_2048_THRES_SWAP 300 /* MB */
153 #define CGROUP_ROOT_2048_THRES_LOW 200 /* MB */
154 #define CGROUP_ROOT_2048_THRES_MEDIUM 160 /* MB */
155 #define CGROUP_ROOT_2048_THRES_LEAVE 300 /* MB */
156 #define CGROUP_ROOT_2048_NUM_VICTIMS 10
158 /* threshold for more than 3072M RAM */
159 #define PROACTIVE_3072_THRES 300 /* MB */
160 #define PROACTIVE_3072_LEAVE 700 /* MB */
161 #define CGROUP_ROOT_3072_THRES_DEDUP 600 /* MB */
162 #define CGROUP_ROOT_3072_THRES_SWAP 500 /* MB */
163 #define CGROUP_ROOT_3072_THRES_LOW 400 /* MB */
164 #define CGROUP_ROOT_3072_THRES_MEDIUM 250 /* MB */
165 #define CGROUP_ROOT_3072_THRES_LEAVE 500 /* MB */
166 #define CGROUP_ROOT_3072_NUM_VICTIMS 10
168 static unsigned proactive_threshold_mb;
169 static unsigned proactive_leave_mb;
170 static unsigned lmk_start_threshold_mb;
173 * Resourced Low Memory Killer
174 * NOTE: planned to be moved to a separate file.
176 /*-------------------------------------------------*/
177 #define OOM_TIMER_INTERVAL_SEC 2
178 #define LMW_LOOP_WAIT_TIMEOUT_MSEC OOM_TIMER_INTERVAL_SEC*(G_USEC_PER_SEC)
179 #define LMW_RETRY_WAIT_TIMEOUT_MSEC (G_USEC_PER_SEC)
181 struct lowmem_control {
183 * For each queued request the following properties
184 * are required with two exceptions:
185 * - status is being set by LMK
186 * - callback is optional
188 /* Processing flags*/
190 /* Indictator for OOM score of targeted processes */
191 enum oom_score score;
193 /* Desired size to be restored - level to be reached (MB)*/
194 unsigned int size_mb;
195 /* Max number of processes to be considered */
197 /* Memory reclaim status */
200 * Optional - if set, will be triggered by LMK once the request
203 void (*callback) (struct lowmem_control *);
206 struct lowmem_worker {
207 pthread_t worker_thread;
213 static struct lowmem_worker lmw;
215 //static int memlog_enabled;
216 //static int memlog_nr_max = DEFAULT_MEMLOG_NR_MAX;
217 /* remove logfiles to reduce to this threshold.
218 * it is about five-sixths of the memlog_nr_max. */
219 //static int memlog_remove_batch_thres = (DEFAULT_MEMLOG_NR_MAX * 5) / 6;
220 //static char *memlog_path = DEFAULT_MEMLOG_PATH;
221 //static char *memlog_prefix[MEMLOG_MAX];
223 #define LOWMEM_WORKER_IS_ACTIVE(_lmw) g_atomic_int_get(&(_lmw)->active)
224 #define LOWMEM_WORKER_ACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 1)
225 #define LOWMEM_WORKER_DEACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 0)
227 #define LOWMEM_WORKER_IS_RUNNING(_lmw) g_atomic_int_get(&(_lmw)->running)
228 #define LOWMEM_WORKER_RUN(_lmw) g_atomic_int_set(&(_lmw)->running, 1)
229 #define LOWMEM_WORKER_IDLE(_lmw) g_atomic_int_set(&(_lmw)->running, 0)
231 #define LOWMEM_NEW_REQUEST() g_slice_new0(struct lowmem_control)
233 #define LOWMEM_DESTROY_REQUEST(_ctl) \
234 g_slice_free(typeof(*(_ctl)), _ctl); \
236 #define LOWMEM_SET_REQUEST(c, __flags, __score, __size, __count, __cb) \
238 (c)->flags = __flags; (c)->score = __score; \
239 (c)->size_mb= __size; (c)->count = __count; \
240 (c)->callback = __cb; \
243 static void lowmem_queue_request(struct lowmem_worker *lmw,
244 struct lowmem_control *ctl)
246 if (LOWMEM_WORKER_IS_ACTIVE(lmw))
247 g_async_queue_push(lmw->queue, ctl);
251 static void lowmem_drain_queue(struct lowmem_worker *lmw)
253 struct lowmem_control *ctl;
255 g_async_queue_lock(lmw->queue);
256 while ((ctl = g_async_queue_try_pop_unlocked(lmw->queue))) {
259 LOWMEM_DESTROY_REQUEST(ctl);
261 g_async_queue_unlock(lmw->queue);
264 static void lowmem_request_destroy(gpointer data)
266 struct lowmem_control *ctl = (struct lowmem_control*) data;
270 LOWMEM_DESTROY_REQUEST(ctl);
273 /*-------------------------------------------------*/
275 /* low memory action function for cgroup */
276 /* low memory action function */
277 static void high_mem_act(void);
278 static void swap_activate_act(void);
279 static void swap_compact_act(void);
280 static void lmk_act(void);
283 static size_t cur_mem_state = MEM_LEVEL_HIGH;
284 static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
285 static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
287 static unsigned long long totalram_bytes;
288 static unsigned long totalram_kb;
290 static bool oom_popup_enable;
291 static bool oom_popup;
292 static bool memcg_swap_status;
293 static int fragmentation_size;
295 const char *lowmem_convert_cgroup_type_to_str(int type)
297 static const char *type_table[] =
299 if (type >= MEMCG_ROOT && type <= MEMCG_THROTTLING)
300 return type_table[type];
305 static const char *convert_status_to_str(int status)
307 static const char *status_table[] =
308 {"none", "done", "drop", "cont", "retry", "next_type"};
309 if(status >= LOWMEM_RECLAIM_NONE && status <= LOWMEM_RECLAIM_NEXT_TYPE)
310 return status_table[status];
311 return "error status";
314 static const char *convert_memstate_to_str(int mem_state)
316 static const char *state_table[] = {"mem high", "mem medium",
317 "mem low", "mem critical", "mem oom",};
318 if (mem_state >= 0 && mem_state < MEM_LEVEL_MAX)
319 return state_table[mem_state];
323 static int lowmem_launch_oompopup(void)
325 GVariantBuilder *const gv_builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
326 g_variant_builder_add(gv_builder, "{ss}", "_SYSPOPUP_CONTENT_", "lowmemory_oom");
328 GVariant *const params = g_variant_new("(a{ss})", gv_builder);
329 g_variant_builder_unref(gv_builder);
331 int ret = d_bus_call_method_sync_gvariant(SYSTEM_POPUP_BUS_NAME,
332 SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
333 "PopupLaunch", params);
335 g_variant_unref(params);
340 static inline void get_total_memory(void)
347 totalram_bytes = (unsigned long long)si.totalram * si.mem_unit;
348 totalram_kb = BYTE_TO_KBYTE(totalram_bytes);
350 register_totalram_bytes(totalram_bytes);
353 _E("Failed to get total ramsize from the kernel");
357 unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
359 unsigned int size_kb = 0, total_size_kb = 0;
364 * If pids are allocated only when there are multiple processes with
365 * the same pgid e.g., browser and web process. Mostly, single process
368 if (tsk->pids == NULL) {
369 ret = proc_get_ram_usage(tsk->pid, &size_kb);
371 /* If there is no proc entry for given pid the process
372 * should be abandoned during further processing
375 _D("failed to get rss memory usage of %d", tsk->pid);
380 for (index = 0; index < tsk->pids->len; index++) {
381 pid = g_array_index(tsk->pids, pid_t, index);
382 ret = proc_get_ram_usage(pid, &size_kb);
383 if (ret != RESOURCED_ERROR_NONE)
385 total_size_kb += size_kb;
388 return total_size_kb;
391 static int lowmem_kill_victim(const struct task_info *tsk,
392 int flags, int memps_log, unsigned int *victim_size)
396 char appname[PATH_MAX];
398 struct proc_app_info *pai;
402 if (pid <= 0 || pid == getpid())
403 return RESOURCED_ERROR_FAIL;
405 ret = proc_get_cmdline(pid, appname, sizeof appname);
406 if (ret == RESOURCED_ERROR_FAIL)
407 return RESOURCED_ERROR_FAIL;
409 if (!strcmp("memps", appname) ||
410 !strcmp("crash-worker", appname) ||
411 !strcmp("system-syspopup", appname)) {
412 _E("%s(%d) was selected, skip it", appname, pid);
413 return RESOURCED_ERROR_FAIL;
418 resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
419 pid, NULL, NULL, PROC_TYPE_NONE);
421 if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
423 } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED && tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
424 int app_flag = pai->flags;
425 sigterm = app_flag & PROC_SIGTERM;
428 if (pai->memory.oom_killed)
431 pai->memory.oom_killed = true;
435 safe_kill(pid, SIGTERM);
437 safe_kill(pid, SIGKILL);
439 _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u KB, sigterm = %d\n",
440 flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
442 *victim_size = tsk->size;
444 if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
445 return RESOURCED_ERROR_NONE;
447 if (oom_popup_enable && !oom_popup) {
448 lowmem_launch_oompopup();
452 return RESOURCED_ERROR_NONE;
455 /* return LOWMEM_RECLAIM_CONT when killing should be continued */
456 static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
458 unsigned int available_mb;
461 * Processes with the priority higher than perceptible are killed
462 * only when the available memory is less than dynamic oom threshold.
464 if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
465 return LOWMEM_RECLAIM_CONT;
467 if (flags & (OOM_FORCE|OOM_SINGLE_SHOT)) {
468 _I("[LMK] %d is dropped during force kill, flag=%d",
470 return LOWMEM_RECLAIM_DROP;
472 available_mb = proc_get_mem_available();
473 if (available_mb > lmk_start_threshold_mb) {
474 _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
475 available_mb, lmk_start_threshold_mb);
476 return LOWMEM_RECLAIM_RETRY;
478 return LOWMEM_RECLAIM_CONT;
481 static void lowmem_free_task_info_array(GArray *array)
485 for (i = 0; i < array->len; i++) {
486 struct task_info *tsk;
488 tsk = &g_array_index(array, struct task_info, i);
490 g_array_free(tsk->pids, true);
493 g_array_free(array, true);
496 static inline int is_dynamic_process_killer(int flags)
498 return (flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK);
501 static unsigned int is_memory_recovered(unsigned int *avail, unsigned int thres)
503 unsigned int available = proc_get_mem_available();
504 unsigned int should_be_freed_mb = 0;
506 if (available < thres)
507 should_be_freed_mb = thres - available;
509 * free THRESHOLD_MARGIN more than real should be freed,
510 * because launching app is consuming up the memory.
512 if (should_be_freed_mb > 0)
513 should_be_freed_mb += THRESHOLD_MARGIN;
517 return should_be_freed_mb;
521 * @brief Terminate up to max_victims processes after finding them from pai.
522 It depends on proc_app_info lists
523 and it also reference systemservice cgroup
524 because some processes in this group don't have proc_app_info.
526 * @max_victims: max number of processes to be terminated
527 * @start_oom: find victims from start oom adj score value
528 * @end_oom: find victims to end oom adj score value
529 * @should_be_freed: amount of memory to be reclaimed (in MB)
530 * @total_size[out]: total size of possibly reclaimed memory (required)
531 * @completed: final outcome (optional)
532 * @threshold: desired value of memory available
534 static int lowmem_kill_victims(int max_victims,
535 int start_oom, int end_oom, unsigned should_be_freed, int flags,
536 unsigned int *total_size, int *completed, unsigned int threshold)
538 GSList *proc_app_list = NULL;
539 int i, ret, victim = 0;
540 unsigned int victim_size = 0;
541 unsigned int total_victim_size = 0;
542 int status = LOWMEM_RECLAIM_NONE;
543 GArray *candidates = NULL;
544 int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
546 proc_app_list = proc_app_list_open();
548 /* Get the victim candidates from lowmem governor */
549 candidates = lowmem_governor_get_kill_candidates(proc_app_list, start_oom, end_oom, flags);
551 proc_app_list_close();
552 proc_app_list = NULL;
554 if (!candidates->len) {
555 status = LOWMEM_RECLAIM_NEXT_TYPE;
559 for (i = 0; i < candidates->len; i++) {
560 struct task_info *tsk;
562 if (i >= max_victims) {
563 status = LOWMEM_RECLAIM_NEXT_TYPE;
568 * Available memory is checking only every
569 * num_vict_between_check process for reducing burden.
571 if (!(i % num_vict_between_check)) {
572 if (proc_get_mem_available() > threshold) {
573 status = LOWMEM_RECLAIM_DONE;
578 if (!(flags & OOM_NOMEMORY_CHECK) &&
579 total_victim_size >= should_be_freed_kb) {
580 _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
581 victim, max_victims, total_victim_size);
582 status = LOWMEM_RECLAIM_DONE;
586 tsk = &g_array_index(candidates, struct task_info, i);
588 status = lowmem_check_kill_continued(tsk, flags);
589 if (status != LOWMEM_RECLAIM_CONT)
592 _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n", tsk->pid, tsk->oom_score_adj);
594 ret = lowmem_kill_victim(tsk, flags, i, &victim_size);
595 if (ret != RESOURCED_ERROR_NONE)
598 total_victim_size += victim_size;
602 lowmem_free_task_info_array(candidates);
603 *total_size = total_victim_size;
604 if(*completed != LOWMEM_RECLAIM_CONT)
607 *completed = LOWMEM_RECLAIM_NEXT_TYPE;
611 static int calculate_range_of_oom(enum oom_score score, int *min, int *max)
613 if (score > OOM_SCORE_MAX || score < OOM_SCORE_HIGH) {
614 _E("[LMK] oom score (%d) is out of scope", score);
615 return RESOURCED_ERROR_FAIL;
618 *max = cgroup_get_highest_oom_score_adj(score);
619 *min = cgroup_get_lowest_oom_score_adj(score);
621 return RESOURCED_ERROR_NONE;
624 static void lowmem_handle_request(struct lowmem_control *ctl)
626 int start_oom, end_oom;
627 int count = 0, victim_cnt = 0;
628 int max_victim_cnt = ctl->count;
629 int status = LOWMEM_RECLAIM_NONE;
630 unsigned int available_mb = 0;
631 unsigned int total_size_mb = 0;
632 unsigned int current_size = 0;
633 unsigned int reclaim_size_mb, shortfall_mb = 0;
634 enum oom_score oom_score = ctl->score;
636 available_mb = proc_get_mem_available();
637 reclaim_size_mb = ctl->size_mb > available_mb /* MB */
638 ? ctl->size_mb - available_mb : 0;
640 if (!reclaim_size_mb) {
641 status = LOWMEM_RECLAIM_DONE;
646 /* Prepare LMK to start doing it's job. Check preconditions. */
647 if (calculate_range_of_oom(oom_score, &start_oom, &end_oom))
650 lmk_start_threshold_mb = get_root_memcg_info()->threshold_mb[MEM_LEVEL_OOM];
651 shortfall_mb = is_memory_recovered(&available_mb, ctl->size_mb);
653 if (!shortfall_mb || !reclaim_size_mb) {
654 status = LOWMEM_RECLAIM_DONE;
660 victim_cnt = lowmem_kill_victims(max_victim_cnt, start_oom, end_oom,
661 reclaim_size_mb, ctl->flags, ¤t_size, &status, ctl->size_mb);
664 current_size = KBYTE_TO_MBYTE(current_size);
665 reclaim_size_mb -= reclaim_size_mb > current_size
666 ? current_size : reclaim_size_mb;
667 total_size_mb += current_size;
669 _I("[LMK] current: kill %d victims, reclaim_size=%uMB from %d to %d status=%s",
670 victim_cnt, current_size,
671 start_oom, end_oom, convert_status_to_str(status));
674 if ((status == LOWMEM_RECLAIM_DONE) ||
675 (status == LOWMEM_RECLAIM_DROP) ||
676 (status == LOWMEM_RECLAIM_RETRY))
680 * If it doesn't finish reclaiming memory in first operation,
681 - if flags has OOM_IN_DEPTH,
682 try to find victims again in the active cgroup.
683 otherwise, just return because there is no more victims in the desired cgroup.
684 - if flags has OOM_REVISE,
685 it means that resourced can't find victims from proc_app_list.
686 So, it should search victims or malicious process from /proc.
687 But searching /proc leads to abnormal behaviour.
688 (Make sluggish or kill same victims continuously)
689 Thus, otherwise, just return in first operation and wait some period.
691 if (oom_score == OOM_SCORE_LOW) {
692 oom_score = OOM_SCORE_MEDIUM;
694 } else if ((oom_score == OOM_SCORE_MEDIUM) && (ctl->flags & OOM_IN_DEPTH)) {
695 oom_score = OOM_SCORE_HIGH;
696 if(ctl->flags & OOM_FORCE)
697 max_victim_cnt = FOREGROUND_VICTIMS;
699 } else if ((oom_score == OOM_SCORE_HIGH) && (ctl->flags & OOM_IN_DEPTH)) {
700 status = LOWMEM_RECLAIM_RETRY;
701 ctl->score = OOM_SCORE_MAX;
703 else if (oom_score == OOM_SCORE_MAX) {
704 status = LOWMEM_RECLAIM_RETRY;
707 _I("[LMK] Done: killed %d processes reclaimed=%uMB remaining=%uMB shortfall=%uMB status=%s",
708 count, total_size_mb, reclaim_size_mb, shortfall_mb, convert_status_to_str(status));
710 /* After we finish reclaiming it's worth to remove oldest memps logs */
711 ctl->status = status;
714 static void *lowmem_reclaim_worker(void *arg)
716 struct lowmem_worker *lmw = (struct lowmem_worker *)arg;
718 setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
720 g_async_queue_ref(lmw->queue);
724 struct lowmem_control *ctl;
726 LOWMEM_WORKER_IDLE(lmw);
727 /* Wait on any wake-up call */
728 ctl = g_async_queue_pop(lmw->queue);
731 _W("[LMK] ctl structure is NULL");
735 if ((ctl->flags & OOM_DROP) || !LOWMEM_WORKER_IS_ACTIVE(lmw)) {
736 LOWMEM_DESTROY_REQUEST(ctl);
740 LOWMEM_WORKER_RUN(lmw);
742 _D("[LMK] %d tries", ++try_count);
743 lowmem_handle_request(ctl);
745 * Case the process failed to reclaim requested amount of memory
746 * or still under have memory pressure - try the timeout wait.
747 * There is a chance this will get woken-up in a better reality.
749 if (ctl->status == LOWMEM_RECLAIM_RETRY &&
750 !(ctl->flags & OOM_SINGLE_SHOT)) {
751 unsigned int available_mb = proc_get_mem_available();
753 if (available_mb >= ctl->size_mb) {
754 _I("[LMK] Memory restored: requested=%uMB available=%uMB\n",
755 ctl->size_mb, available_mb);
756 ctl->status = LOWMEM_RECLAIM_DONE;
759 LOWMEM_DESTROY_REQUEST(ctl);
760 LOWMEM_WORKER_IDLE(lmw);
764 if (LOWMEM_WORKER_IS_ACTIVE(lmw)) {
765 g_usleep(LMW_RETRY_WAIT_TIMEOUT_MSEC);
766 ctl->flags |= OOM_REVISE;
772 * The ctl callback would check available size again.
773 * And it is last point in reclaiming worker.
774 * Resourced sent SIGKILL signal to victim processes
775 * so it should wait for a some seconds until each processes returns memory.
777 g_usleep(LMW_LOOP_WAIT_TIMEOUT_MSEC);
781 /* The lmk becomes the owner of all queued requests .. */
782 LOWMEM_DESTROY_REQUEST(ctl);
783 LOWMEM_WORKER_IDLE(lmw);
785 g_async_queue_unref(lmw->queue);
789 static void change_lowmem_state(unsigned int mem_state)
791 cur_mem_state = mem_state;
792 lmk_start_threshold_mb = get_root_memcg_info()->threshold_mb[MEM_LEVEL_OOM];
794 resourced_notify(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
795 (void *)&cur_mem_state);
798 /* only app can call this function
799 * that is, service cannot call the function
801 static void lowmem_swap_memory(char *path)
803 unsigned int available_mb;
805 if (cur_mem_state == MEM_LEVEL_HIGH)
808 if (swap_get_state() != SWAP_ON)
811 available_mb = proc_get_mem_available();
812 if (cur_mem_state != MEM_LEVEL_LOW &&
813 available_mb <= get_root_memcg_info()->threshold_mb[MEM_LEVEL_LOW])
816 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
817 memcg_swap_status = true;
820 void lowmem_trigger_swap(pid_t pid, char *path, bool move)
824 int lowest_oom_score_adj;
827 _E("[SWAP] Unknown memory cgroup path to swap");
831 /* In this case, corresponding process will be moved to memory MEMCG_THROTTLING.
834 error = proc_get_oom_score_adj(pid, &oom_score_adj);
836 _E("[SWAP] Cannot get oom_score_adj of pid (%d)", pid);
840 lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(OOM_SCORE_LOW);
842 if (oom_score_adj < lowest_oom_score_adj) {
843 oom_score_adj = lowest_oom_score_adj;
844 /* End of this funciton, 'lowmem_swap_memory()' funciton will be called */
845 proc_set_oom_score_adj(pid, oom_score_adj, find_app_info(pid));
850 /* Correponding process is already managed per app or service.
851 * In addition, if some process is already located in the MEMCG_THROTTLING, then just do swap
853 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
856 static void memory_level_send_system_event(int lv)
863 case MEM_LEVEL_MEDIUM:
865 str = EVT_VAL_MEMORY_NORMAL;
867 case MEM_LEVEL_CRITICAL:
868 str = EVT_VAL_MEMORY_SOFT_WARNING;
871 str = EVT_VAL_MEMORY_HARD_WARNING;
880 _E("Failed to create bundle");
884 bundle_add_str(b, EVT_KEY_LOW_MEMORY, str);
885 eventsystem_send_system_event(SYS_EVENT_LOW_MEMORY, b);
889 static void high_mem_act(void)
893 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
895 _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
896 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
897 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
898 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
899 memory_level_send_system_event(MEM_LEVEL_HIGH);
902 change_lowmem_state(MEM_LEVEL_HIGH);
904 if (swap_get_state() == SWAP_ON && memcg_swap_status) {
905 resourced_notify(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, get_memcg_info(MEMCG_THROTTLING));
906 memcg_swap_status = false;
908 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
909 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
910 (void *)CGROUP_FREEZER_ENABLED);
913 static void swap_activate_act(void)
917 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
919 _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
921 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
922 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
923 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
924 memory_level_send_system_event(MEM_LEVEL_LOW);
926 change_lowmem_state(MEM_LEVEL_LOW);
927 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
928 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
929 (void *)CGROUP_FREEZER_ENABLED);
931 if (swap_get_state() != SWAP_ON)
932 resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
935 static void dedup_act(enum ksm_scan_mode mode)
940 if (dedup_get_state() != DEDUP_ONE_SHOT)
943 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
944 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
945 (void *)CGROUP_FREEZER_ENABLED);
947 if (mode == KSM_SCAN_PARTIAL) {
948 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
950 _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
952 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
953 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
954 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
955 memory_level_send_system_event(MEM_LEVEL_MEDIUM);
957 change_lowmem_state(MEM_LEVEL_MEDIUM);
959 data = KSM_SCAN_PARTIAL;
960 resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
961 } else if (mode == KSM_SCAN_FULL) {
962 data = KSM_SCAN_FULL;
963 resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
967 static void swap_compact_act(void)
969 change_lowmem_state(MEM_LEVEL_CRITICAL);
970 resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_CRITICAL);
971 memory_level_send_system_event(MEM_LEVEL_CRITICAL);
974 static void medium_cb(struct lowmem_control *ctl)
976 if (ctl->status == LOWMEM_RECLAIM_DONE)
978 lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
981 static void lmk_act(void)
983 unsigned int available_mb;
985 int status = VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL;
988 * Don't trigger reclaim worker
989 * if it is already running
991 if (LOWMEM_WORKER_IS_RUNNING(&lmw))
994 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
996 _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
998 memory_level_send_system_event(MEM_LEVEL_OOM);
999 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING) {
1000 if (proc_get_freezer_status() == CGROUP_FREEZER_ENABLED)
1001 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1002 (void *)CGROUP_FREEZER_PAUSED);
1003 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1004 VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
1006 available_mb = proc_get_mem_available();
1008 change_lowmem_state(MEM_LEVEL_OOM);
1010 if (available_mb < get_root_memcg_info()->threshold_leave_mb) {
1011 struct lowmem_control *ctl;
1013 ctl = LOWMEM_NEW_REQUEST();
1015 LOWMEM_SET_REQUEST(ctl, OOM_IN_DEPTH,
1016 OOM_SCORE_LOW, get_root_memcg_info()->threshold_leave_mb,
1017 num_max_victims, medium_cb);
1018 lowmem_queue_request(&lmw, ctl);
1022 resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_OOM);
1025 * Flush resourced memory such as other processes.
1026 * Resourced can use both many fast bins and sqlite3 cache memery.
1033 void lowmem_trigger_memory_state_action(int mem_state)
1036 * Check if the state we want to set is different from current
1037 * But it should except this condition if mem_state is already medium.
1038 * Otherwise, recalim worker couldn't run any more.
1040 if (mem_state != MEM_LEVEL_OOM && cur_mem_state == mem_state)
1043 switch (mem_state) {
1044 case MEM_LEVEL_HIGH:
1047 case MEM_LEVEL_MEDIUM:
1048 dedup_act(KSM_SCAN_PARTIAL);
1051 swap_activate_act();
1053 case MEM_LEVEL_CRITICAL:
1054 dedup_act(KSM_SCAN_FULL);
1065 static unsigned int check_mem_state(unsigned int available_mb)
1068 for (mem_state = MEM_LEVEL_MAX - 1; mem_state > MEM_LEVEL_HIGH; mem_state--) {
1069 if (mem_state != MEM_LEVEL_OOM &&
1070 available_mb <= get_root_memcg_info()->threshold_mb[mem_state])
1072 else if (mem_state == MEM_LEVEL_OOM && available_mb <= lmk_start_threshold_mb)
1079 /* setup memcg parameters depending on total ram size. */
1080 static void setup_memcg_params(void)
1082 unsigned long total_ramsize_mb;
1085 total_ramsize_mb = BYTE_TO_MBYTE(totalram_bytes);
1087 _D("Total: %lu MB", total_ramsize_mb);
1088 if (total_ramsize_mb <= MEM_SIZE_64) {
1089 /* set thresholds for ram size 64M */
1090 proactive_threshold_mb = PROACTIVE_64_THRES;
1091 proactive_leave_mb = PROACTIVE_64_LEAVE;
1092 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_64_THRES_DEDUP);
1093 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_64_THRES_SWAP);
1094 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_64_THRES_LOW);
1095 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_64_THRES_MEDIUM);
1096 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_64_THRES_LEAVE);
1097 num_max_victims = CGROUP_ROOT_64_NUM_VICTIMS;
1098 } else if (total_ramsize_mb <= MEM_SIZE_256) {
1099 /* set thresholds for ram size 256M */
1100 proactive_threshold_mb = PROACTIVE_256_THRES;
1101 proactive_leave_mb = PROACTIVE_256_LEAVE;
1102 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_256_THRES_DEDUP);
1103 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_256_THRES_SWAP);
1104 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_256_THRES_LOW);
1105 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_256_THRES_MEDIUM);
1106 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_256_THRES_LEAVE);
1107 num_max_victims = CGROUP_ROOT_256_NUM_VICTIMS;
1108 } else if (total_ramsize_mb <= MEM_SIZE_448) {
1109 /* set thresholds for ram size 448M */
1110 proactive_threshold_mb = PROACTIVE_448_THRES;
1111 proactive_leave_mb = PROACTIVE_448_LEAVE;
1112 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_448_THRES_DEDUP);
1113 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_448_THRES_SWAP);
1114 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_448_THRES_LOW);
1115 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_448_THRES_MEDIUM);
1116 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_448_THRES_LEAVE);
1117 num_max_victims = CGROUP_ROOT_448_NUM_VICTIMS;
1118 } else if (total_ramsize_mb <= MEM_SIZE_512) {
1119 /* set thresholds for ram size 512M */
1120 proactive_threshold_mb = PROACTIVE_512_THRES;
1121 proactive_leave_mb = PROACTIVE_512_LEAVE;
1122 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_512_THRES_DEDUP);
1123 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_512_THRES_SWAP);
1124 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_512_THRES_LOW);
1125 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_512_THRES_MEDIUM);
1126 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_512_THRES_LEAVE);
1127 num_max_victims = CGROUP_ROOT_512_NUM_VICTIMS;
1128 } else if (total_ramsize_mb <= MEM_SIZE_768) {
1129 /* set thresholds for ram size 768M */
1130 proactive_threshold_mb = PROACTIVE_768_THRES;
1131 proactive_leave_mb = PROACTIVE_768_LEAVE;
1132 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_768_THRES_DEDUP);
1133 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_768_THRES_SWAP);
1134 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_768_THRES_LOW);
1135 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_768_THRES_MEDIUM);
1136 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_768_THRES_LEAVE);
1137 num_max_victims = CGROUP_ROOT_768_NUM_VICTIMS;
1138 } else if (total_ramsize_mb <= MEM_SIZE_1024) {
1139 /* set thresholds for ram size more than 1G */
1140 proactive_threshold_mb = PROACTIVE_1024_THRES;
1141 proactive_leave_mb = PROACTIVE_1024_LEAVE;
1142 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_1024_THRES_DEDUP);
1143 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_1024_THRES_SWAP);
1144 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_1024_THRES_LOW);
1145 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_1024_THRES_MEDIUM);
1146 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_1024_THRES_LEAVE);
1147 num_max_victims = CGROUP_ROOT_1024_NUM_VICTIMS;
1148 } else if (total_ramsize_mb <= MEM_SIZE_2048) {
1149 proactive_threshold_mb = PROACTIVE_2048_THRES;
1150 proactive_leave_mb = PROACTIVE_2048_LEAVE;
1151 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_2048_THRES_DEDUP);
1152 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_2048_THRES_SWAP);
1153 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_2048_THRES_LOW);
1154 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_2048_THRES_MEDIUM);
1155 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_2048_THRES_LEAVE);
1156 num_max_victims = CGROUP_ROOT_2048_NUM_VICTIMS;
1158 proactive_threshold_mb = PROACTIVE_3072_THRES;
1159 proactive_leave_mb = PROACTIVE_3072_LEAVE;
1160 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_3072_THRES_DEDUP);
1161 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_3072_THRES_SWAP);
1162 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_3072_THRES_LOW);
1163 memcg_set_threshold(MEMCG_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_3072_THRES_MEDIUM);
1164 memcg_set_leave_threshold(MEMCG_ROOT, CGROUP_ROOT_3072_THRES_LEAVE);
1165 num_max_victims = CGROUP_ROOT_3072_NUM_VICTIMS;
1169 static void lowmem_move_memcgroup(int pid, int next_oom_score_adj, struct proc_app_info *pai)
1171 int cur_oom_score_adj;
1173 struct memcg_info *mi;
1174 int next_memcg_idx = cgroup_get_type(next_oom_score_adj);
1176 mi = get_memcg_info(next_memcg_idx);
1183 cgroup_write_pid_fullpath(mi->name, pid);
1188 if (pai->main_pid == pid) {
1189 cur_oom_score_adj = pai->memory.oom_score_adj;
1190 cur_memcg_idx = cgroup_get_type(cur_oom_score_adj);
1192 if (cur_oom_score_adj == next_oom_score_adj) {
1193 _D("next oom_score_adj (%d) is same with current one", next_oom_score_adj);
1197 proc_set_process_memory_state(pai, next_memcg_idx, mi, next_oom_score_adj);
1199 if (!lowmem_limit_move_cgroup(pai))
1202 if(cur_memcg_idx == next_memcg_idx)
1205 _I("app (%s) memory cgroup move from %s to %s", pai->appid, lowmem_convert_cgroup_type_to_str(cur_memcg_idx), lowmem_convert_cgroup_type_to_str(next_memcg_idx));
1206 cgroup_write_pid_fullpath(mi->name, pid);
1207 if (next_memcg_idx == MEMCG_THROTTLING)
1208 lowmem_swap_memory(get_memcg_info(MEMCG_THROTTLING)->name);
1212 if (pai->memory.use_mem_limit)
1215 cgroup_write_pid_fullpath(mi->name, pid);
1219 static int lowmem_activate_worker(void)
1221 int ret = RESOURCED_ERROR_NONE;
1223 if (LOWMEM_WORKER_IS_ACTIVE(&lmw)) {
1227 lmw.queue = g_async_queue_new_full(lowmem_request_destroy);
1229 _E("Failed to create request queue\n");
1230 return RESOURCED_ERROR_FAIL;
1232 LOWMEM_WORKER_ACTIVATE(&lmw);
1233 ret = pthread_create(&lmw.worker_thread, NULL,
1234 (void *)lowmem_reclaim_worker, (void *)&lmw);
1236 LOWMEM_WORKER_DEACTIVATE(&lmw);
1237 _E("Failed to create LMK thread: %d\n", ret);
1239 pthread_detach(lmw.worker_thread);
1240 ret = RESOURCED_ERROR_NONE;
1245 static void lowmem_deactivate_worker(void)
1247 struct lowmem_control *ctl;
1249 if (!LOWMEM_WORKER_IS_ACTIVE(&lmw))
1252 LOWMEM_WORKER_DEACTIVATE(&lmw);
1253 lowmem_drain_queue(&lmw);
1255 ctl = LOWMEM_NEW_REQUEST();
1257 _E("Critical - g_slice alloc failed - Lowmem cannot be deactivated");
1260 ctl->flags = OOM_DROP;
1261 g_async_queue_push(lmw.queue, ctl);
1262 g_async_queue_unref(lmw.queue);
1265 static void lowmem_press_root_cgroup_handler(void)
1267 static unsigned int prev_available_mb;
1268 unsigned int available_mb;
1271 available_mb = proc_get_mem_available();
1272 if (prev_available_mb == available_mb)
1275 mem_state = check_mem_state(available_mb);
1276 lowmem_trigger_memory_state_action(mem_state);
1277 prev_available_mb = available_mb;
1280 static void lowmem_force_reclaim_cb(struct lowmem_control *ctl)
1282 lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
1285 int lowmem_trigger_reclaim(int flags, int victims, enum oom_score score, int threshold_mb)
1287 struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
1292 flags |= OOM_FORCE | OOM_IN_DEPTH | OOM_SINGLE_SHOT;
1293 victims = victims > 0 ? victims : MAX_MEMORY_CGROUP_VICTIMS;
1294 score = score > 0 ? score : OOM_SCORE_LOW;
1295 threshold_mb = threshold_mb > 0 ? threshold_mb : get_root_memcg_info()->threshold_leave_mb;
1297 lowmem_change_memory_state(MEM_LEVEL_CRITICAL, 1);
1298 LOWMEM_SET_REQUEST(ctl, flags,
1299 score, threshold_mb, victims,
1300 lowmem_force_reclaim_cb);
1301 lowmem_queue_request(&lmw, ctl);
1306 void lowmem_trigger_swap_reclaim(enum oom_score score, unsigned long long swap_size_bytes)
1308 int size_mb, victims;
1310 victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS
1311 ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
1313 size_mb = get_root_memcg_info()->threshold_leave_mb + BYTE_TO_MBYTE(swap_size_bytes);
1314 lowmem_trigger_reclaim(0, victims, score, size_mb);
1317 bool lowmem_fragmentated(void)
1319 struct buddyinfo bi;
1322 ret = proc_get_buddyinfo("Normal", &bi);
1327 * The fragmentation_size is the minimum count of order-2 pages in "Normal" zone.
1328 * If total buddy pages is smaller than fragmentation_size,
1329 * resourced will detect kernel memory is fragmented.
1330 * Default value is zero in low memory device.
1332 if (bi.page[PAGE_32K] + (bi.page[PAGE_64K] << 1) + (bi.page[PAGE_128K] << 2) +
1333 (bi.page[PAGE_256K] << 3) < fragmentation_size) {
1334 _I("fragmentation detected, need to execute proactive oom killer");
1340 static void lowmem_proactive_oom_killer(int flags, char *appid)
1342 unsigned int before_mb;
1345 before_mb = proc_get_mem_available();
1347 /* If memory state is medium or normal, just return and kill in oom killer */
1348 if (before_mb < get_root_memcg_info()->threshold_mb[MEM_LEVEL_OOM] ||
1349 before_mb > proactive_leave_mb)
1352 victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS
1353 ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
1355 #ifdef HEART_SUPPORT
1357 * This branch is used only when HEART module is compiled in and
1358 * it's MEMORY module must be enabled. Otherwise this is skipped.
1360 struct heart_memory_data *md = heart_memory_get_memdata(appid, DATA_LATEST);
1362 unsigned int rss_mb, after_mb, size_mb;
1364 rss_mb = KBYTE_TO_MBYTE(md->avg_rss);
1368 after_mb = before_mb - rss_mb;
1370 * after launching app, ensure that available memory is
1371 * above threshold_leave
1373 if (after_mb >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
1376 if (proactive_threshold_mb - rss_mb >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
1377 size_mb = proactive_threshold_mb;
1379 size_mb = rss_mb + get_root_memcg_info()->threshold[MEM_LEVEL_OOM] + THRESHOLD_MARGIN;
1381 _D("history based proactive LMK : avg rss %u, available %u required = %u MB",
1382 rss_mb, before_mb, size_mb);
1383 lowmem_trigger_reclaim(0, victims, OOM_SCORE_LOW, size_mb);
1390 * When there is no history data for the launching app,
1391 * it is necessary to check current fragmentation state or application manifest file.
1392 * So, resourced feels proactive LMK is required, run oom killer based on dynamic
1395 if (lowmem_fragmentated())
1399 * run proactive oom killer only when available is larger than
1400 * dynamic process threshold
1402 if (!proactive_threshold_mb || before_mb >= proactive_threshold_mb)
1405 if (!(flags & PROC_LARGEMEMORY))
1410 * free THRESHOLD_MARGIN more than real should be freed,
1411 * because launching app is consuming up the memory.
1413 _D("Run threshold based proactive LMK: memory level to reach: %u MB\n",
1414 proactive_leave_mb + THRESHOLD_MARGIN);
1415 lowmem_trigger_reclaim(0, victims, OOM_SCORE_LOW, proactive_leave_mb + THRESHOLD_MARGIN);
1418 unsigned int lowmem_get_proactive_thres(void)
1420 return proactive_threshold_mb;
1423 static int lowmem_prelaunch_handler(void *data)
1425 struct proc_status *ps = (struct proc_status *)data;
1426 struct proc_app_info *pai = ps->pai;
1428 if (!pai || CHECK_BIT(pai->flags, PROC_SERVICEAPP))
1429 return RESOURCED_ERROR_NONE;
1431 lowmem_proactive_oom_killer(ps->pai->flags, ps->pai->appid);
1432 return RESOURCED_ERROR_NONE;
1435 int lowmem_control_handler(void *data)
1437 struct lowmem_control_data *lowmem_data;
1439 lowmem_data = (struct lowmem_control_data *)data;
1440 switch (lowmem_data->control_type) {
1441 case LOWMEM_MOVE_CGROUP:
1442 lowmem_move_memcgroup((pid_t)lowmem_data->pid,
1443 lowmem_data->oom_score_adj, lowmem_data->pai);
1448 return RESOURCED_ERROR_NONE;
1451 static inline int calculate_threshold_size(double ratio)
1453 unsigned long long size_bytes = (double)totalram_bytes * ratio / 100.0;
1454 return BYTE_TO_MBYTE(size_bytes);
1457 static void load_configs(void)
1459 struct memcg_conf *memcg_conf = get_memcg_conf();
1461 /* set MemoryGroupLimit section */
1462 for (int cgroup = MEMCG_THROTTLING; cgroup < MEMCG_END; cgroup++) {
1463 if (memcg_conf->cgroup_limit[cgroup] > 0.0)
1464 memcg_info_set_limit(get_memcg_info(cgroup),
1465 memcg_conf->cgroup_limit[cgroup]/100.0, totalram_bytes);
1468 /* set MemoryLevelThreshold section */
1469 for (int lvl = MEM_LEVEL_MEDIUM; lvl < MEM_LEVEL_MAX; lvl++) {
1470 if (memcg_conf->threshold[lvl].percent &&
1471 memcg_conf->threshold[lvl].threshold > 0) {
1472 memcg_set_threshold(MEMCG_ROOT, lvl,
1473 calculate_threshold_size(memcg_conf->threshold[lvl].threshold));
1475 if (lvl == MEM_LEVEL_OOM) {
1476 memcg_set_leave_threshold(MEMCG_ROOT,
1477 get_memcg_info(MEMCG_ROOT)->threshold_mb[lvl] * 1.5);
1478 proactive_threshold_mb = get_memcg_info(MEMCG_ROOT)->threshold_leave_mb;
1479 proactive_leave_mb = proactive_threshold_mb * 1.5;
1482 else if (memcg_conf->threshold[lvl].threshold > 0) {
1483 memcg_set_threshold(MEMCG_ROOT, lvl,
1484 memcg_conf->threshold[lvl].threshold);
1486 if (lvl == MEM_LEVEL_OOM) {
1487 memcg_set_leave_threshold(MEMCG_ROOT,
1488 get_memcg_info(MEMCG_ROOT)->threshold_mb[lvl] * 1.5);
1489 proactive_threshold_mb = get_memcg_info(MEMCG_ROOT)->threshold_leave_mb;
1490 proactive_leave_mb = proactive_threshold_mb * 1.5;
1495 oom_popup_enable = memcg_conf->oom_popup;
1497 /* set MemoryAppTypeLimit and MemoryAppStatusLimit section */
1498 lowmem_memory_init(memcg_conf->service.memory_bytes, memcg_conf->widget.memory_bytes,
1499 memcg_conf->guiapp.memory_bytes, memcg_conf->background.memory_bytes);
1500 lowmem_action_init(memcg_conf->service.action, memcg_conf->widget.action,
1501 memcg_conf->guiapp.action, memcg_conf->background.action);
1506 static void print_mem_configs(void)
1508 /* print info of Memory section */
1509 for (int cgroup = MEMCG_THROTTLING; cgroup < MEMCG_END; cgroup++) {
1510 _I("[MEMORY-CGROUP] set memory for cgroup '%s' to %llu bytes",
1511 lowmem_convert_cgroup_type_to_str(cgroup), get_memcg_info(cgroup)->limit_bytes);
1514 for (int cgroup = MEMCG_ROOT; cgroup < MEMCG_END; cgroup++) {
1515 for (int mem_lvl = 0; mem_lvl < MEM_LEVEL_MAX; mem_lvl++) {
1516 _I("[MEMORY-LEVEL] set threshold of %s for memory level '%s' to %u MB", lowmem_convert_cgroup_type_to_str(cgroup),
1517 convert_memstate_to_str(mem_lvl), get_memcg_info(cgroup)->threshold_mb[mem_lvl]);
1521 _I("[LMK] set number of max victims as %d", num_max_victims);
1522 _I("[LMK] set threshold leave to %u MB", get_root_memcg_info()->threshold_leave_mb);
1523 _I("[LMK] set proactive threshold to %u MB", proactive_threshold_mb);
1524 _I("[LMK] set proactive low memory killer leave to %u MB", proactive_leave_mb);
1526 /* print info of POPUP section */
1527 _I("[POPUP] oom popup is %s", oom_popup_enable == true ? "enabled" : "disabled");
1530 /* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
1531 static int lowmem_init(void)
1533 int ret = RESOURCED_ERROR_NONE;
1535 _D("resourced memory init start");
1538 ret = memcg_make_full_subdir(MEMCG_PATH);
1539 ret_value_msg_if(ret < 0, ret, "memory cgroup init failed\n");
1540 memcg_params_init();
1542 setup_memcg_params();
1544 /* default configuration */
1547 /* this function should be called after parsing configurations */
1548 memcg_write_limiter_params();
1549 print_mem_configs();
1551 /* make a worker thread called low memory killer */
1552 ret = lowmem_activate_worker();
1554 _E("[LMK] oom thread create failed\n");
1558 /* register threshold and event fd */
1559 ret = lowmem_monitor_pressure_initialize(
1560 lowmem_press_root_cgroup_handler);
1562 _E("[MEMORY-LIMIT] eventfd setup failed");
1567 lowmem_limit_init();
1568 lowmem_system_init();
1570 register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
1571 register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
1576 static int lowmem_exit(void)
1578 lowmem_deactivate_worker();
1579 lowmem_limit_exit();
1580 lowmem_system_exit();
1582 unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
1583 unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
1585 return RESOURCED_ERROR_NONE;
1588 static int resourced_memory_init(void *data)
1590 return lowmem_init();
1593 static int resourced_memory_finalize(void *data)
1595 return lowmem_exit();
1598 void lowmem_change_memory_state(int state, int force)
1605 unsigned int available_mb = proc_get_mem_available();
1606 mem_state = check_mem_state(available_mb);
1609 lowmem_trigger_memory_state_action(mem_state);
1612 unsigned long lowmem_get_ktotalram(void)
1617 unsigned long long lowmem_get_totalram(void)
1619 return totalram_bytes;
1622 void lowmem_restore_memcg(struct proc_app_info *pai)
1626 struct cgroup *cgroup = NULL;
1627 struct memcg_info *mi = NULL;
1628 pid_t pid = pai->main_pid;
1630 ret = cgroup_pid_get_path("memory", pid, &cgpath);
1634 for (index = MEMCG_END-1; index >= MEMCG_ROOT; index--) {
1635 cgroup = get_cgroup_tree(index);
1639 mi = cgroup->memcg_info;
1643 if (!strcmp(cgroup->hashname, ""))
1645 if (strstr(cgpath, cgroup->hashname))
1648 pai->memory.memcg_idx = index;
1649 pai->memory.memcg_info = mi;
1650 if(strstr(cgpath, pai->appid))
1651 pai->memory.use_mem_limit = true;
1656 static struct module_ops memory_modules_ops = {
1657 .priority = MODULE_PRIORITY_EARLY,
1659 .init = resourced_memory_init,
1660 .exit = resourced_memory_finalize,
1663 MODULE_REGISTER(&memory_modules_ops)