lowmem: Split up governor from lowmem module 29/286529/6 accepted/tizen/unified/20230131.162139
authorSangYoun Kwak <sy.kwak@samsung.com>
Mon, 9 Jan 2023 08:28:23 +0000 (17:28 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Mon, 30 Jan 2023 07:30:25 +0000 (07:30 +0000)
The lowmem-governor.c was created by extracting the
"sorting out kill candidate" functionality from lowmem.c.
    * Newly created: lowmem-governor.c, lowmem-governor.h
    * "lowmem_governor_get_kill_candidates" function from
      lowmem-governor.c gets a list of procs/apps and returns a sorted
      list of kill candidates.
    * Functions that only used in lowmem-governor.c were moved into
      lowmem-governor.c from lowmem.c.

Change-Id: Ieba1612c040a9891e2f87f44e6bd1a34251f05ea
Signed-off-by: SangYoun Kwak <sy.kwak@samsung.com>
src/resource-limiter/memory/lowmem-governor.c [new file with mode: 0644]
src/resource-limiter/memory/lowmem-governor.h [new file with mode: 0644]
src/resource-limiter/memory/lowmem.c

diff --git a/src/resource-limiter/memory/lowmem-governor.c b/src/resource-limiter/memory/lowmem-governor.c
new file mode 100644 (file)
index 0000000..d249129
--- /dev/null
@@ -0,0 +1,248 @@
+/**
+ * resourced
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file lowmem-governor.c
+ * @desc Provides governor function to sort out candidate process to kill.
+ */
+
+#include <unistd.h>
+#include <ctype.h>
+
+#include "lowmem.h"
+#include "lowmem-governor.h"
+#include "procfs.h"
+#include "proc-common.h"
+#include "macro.h"
+#include "trace.h"
+
+#define BUFF_MAX      255
+#define APP_ATTR_PATH "/proc/%d/attr/current"
+
+static unsigned long totalram_kb;
+
+static int get_privilege(pid_t pid, char *name, size_t len)
+{
+       char path[PATH_MAX];
+       char attr[BUFF_MAX];
+       size_t attr_len;
+       FILE *fp;
+
+       snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
+
+       fp = fopen(path, "r");
+       if (!fp)
+               return -errno;
+
+       attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
+       fclose(fp);
+       if (attr_len <= 0)
+               return -ENOENT;
+
+       attr[attr_len] = '\0';
+
+       snprintf(name, len, "%s", attr);
+       return 0;
+}
+
+static int is_app(pid_t pid)
+{
+       char attr[BUFF_MAX];
+       size_t len;
+       int ret;
+
+       ret = get_privilege(pid, attr, sizeof(attr));
+       if (ret < 0) {
+               _E("Failed to get privilege of PID(%d).", pid);
+               return -1;
+       }
+
+       len = strlen(attr) + 1;
+
+       if (!strncmp("System", attr, len))
+               return 0;
+
+       if (!strncmp("User", attr, len))
+               return 0;
+
+       if (!strncmp("System::Privileged", attr, len))
+               return 0;
+
+       return 1;
+}
+
+static int lowmem_get_pids_proc(GArray *pids)
+{
+       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(is_app(pid) != 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 (oom > OOMADJ_SU && oom <= OOMADJ_APP_MAX)
+                       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);
+               tsk.pai = NULL;
+
+               g_array_append_val(pids, tsk);
+       }
+
+       closedir(dp);
+       return RESOURCED_ERROR_NONE;
+}
+
+static int compare_victims(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.
+        */
+       pa = ta->oom_score_lru * (totalram_kb / 2000) + ta->size;
+       pb = tb->oom_score_lru * (totalram_kb / 2000) + tb->size;
+
+       return pb - pa;
+}
+
+GArray *lowmem_governor_get_kill_candidates(GSList *proc_app_list, int start_oom, int end_oom, int killer_flags)
+{
+       GSList *iter, *iterchild;
+       GArray *candidates = g_array_new(false, false, sizeof(struct task_info));
+       struct proc_app_info *pai = NULL;
+       int proc_app_count = 0;
+       int oom_score_adj;
+
+       gslist_for_each_item(iter, proc_app_list) {
+               struct task_info ti;
+
+               proc_app_count++;
+               pai = (struct proc_app_info *)iter->data;
+               if (!pai->main_pid)
+                       continue;
+
+               oom_score_adj = pai->memory.oom_score_adj;
+               if (oom_score_adj > end_oom || oom_score_adj < start_oom)
+                       continue;
+
+               // killer_flags: enum oom_killer_cb_flags
+               if ((killer_flags & OOM_REVISE) && pai->memory.oom_killed)
+                       continue;
+
+               ti.pid = pai->main_pid;
+               ti.pgid = getpgid(ti.pid);
+               ti.oom_score_adj = oom_score_adj;
+               ti.pai = pai;
+
+               /**
+                * 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);
+                       gslist_for_each_item(iterchild, pai->childs) {
+                               pid_t child = GPOINTER_TO_PID(iterchild->data);
+                               g_array_append_val(ti.pids, child);
+                       }
+               } else
+                       ti.pids = NULL;
+
+               g_array_append_val(candidates, ti);
+       }
+
+       if (!candidates->len) {
+               return candidates;
+       }
+
+       _D("[LMK] candidate ratio=%d/%d", candidates->len, proc_app_count);
+
+       for (int 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);                 /* KB */
+       }
+
+       /**
+        * 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);
+
+       totalram_kb = lowmem_get_ktotalram();
+       g_array_sort(candidates, (GCompareFunc)compare_victims);
+
+       return candidates;
+}
+
diff --git a/src/resource-limiter/memory/lowmem-governor.h b/src/resource-limiter/memory/lowmem-governor.h
new file mode 100644 (file)
index 0000000..ebd34ae
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @file lowmem-governor.h
+ * @desc Functions for governor features.
+ **/
+
+#ifndef __LOWMEM_GOVERNOR_H__
+#define __LOWMEM_GOVERNOR_H__
+
+GArray *lowmem_governor_get_kill_candidates(GSList *proc_app_list, int start_oom, int end_oom, int killer_flags);
+
+#endif /* __LOWMEM_GOVERNOR_H__ */
index 717b962..64e7a8b 100644 (file)
@@ -49,6 +49,7 @@
 #include "lowmem-dbus.h"
 #include "lowmem-system.h"
 #include "lowmem-limit.h"
+#include "lowmem-governor.h"
 #include "proc-common.h"
 #include "procfs.h"
 #include "freezer.h"
@@ -242,60 +243,6 @@ static struct lowmem_worker lmw;
        (c)->callback   = __cb;                                         \
 }
 
