proc: get approximate memory usage from /proc/{pid}/statm 82/130482/1
authorByungSoo Kim <bs1770.kim@samsung.com>
Tue, 2 May 2017 11:53:40 +0000 (20:53 +0900)
committerKunhoon Baik <knhoon.baik@samsung.com>
Mon, 22 May 2017 11:03:15 +0000 (20:03 +0900)
Considering RSS and Shared of statm is more accurate than using the ratio for RSS.
And, there are many apis for getting memory usage in procfs.
Of course, resourced should know all kinds of memory information
depending on the situations.

For instance, when LMK predicts secured memory usage after killing victims,
it should check real ram usage which considers zram compression ratio.
On the other hand, if someone wants to know memory usage,
it can check approximate memory usage from /proc/{pid}/statm
and swap usage from /proc/{pid}/status.

Conflicts:
src/memory/lowmem-limit.c

Change-Id: I7e664ff40f05fa9c1d8122be64180e5e7a8fab77
Signed-off-by: ByungSoo Kim <bs1770.kim@samsung.com>
src/common/procfs.c
src/common/procfs.h
src/heart/heart-memory.c
src/memory/vmpressure-lowmem-handler.c
src/proc-stat/proc-main.c
src/proc-stat/proc-monitor.c
src/swap/swap.c

index 99f7721b067b197ed2406bcf6f8f7d38c2dd02e7..b734a22ced0309abedda10e21cb8cff99b1a7a7f 100644 (file)
@@ -53,7 +53,9 @@
 
 #define PAGE_SIZE_KB 4
 
-#define MEM_RSS_RATIO                  0.3
+#define PAGE_SHIFT      12
+#define PAGE_SIZE       (1 << PAGE_SHIFT)
+
 #define MEM_SWAP_RATIO                 0.5
 
 static struct sys_node_table sys_node_tables[] = {
@@ -192,13 +194,13 @@ int proc_get_label(pid_t pid, char *label)
        return RESOURCED_ERROR_NONE;
 }
 
-int proc_get_mem_usage(pid_t pid, unsigned int *vmswap, unsigned int *vmrss)
+int proc_get_mem_status(pid_t pid, unsigned int *vmswap, unsigned int *vmrss)
 {
        char filename[PROC_BUF_MAX];
        _cleanup_fclose_ FILE *fp = NULL;
        unsigned int swap = 0, rss = 0;
 
-       snprintf(filename, PROC_BUF_MAX, "/proc/%d/status", pid);
+       sprintf(filename, "/proc/%d/status", pid);
        fp = fopen(filename, "r");
        if (!fp)
                return RESOURCED_ERROR_FAIL;
@@ -290,28 +292,6 @@ int proc_get_uss(pid_t pid, unsigned int *uss)
        return RESOURCED_ERROR_NONE;
 }
 
-int proc_get_rss(pid_t pid, unsigned int *rss)
-{
-       unsigned int vmrss, vmswap;
-       int ret;
-
-       *rss = 0;
-
-       ret = proc_get_mem_usage(pid, &vmswap, &vmrss);
-       if (ret != RESOURCED_ERROR_NONE)
-               return ret;
-
-       /*
-        * USS is more real live usage compare to RSS.
-        * But, RSS is faster to get, PSS is very slow.
-        * So, RSS value with heuristic weight factor and SWAP size which is considered swap compression ration
-        * can be more accurate value as well as getting it fastly.
-        */
-       *rss = vmrss * MEM_RSS_RATIO + vmswap * MEM_SWAP_RATIO;
-
-       return RESOURCED_ERROR_NONE;
-}
-
 int proc_get_zram_usage(pid_t pid, unsigned int *usage)
 {
        int ret;
@@ -331,7 +311,7 @@ int proc_get_zram_usage(pid_t pid, unsigned int *usage)
        }
 
        /* Read usage of Swap (VmSwap) of interested process */
-       ret = proc_get_mem_usage(pid, &proc_swap_usage, NULL);
+       ret = proc_get_mem_status(pid, &proc_swap_usage, NULL);
        if (ret != RESOURCED_ERROR_NONE)
                return ret;
 
@@ -349,28 +329,91 @@ int proc_get_zram_usage(pid_t pid, unsigned int *usage)
        return RESOURCED_ERROR_NONE;
 }
 
