Add an option for using smaps_rollup 96/287896/2
authorSung-hun Kim <sfoon.kim@samsung.com>
Tue, 7 Feb 2023 09:46:36 +0000 (18:46 +0900)
committerSung-hun Kim <sfoon.kim@samsung.com>
Tue, 7 Feb 2023 11:45:22 +0000 (20:45 +0900)
Recent Linux kernel provides an entry in procfs, namely smaps_rollup,
to improve performance of user programs which want to get the statistics
of process memory like memps.

This patch add an option for using smaps_rollup. If the target kernel
does not provide smaps_rollup, memps falls back to default lookup path
which traverses the smaps file of the process.

Change-Id: I377e00f5eb92f5ba97c583329198f39741e6b2d2
Signed-off-by: Sung-hun Kim <sfoon.kim@samsung.com>
memps.c

diff --git a/memps.c b/memps.c
index b56ff3a..4e3863d 100644 (file)
--- a/memps.c
+++ b/memps.c
@@ -775,6 +775,53 @@ static int get_tmpfs_info(FILE *output_fp)
        return 0;
 }
 
+mapinfo *load_maps_rollup(int pid)
+{
+       char* smaps_rollup;
+       char tmp[128];
+       mapinfo *milist = 0;
+       mapinfo *mi;
+
+       /*
+        * use smaps_rollup instead of traversing smaps
+        * for getting values quickly
+        */
+       snprintf(tmp, sizeof(tmp), "/proc/%d/smaps_rollup", pid);
+       if (access(tmp, F_OK) < 0)
+               return 0;
+
+       smaps_rollup = cread(tmp);
+       if (smaps_rollup == NULL)
+               return 0;
+
+       while ((mi = read_mapinfo(&smaps_rollup)) != 0) {
+               if (milist) {
+                       if ((!strcmp(mi->name, milist->name)
+                            && (mi->name[0] != '['))) {
+                               milist->size += mi->size;
+                               milist->swap += mi->swap;
+                               milist->rss += mi->rss;
+                               milist->pss += mi->pss;
+                               milist->shared_clean += mi->shared_clean;
+                               milist->shared_dirty += mi->shared_dirty;
+                               milist->private_clean += mi->private_clean;
+                               milist->private_dirty += mi->private_dirty;
+
+                               milist->end = mi->end;
+                               strncpy(milist->perm, mi->perm, 4);
+                               free(mi->perm);
+                               free(mi->name);
+                               free(mi);
+                               continue;
+                       }
+               }
+               mi->next = milist;
+               milist = mi;
+       }
+
+       return milist;
+}
+
 mapinfo *load_maps(int pid)
 {
        char* smaps;
@@ -1112,7 +1159,7 @@ static void show_rss(int output_type, char *output_path)
        return;
 }
 
-static int show_map_all_new(int output_type, char *output_path)
+static int show_map_all_new(int output_type, char *output_path, bool use_rollup)
 {
        DIR *pDir = NULL;
        struct dirent *curdir;
@@ -1183,7 +1230,7 @@ static int show_map_all_new(int output_type, char *output_path)
 
        errno = 0;
        while ((curdir = readdir(pDir)) != NULL && !errno) {
-               mapinfo *milist;
+               mapinfo *milist = 0;
 
                pid = atoi(curdir->d_name);
                if (pid < 1 || pid > pid_max || pid == getpid())
@@ -1192,9 +1239,15 @@ static int show_map_all_new(int output_type, char *output_path)
                if (get_cmdline(pid, cmdline) < 0)
                        continue;
 
-               milist = load_maps(pid);
-               if (milist == 0)
-                       continue;
+               if (use_rollup)
+                       milist = load_maps_rollup(pid);
+
+               if (milist == 0) {
+                       /* fall back to the default lookup path */
+                       milist = load_maps(pid);
+                       if (milist == 0)
+                               continue;
+               }
 
                /* get classified map info, milist will be freed */
                get_trib_mapinfo(pid, milist, glist, gpu_glist, &tmi);
@@ -1470,18 +1523,22 @@ int main(int argc, char *argv[])
                        }
                } else if (!strncmp(argv[1], "-a", strlen("-a")+1)) {
                        verbos = 0;
-                       show_map_all_new(OUTPUT_UART, NULL);
+                       show_map_all_new(OUTPUT_UART, NULL, false);
                        usage = 0;
                } else if (!strncmp(argv[1], "-v", strlen("-v")+1)) {
                        verbos = 1;
-                       show_map_all_new(OUTPUT_UART, NULL);
+                       show_map_all_new(OUTPUT_UART, NULL, false);
                        usage = 0;
                } else if (!strncmp(argv[1], "-f", strlen("-f")+1)) {
                        if (argc >= 3) {
                                verbos = 1;
-                               show_map_all_new(OUTPUT_FILE, argv[2]);
+                               show_map_all_new(OUTPUT_FILE, argv[2], false);
                                usage = 0;
                        }
+               } else if (!strncmp(argv[1], "-q", strlen("-q")+1)) {
+                       verbos = 1;
+                       show_map_all_new(OUTPUT_UART, NULL, true);
+                       usage = 0;
                } else if (argc == 2 && atoi(argv[1]) > 0) {
                        show_map_new(atoi(argv[1]));
                        usage = 0;
@@ -1489,12 +1546,13 @@ int main(int argc, char *argv[])
        }
        if (usage) {
                fprintf(stderr,
-                       "memps [-a] | [-v] | [-r] | [-s] <pid> | <pid> | [-f] <output file full path>\n"
+                       "memps [-a] | [-v] | [-q] | [-r] | [-s] <pid> | <pid> | [-f] <output file full path>\n"
                        "        -s = sum (show only sum of each)\n"
                        "        -f = all (show all processes via output file)\n"
                        "        -a = all (show all processes)\n"
                        "        -r = all (show rss of all processes)\n"
-                       "        -v = verbose (show all processes in detail)\n");
+                       "        -v = verbose (show all processes in detail)\n"
+                       "        -q = verbose (experimental - quickly show all processes in detail)\n");
        }
 
        return 0;