-#define BUFF_MAX        255
-#define APP_ATTR_PATH "/proc/%d/attr/current"
-
-static int get_privilege(pid_t pid, char *name, size_t len)
-{
-       char path[PATH_MAX];
-       char attr[BUFF_MAX];
-       size_t attr_len;
-       FILE *fp;
-
-       snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
-
-       fp = fopen(path, "r");
-       if (!fp)
-               return -errno;
-
-       attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
-       fclose(fp);
-       if (attr_len <= 0)
-               return -ENOENT;
-
-       attr[attr_len] = '\0';
-
-       snprintf(name, len, "%s", attr);
-       return 0;
-}
-
-static int is_app(pid_t pid)
-{
-       char attr[BUFF_MAX];
-       size_t len;
-       int ret;
-
-       ret = get_privilege(pid, attr, sizeof(attr));
-       if (ret < 0) {
-               _E("Failed to get privilege of PID(%d).", pid);
-               return -1;
-       }
-
-       len = strlen(attr) + 1;
-
-       if (!strncmp("System", attr, len))
-               return 0;
-
-       if (!strncmp("User", attr, len))
-               return 0;
-
-       if (!strncmp("System::Privileged", attr, len))
-               return 0;
-
-       return 1;
-}
-
-
 static void lowmem_queue_request(struct lowmem_worker *lmw,
                                struct lowmem_control *ctl)
 {
@@ -534,22 +481,6 @@ static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
        return LOWMEM_RECLAIM_CONT;
 }
 
-static int compare_victims(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.
-        */
-       pa = ta->oom_score_lru * (totalram_kb / 2000) + ta->size;
-       pb = tb->oom_score_lru * (totalram_kb / 2000) + tb->size;
-
-       return pb - pa;
-}
-
 static void lowmem_free_task_info_array(GArray *array)
 {
        int i;
@@ -589,69 +520,6 @@ static unsigned int is_memory_recovered(unsigned int *avail, unsigned int thres)
        return should_be_freed_mb;
 }
 
-static int lowmem_get_pids_proc(GArray *pids)
-{
-       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(is_app(pid) != 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 (oom > OOMADJ_SU && oom <= OOMADJ_APP_MAX)
-                       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);
-               tsk.pai = NULL;
-
-               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
@@ -670,92 +538,26 @@ static int lowmem_kill_victims(int max_victims,
        int start_oom, int end_oom, unsigned should_be_freed, int flags,
        unsigned int *total_size, int *completed, unsigned int threshold)
 {
-       int total_count = 0;
        GSList *proc_app_list = NULL;
        int i, ret, victim = 0;
        unsigned int victim_size = 0;
        unsigned int total_victim_size = 0;
        int status = LOWMEM_RECLAIM_NONE;
        GArray *candidates = NULL;
-       GSList *iter, *iterchild;
-       struct proc_app_info *pai = NULL;
-       int oom_score_adj;
        int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
 
-       candidates = g_array_new(false, false, sizeof(struct task_info));
-
        proc_app_list = proc_app_list_open();
-       gslist_for_each_item(iter, proc_app_list) {
-               struct task_info ti;
 
-               total_count++;
-               pai = (struct proc_app_info *)iter->data;
-               if (!pai->main_pid)
-                       continue;
-
-               oom_score_adj = pai->memory.oom_score_adj;
-               if (oom_score_adj > end_oom || oom_score_adj < start_oom)
-                       continue;
-
-               if ((flags & OOM_REVISE) && pai->memory.oom_killed)
-                       continue;
-
-               ti.pid = pai->main_pid;
-               ti.pgid = getpgid(ti.pid);
-               ti.oom_score_adj = oom_score_adj;
-               ti.pai = pai;
-
-               /*
-                * 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);
-                       gslist_for_each_item(iterchild, pai->childs) {
-                               pid_t child = GPOINTER_TO_PID(iterchild->data);
-                               g_array_append_val(ti.pids, child);
-                       }
-               } else
-                       ti.pids = NULL;
-
-               g_array_append_val(candidates, ti);
-       }
+       /* Get the victim candidates from lowmem governor */
+       candidates = lowmem_governor_get_kill_candidates(proc_app_list, start_oom, end_oom, flags);
 
        proc_app_list_close();
+       proc_app_list = NULL;
 
        if (!candidates->len) {
                status = LOWMEM_RECLAIM_NEXT_TYPE;
                goto leave;
        }
-       else {
-               _D("[LMK] candidate ratio=%d/%d", candidates->len, total_count);
-       }
-
-       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);                 /* KB */
-       }
-
-       /*
-        * 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);
-
-       g_array_sort(candidates, (GCompareFunc)compare_victims);
 
        for (i = 0; i < candidates->len; i++) {
                struct task_info *tsk;