-int proc_get_procstat_mem_usage(pid_t pid, unsigned int *usage)
+int proc_get_approx_mem_usage(pid_t pid, unsigned int *usage)
 {
        int ret;
-       unsigned int pss, swap;
+       unsigned long resident = 0, shared = 0;
+       char filename[PROC_BUF_MAX];
+       _cleanup_fclose_ FILE *fp = NULL;
 
-       ret = proc_get_pss(pid, &pss);
-       if (ret != RESOURCED_ERROR_NONE)
-               return ret;
+       snprintf(filename, PROC_BUF_MAX, "/proc/%d/statm", pid);
+       fp = fopen(filename, "r");
+       if (!fp)
+               return RESOURCED_ERROR_FAIL;
 
-       ret = proc_get_mem_usage(pid, &swap, NULL);
-       if (ret != RESOURCED_ERROR_NONE)
-               return ret;
+       /*
+        * For quick read, open code by putting numbers directly
+        * expected format is
+        * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n",
+        *               size, resident, shared, text, data);
+        */
+       ret = fscanf(fp, "%*s %lu %lu %*s %*s %*s %*s\n", &resident, &shared);
+       if (ret < 0)
+               return RESOURCED_ERROR_FAIL;
 
        /*
-        * For user information it's better to present PSS value
-        * as it account libraries as they are shared between processes.
-        *
-        * If process is being swapped (moved to zram) then it's PSS goes
-        * to very low value, then it's needed to account VmSwap usage
-        * so there wouldn't be any strange information about process memory usage.
+        * The value resident - shared is mostly similar to Uss.
         */
-       *usage = pss + swap;
+       *usage = BYTE_TO_KBYTE((resident - shared) << PAGE_SHIFT);
+       return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * @desc get total memory usage from VmSwap and VmRSS.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_mem_usage(pid_t pid, unsigned int *usage)
+{
+       int ret;
+       unsigned int vmswap = 0, total = 0;
+
+       ret = proc_get_approx_mem_usage(pid, &total);
+       if (ret < 0) {
+               _E("Failed to get usage : %d", pid);
+               return ret;
+       }
+
+       if (swap_get_state() == SWAP_ON) {
+               ret = proc_get_mem_status(pid, &vmswap, NULL);
+               if (ret != RESOURCED_ERROR_NONE)
+                       goto out;
+
+               total += vmswap;
+       }
+out:
+       *usage = total;
+       return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * @desc get how much ram is used in each application
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_ram_usage(pid_t pid, unsigned int *usage)
+{
+       int ret;
+       unsigned int vmswap = 0, total = 0;
+
+       ret = proc_get_approx_mem_usage(pid, &total);
+       if (ret < 0) {
+               _E("Failed to get usage : %d", pid);
+               return ret;
+       }
+
+       if (swap_get_state() == SWAP_ON) {
+               ret = proc_get_mem_status(pid, &vmswap, NULL);
+               if (ret != RESOURCED_ERROR_NONE)
+                       goto out;
+
+               /*
+                * If it is necessary to know real ram size about each application,
+                * it should consider compression ratio.
+                */
+               vmswap *= MEM_SWAP_RATIO;
+               total += vmswap;
+       }
+out:
+       *usage = total;
        return RESOURCED_ERROR_NONE;
 }
 
@@ -729,7 +772,7 @@ void proc_print_meninfo(FILE *fp)
                if (ret)
                        continue;
 
-               ret = proc_get_mem_usage(pid, &swap, &rss);
+               ret = proc_get_mem_status(pid, &swap, &rss);
                if (ret)
                        continue;
 
index fe01594b0db26072c50047b5b4b96f40d106b5c3..536de2b9d178fc7f73c20815b1a84cdfe2eba05e 100644 (file)
@@ -231,12 +231,6 @@ int proc_set_oom_score_adj(int pid, int oom_score_adj);
  */
 int proc_get_label(pid_t pid, char *label);
 
-/**
- * @desc get VmSwap and VmRSS from /proc/{pid}/status file.
- * @return negative value if error or pid doesn't exist
- */
-int proc_get_mem_usage(pid_t pid, unsigned int *vmswap, unsigned int *vmrss);
-
 /**
  * @desc get PSS memory usage from /proc/{pid}/smaps file.
  * @return negative value if error or pid doesn't exist
@@ -250,10 +244,10 @@ int proc_get_pss(pid_t pid, unsigned int *pss);
 int proc_get_uss(pid_t pid, unsigned int *uss);
 
 /**
- * @desc get RSS memory usage from /proc/{pid}/status file.
+ * @desc get VmRSS and VmSwap from /proc/{pid}/status file.
  * @return negative value if error or pid doesn't exist
  */
-int proc_get_rss(pid_t pid, unsigned int *rss);
+int proc_get_mem_status(pid_t pid, unsigned int *rss, unsigned int *swap);
 
 /**
  * @desc get aproximated usage of Zram for pid
@@ -262,10 +256,22 @@ int proc_get_rss(pid_t pid, unsigned int *rss);
 int proc_get_zram_usage(pid_t pid, unsigned int *usage);
 
 /**
- * @desc get memory usage for proc-stat: PSS+VmSwap
+ * @desc get approximate memory usage from status and statm
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_approx_mem_usage(pid_t pid, unsigned int *usage);
+
+/**
+ * @desc get total memory usage from VmSwap and VmRSS.
+ * @return negative value if error or pid doesn't exist
+ */
+int proc_get_mem_usage(pid_t pid, unsigned int *usage);
+
+/**
+ * @desc get how much ram is used in each application
  * @return negative value if error or pid doesn't exist
  */
-int proc_get_procstat_mem_usage(pid_t pid, unsigned int *usage);
+int proc_get_ram_usage(pid_t pid, unsigned int *usage);
 
 /**
  * @desc get MemAvaliable from /proc/meminfo or calcuate it by MemFree+Cached
index f789b62078ec7dde10495aff3c20434af2dad42c..4df1a21dd066ec115c79e635aee4eb10feb7f942 100644 (file)
@@ -1016,35 +1016,35 @@ void heart_memory_update(struct logging_table_form *data, void *user_data)
 static int heart_memory_write(char *appid, char *pkgid, struct proc_status *p_data)
 {
        _cleanup_free_ char *info = NULL;
-       unsigned int rss = 0;
+       unsigned int usage = 0;
        int ret;
        struct proc_app_info *pai = p_data->pai;
 
        /* For write to data crud during period */
        /* write memory usage in proc_list */
-       ret = proc_get_rss(p_data->pid, &rss);
+       ret = proc_get_mem_usage(p_data->pid, &usage);
        if (ret < 0) {
                _E("Failed to get PID(%d) rss: %m", p_data->pid);
                return ret;
        }
 
        if (pai && pai->childs) {
-               unsigned int child_rss;
+               unsigned int child_usage;
                GSList *iterchild;
 
                gslist_for_each_item(iterchild, pai->childs) {
                        pid_t child = GPOINTER_TO_PID(iterchild->data);
-                       ret = proc_get_rss(child, &child_rss);
+                       ret = proc_get_mem_usage(child, &child_usage);
                        if (ret < 0) {
                                _E("Failed to get PID(%d) rss: %m", child);
                                continue;
                        }
-                       rss += child_rss;
+                       usage += child_usage;
                }
        }
 
-       _SD("memory write : %s(%d), usage %u", appid, p_data->pid, rss);
-       ret = asprintf(&info, "%u", rss);
+       _SD("memory write : %s(%d), usage %u", appid, p_data->pid, usage);
+       ret = asprintf(&info, "%u", usage);
        if (ret < 0) {
                _E("Failed to allocate memory");
                return -ENOMEM;
index 36fcb8f8925c6b6d1e62d76a0c6d33055c987d5d..440386b28c74a49687050584193821b5c92ff373 100644 (file)
@@ -376,7 +376,7 @@ unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
         * is used.
         */
        if (tsk->pids == NULL) {
-               ret = proc_get_rss(tsk->pid, &size);
+               ret = proc_get_ram_usage(tsk->pid, &size);
 
                /* If there is no proc entry for given pid the process
                 * should be abandoned during further processing
@@ -389,7 +389,7 @@ unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
 
        for (index = 0; index < tsk->pids->len; index++) {
                pid = g_array_index(tsk->pids, pid_t, index);
-               ret = proc_get_rss(pid, &size);
+               ret = proc_get_ram_usage(pid, &size);
                if (ret != RESOURCED_ERROR_NONE)
                        continue;
                total_size += size;
index ec68d345b4514c3230076aaa2faad70d5ad789aa..edfce8bef6861a6d1a070ce7f4269d885f824d7f 100644 (file)
@@ -982,7 +982,7 @@ static void proc_dump_process_list(FILE *fp)
                    pai->lru_state, pai->proc_exclude, pai->runtime_exclude,
                    pai->flags, pai->state);
 
-               if (proc_get_procstat_mem_usage(pai->main_pid, &size))
+               if (proc_get_mem_usage(pai->main_pid, &size))
                        size = 0;
                proc_get_cpu_time(pai->main_pid, &utime, &stime, &starttime);
                LOG_DUMP(fp, "\t main pid : %d, oom score : %d, memory rss : %d KB,"
@@ -990,7 +990,7 @@ static void proc_dump_process_list(FILE *fp)
                    utime, stime, starttime);
                if (pai->childs) {
                        gslist_for_each_item(iter_child, pai->childs) {
-                               if (proc_get_procstat_mem_usage(GPOINTER_TO_PID(iter_child->data), &size))
+                               if (proc_get_mem_usage(GPOINTER_TO_PID(iter_child->data), &size))
                                        size = 0;
                                proc_get_cpu_time(GPOINTER_TO_PID(iter_child->data),
                                                                &utime, &stime, &starttime);
index 83d80b1a619b5905a2f0bcabcda4b9fc476a9745..69c948abd344866169489284333b52aa8aea3542 100755 (executable)
@@ -220,7 +220,7 @@ static void dbus_get_app_memory(GDBusMethodInvocation *invocation, GVariant *par
                return;
        }
 
-       if (proc_get_procstat_mem_usage(pai->main_pid, &usage) < 0) {
+       if (proc_get_mem_usage(pai->main_pid, &usage) < 0) {
                _E("lowmem_get_proc_mem_usage failed for appid = %s (%d)",
                        appid, pai->main_pid);
                D_BUS_REPLY_NULL(invocation);
@@ -249,7 +249,7 @@ static void dbus_get_memory_list(GDBusMethodInvocation *invocation, GVariant *pa
                pai = (struct proc_app_info *)giter->data;
                if (!pai || !pai->main_pid)
                        continue;
-               if (proc_get_procstat_mem_usage(pai->main_pid, &usage) < 0)
+               if (proc_get_mem_usage(pai->main_pid, &usage) < 0)
                        continue;
 
                appid = pai->appid;
@@ -334,7 +334,7 @@ static void dbus_get_memory_lists(GDBusMethodInvocation *invocation, GVariant *p
                        continue;
                if (type != PROC_TYPE_MAX && pai->type != type)
                        continue;
-               if (proc_get_procstat_mem_usage(pai->main_pid, &usage) < 0)
+               if (proc_get_mem_usage(pai->main_pid, &usage) < 0)
                        continue;
 
                appid = pai->appid;
index 2e343bd0dc0e44924e886a263d1b9740b4eee331..15379ecb87c52ed92d5250010f081f21245d8e9e 100644 (file)
@@ -291,7 +291,7 @@ static int swap_reduce_victims(GArray *candidates, int max)
        int index;
        struct swap_task tsk;
        struct proc_app_info *pai = NULL;
-       unsigned int vmrss = 0;
+       unsigned int usage = 0;
 
        if (!candidates)
                return RESOURCED_ERROR_NO_DATA;
@@ -301,19 +301,19 @@ static int swap_reduce_victims(GArray *candidates, int max)
                pai = tsk.pai;
 
                /* Measuring VmRSS is OK as it's anonymous + swapcache */
-               if (proc_get_mem_usage(pai->main_pid, NULL, &vmrss) < 0)
+               if (proc_get_approx_mem_usage(pai->main_pid, &usage) < 0)
                        continue;
 
-               tsk.size += vmrss;
+               tsk.size += usage;
 
                if (pai->childs) {
                        GSList *iter_child = NULL;
 
                        gslist_for_each_item(iter_child, pai->childs) {
                                pid_t child = GPOINTER_TO_PID(iter_child->data);
-                               if (proc_get_mem_usage(child, NULL, &vmrss) < 0)
+                               if (proc_get_approx_mem_usage(child, &usage) < 0)
                                        continue;
-                               tsk.size += vmrss;
+                               tsk.size += usage;
                        }
                }
        }