Remove mmap size of drm render node as like drm node
[platform/core/system/memps.git] / memps.c
1 /* Copyright 2014-2020 Samsung Electronics Co., Ltd All Rights Reserved
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdbool.h>
19 #include <math.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/vfs.h>
27 #include <linux/limits.h>
28 #include <limits.h>
29
30 #include <ctype.h>
31 #include <stddef.h>
32 #include <inttypes.h>
33
34 #include <dirent.h>
35 #include <sys/utsname.h>
36
37 #define STR_SGX_PATH    "/dev/pvrsrvkm"
38 #define STR_3D_PATH1    "/dev/mali"
39 #define STR_3D_PATH2    "/dev/kgsl-3d0"
40 #define STR_3D_UNIFIED_PATH "/usr/bin/gpu_mem_info"
41 #define STR_DRM_PATH1   "/drm mm object (deleted)"
42 #define STR_DRM_PATH2   "/dev/dri/card"
43 #define STR_DRM_DBG_DIR "/sys/kernel/debug/dri/"
44 #define STR_DRM_RENDER_PATH     "/dev/dri/renderD"
45 #define MEMCG_PATH      "/sys/fs/cgroup/memory"
46 #define ZRAM_USED_PATH  "/sys/block/zram0/mem_used_total"
47 #define ZRAM_MM_STAT_PATH       "/sys/block/zram0/mm_stat"
48 #define OOM_SCORE_ADJ_STR       "oom_score_adj"
49 #define OOM_SCORE_STR   "oom_score"
50
51 #define BUF_MAX         (BUFSIZ)            /* most optimal for libc::stdio */
52 #define BUF_INC_SIZE    (512 * 1024)        /* maximal SMAPS I saw 2 MB     */
53 #define KB(bytes)       ((bytes)/1024)
54
55 #define BYTE_TO_KBYTE(b) ((b) >> 10)
56 #define BYTE_TO_MBYTE(b) ((b) >> 20)
57 #define BYTE_TO_GBYTE(b) ((b) >> 30)
58
59 #define KBYTE_TO_BYTE(k) ((k) << 10)
60 #define KBYTE_TO_MBYTE(k) ((k) >> 10)
61 #define KBYTE_TO_GBYTE(k) ((k) >> 20)
62
63 #define GBYTE_TO_BYTE(g) ((g) << 30)
64 #define GBYTE_TO_KBYTE(g) ((g) << 20)
65 #define GBYTE_TO_MBYTE(g) ((g) << 10)
66
67 typedef struct geminfo geminfo;
68 typedef struct mapinfo mapinfo;
69 typedef struct trib_mapinfo trib_mapinfo;
70
71 enum {
72         OUTPUT_UART,
73         OUTPUT_FILE,
74         NUM_OUTPUT_TYPE
75 };
76
77 struct mapinfo {
78         mapinfo *next;
79         unsigned long start;
80         unsigned long end;
81         unsigned size;
82         unsigned swap;
83         unsigned rss;
84         unsigned pss;
85         unsigned shared_clean;
86         unsigned shared_dirty;
87         unsigned private_clean;
88         unsigned private_dirty;
89         char *perm;
90         char *name;
91 };
92
93 /* classify normal, graphic and other devices memory */
94 struct trib_mapinfo {
95         unsigned shared_clean;
96         unsigned shared_dirty;
97         unsigned private_clean;
98         unsigned private_dirty;
99         unsigned shared_clean_pss;
100         unsigned shared_dirty_pss;
101         unsigned swap;
102         unsigned rss;
103         unsigned pss;
104         unsigned size;
105         unsigned graphic_3d;
106         unsigned gem_rss;
107         unsigned gem_pss;
108         unsigned peak_rss;
109         unsigned other_devices;
110         unsigned gem_mmap;
111         unsigned render_gem_mmap;
112 };
113
114 struct geminfo {
115         geminfo *next;
116         unsigned int tgid;
117         unsigned rss_size;
118         unsigned pss_size;
119         unsigned hcount;
120 };
121
122 static int sum;
123 static int verbos;
124 static int use_gpu_mem_info = 0;
125 static int pid_max = 0;
126 static int dri_card = 0;
127
128 /* reads file contents into memory */
129 static char* cread(const char* path)
130 {
131         /* once allocated area for reads */
132         static char*    text = NULL;
133         static size_t   size = 0;
134
135         ssize_t ret;
136         char*   ptr = text;
137         size_t  cap = size;
138         int     fd  = open(path, O_RDONLY);
139
140         if (fd < 0)
141                 return NULL;
142
143         do {
144                 /* ensure we have enough space */
145                 if (cap == 0) {
146                         ptr = (char*)realloc(text, size + BUF_INC_SIZE);
147                         if (ptr == NULL) {
148                                 ret = -1;
149                                 break;
150                         }
151
152                         text  = ptr;
153                         ptr   = text + size;
154                         cap   = BUF_INC_SIZE;
155                         size += BUF_INC_SIZE;
156                 }
157                 ret = read(fd, ptr, cap);
158                 if (ret == 0) {
159                         *ptr = 0;
160                 } else if (ret > 0) {
161                         cap -= ret;
162                         ptr += ret;
163                 }
164         } while (ret > 0);
165         close(fd);
166
167         return (ret < 0 ? NULL : text);
168 } /* cread */
169
170 /* like fgets/gets but adjusting contents pointer */
171 static inline char* cgets(char** contents)
172 {
173         if (contents && *contents && **contents) {
174                 char* bos = *contents;          /* begin of string */
175                 char* eos = strchr(bos, '\n');  /* end of string   */
176
177                 if (eos) {
178                         *contents = eos + 1;
179                         *eos      = 0;
180                 } else {
181                         *contents = NULL;
182                 }
183                 return bos;
184         }
185
186         return NULL;
187 } /* cgets */
188
189 /* get pid_max value */
190 static inline int get_pid_max(void)
191 {
192         static const char pid_max_path[] = "/proc/sys/kernel/pid_max";
193         char* line;
194
195         line = cread(pid_max_path);
196         if (line == NULL) {
197                 fprintf(stderr, "cannot open %s\n", pid_max_path);
198                 return 0;
199         }
200
201         return strtoul(line, NULL, 10);
202 }
203
204
205 static unsigned get_peak_rss(unsigned int pid)
206 {
207         static const char field[] = "VmHWM:";
208         char tmp[128];
209         char* line;
210         char* value;
211
212         snprintf(tmp, sizeof(tmp), "/proc/%d/status", pid);
213         line = cread(tmp);
214         if (line == NULL) {
215                 fprintf(stderr, "cannot open %s\n", tmp);
216                 return 0;
217         }
218
219         value = strstr(line, field);
220         if (value) {
221                 value += sizeof(field);
222                 return strtoul(value, NULL, 10);
223         }
224
225         return 0;
226 }
227 #define NUM_GEM_FIELD 6
228
229 static geminfo *read_geminfo(FILE *fp)
230 {
231         geminfo *tgeminfo;
232         char line[BUF_MAX];
233         unsigned int pid, tgid, handle, refcount, hcount;
234         unsigned gem_size;
235
236         if (fgets(line, BUF_MAX, fp) != NULL) {
237                 if (sscanf(line, "%d %d %d %d %d 0x%x",
238                         &pid, &tgid, &handle, &refcount,
239                         &hcount, &gem_size) != NUM_GEM_FIELD)
240                         return NULL;
241
242                 if (hcount == 0)
243                         return NULL;
244                 tgeminfo = malloc(sizeof(geminfo));
245                 if (tgeminfo == NULL)
246                         return NULL;
247                 tgeminfo->tgid = tgid;
248                 tgeminfo->hcount = hcount;
249                 tgeminfo->rss_size = KB(gem_size);
250                 tgeminfo->pss_size = KB(gem_size/tgeminfo->hcount);
251         } else
252                 return NULL;
253
254         return tgeminfo;
255 }
256
257
258 static geminfo *find_geminfo(unsigned int tgid, geminfo *gilist)
259 {
260         geminfo *gi;
261         for (gi = gilist; gi; ) {
262                 if (gi->tgid == tgid)
263                         return gi;
264
265                 gi = gi->next;
266         }
267         return NULL;
268 }
269
270 static geminfo *get_geminfo(FILE *drm_fp)
271 {
272         geminfo *ginfo;
273         geminfo *gilist = NULL;
274         geminfo *exist_ginfo = NULL;
275
276         char line[BUF_MAX];
277
278         if (fgets(line, BUF_MAX, drm_fp) == NULL) {
279                 return NULL;
280         } else {
281                 /* we should count a number of whitespace separated fields */
282                 int in_field = (line[0] && !isblank(line[0]));
283                 unsigned int size = (unsigned)in_field;
284                 const char*  ptr  = &line[1];
285
286                 /* sscanf() was used in original code, so number of fields */
287                 /* in string is expected to be at least NUM_GEM_FIELD      */
288                 while (*ptr && size < NUM_GEM_FIELD) {
289                         if (isblank(*ptr++)) {
290                                 if (in_field) {
291                                         /* end of field */
292                                         in_field = 0;
293                                 }
294                         } else {
295                                 if (!in_field) {
296                                         /* next field started */
297                                         in_field = 1;
298                                         size++;
299                                 }
300                         }
301                 } /* while */
302
303                 if (size != NUM_GEM_FIELD) {
304                         return NULL;
305                 }
306         }
307
308         while ((ginfo = read_geminfo(drm_fp)) != NULL) {
309                 if (gilist && ginfo->tgid == gilist->tgid) {
310                         gilist->pss_size += ginfo->pss_size;
311                         gilist->rss_size += ginfo->rss_size;
312                         free(ginfo);
313                         continue;
314                 } else if (gilist && ((exist_ginfo = find_geminfo(ginfo->tgid, gilist)) != NULL)) {
315                         exist_ginfo->pss_size += ginfo->pss_size;
316                         exist_ginfo->rss_size += ginfo->rss_size;
317                         free(ginfo);
318                         continue;
319                 }
320                 ginfo->next = gilist;
321                 gilist = ginfo;
322         }
323
324         return gilist;
325 }
326
327 static geminfo *load_geminfo(void)
328 {
329         geminfo *gilist;
330         FILE *drm_fp;
331
332         drm_fp = fopen(STR_DRM_DBG_DIR "0/gem_info", "r");
333         if (drm_fp == NULL) {
334                 drm_fp = fopen(STR_DRM_DBG_DIR "1/gem_info", "r");
335                 dri_card = 1;
336                 if (drm_fp == NULL) {
337                         fprintf(stderr,
338                                 "cannot open " STR_DRM_DBG_DIR "%d/gem_info\n",
339                                 dri_card);
340                         return NULL;
341                 }
342         }
343
344         gilist = get_geminfo(drm_fp);
345
346         fclose(drm_fp);
347
348         return gilist;
349 }
350
351 static geminfo *load_gpu_geminfo(void)
352 {
353         geminfo *gilist;
354         FILE *drm_fp;
355
356         /* Check the render dri card having gpu_gem_info */
357         drm_fp = fopen(STR_DRM_DBG_DIR "128/gpu_gem_info", "r");
358         if (drm_fp == NULL) {
359                 fprintf(stderr,
360                         "cannot open " STR_DRM_DBG_DIR "128/gpu_gem_info\n");
361                 return NULL;
362         }
363
364         gilist = get_geminfo(drm_fp);
365
366         fclose(drm_fp);
367
368         return gilist;
369 }
370
371 /* b6e82000-b6e83000 rw-p 00020000 b3:19 714        /usr/lib/ld-2.20-2014.11.so  : TM1
372  * 7f9389d000-7f9389e000 rw-p 0001f000 b3:12 618                            /usr/lib64/ld-2.20-2014.11.so  : TM2
373  * 7fae2e4b2000-7fae2e4b3000 r--p 00021000 fe:01 603                        /usr/lib64/ld-2.20-2014.11.so  : x86-64 Emulator
374  * 01234567890123456789012345678901234567890123456789012345678901234567890123456789
375  * 0         1         2         3         4         5         6         7
376  */
377 mapinfo *read_mapinfo(char** smaps)
378 {
379         char* line;
380         mapinfo *mi;
381         int len;
382         int n;
383
384         if ((line = cgets(smaps)) == 0)
385                 return 0;
386
387         len = strlen(line);
388         if (len < 1)
389                 return 0;
390
391         mi = malloc(sizeof(mapinfo));
392         if (mi == 0)
393                 return 0;
394
395         n = sscanf(line, "%lx-%lx %ms %*s %*s %*s %m[^\n]",
396                            &mi->start, &mi->end, &mi->perm, &mi->name);
397
398         if (n == 3 && !mi->name)
399                 mi->name = strndup("[anon]", strlen("[anon]"));
400         else if (n <= 3) {
401                 fprintf(stderr, "Fail to parse smaps\n");
402                 free(mi);
403                 return 0;
404         }
405
406         while ((line = cgets(smaps))) {
407                 if (sscanf(line, "Size: %d kB", &mi->size) == 1)
408                         ;
409                 else if (sscanf(line, "Rss: %d kB", &mi->rss) == 1)
410                         ;
411                 else if (sscanf(line, "Pss: %d kB", &mi->pss) == 1)
412                         ;
413                 else if (sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) == 1)
414                         ;
415                 else if (sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) == 1)
416                         ;
417                 else if (sscanf(line, "Private_Clean: %d kB", &mi->private_clean) == 1)
418                         ;
419                 else if (sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) == 1)
420                         ;
421                 else if (sscanf(line, "Swap: %d kB", &mi->swap) == 1)
422                         ;
423                 if (*smaps) {
424                         /* Drain lines until it meets next VMA address */
425                         char next = **smaps;
426                         if  ((next >= '0' && next <= '9') || (next >= 'a' && next <= 'f'))
427                                 break;
428                 }
429         }
430
431         return mi;
432 }
433
434 static unsigned total_gem_memory(void)
435 {
436         FILE *gem_fp;
437         unsigned total_gem_mem = 0;
438         unsigned name, size, handles, refcount;
439         char line[BUF_MAX];
440
441         if (!dri_card)
442                 gem_fp = fopen(STR_DRM_DBG_DIR "0/gem_names", "r");
443         else
444                 gem_fp = fopen(STR_DRM_DBG_DIR "1/gem_names", "r");
445         if (gem_fp == NULL) {
446                 fprintf(stderr,
447                 "cannot open " STR_DRM_DBG_DIR "%d/gem_names\n", dri_card);
448                 return 0;
449         }
450
451         if (fgets(line, BUF_MAX, gem_fp) == NULL) {
452                 fclose(gem_fp);
453                 return 0;
454         }
455
456         while (fgets(line, BUF_MAX, gem_fp) != NULL) {
457                 if (sscanf(line, "%d %d %d %d\n",
458                     &name, &size, &handles, &refcount) == 4) {
459                         if (total_gem_mem <= UINT_MAX - size) {
460                                 total_gem_mem += size;
461                         }
462                 }
463         }
464         fclose(gem_fp);
465
466         return total_gem_mem;
467 }
468
469 int get_zram_used(u_int32_t *zram_used)
470 {
471         FILE *f = NULL;
472         /* only read 3rd value */
473         char *fscanf_format = "%*d %*d %d %*d %*d %*d %*d %*d";
474         int ret;
475
476         f = fopen(ZRAM_MM_STAT_PATH, "r");
477         if (!f) {
478                 /*
479                  * ZRAM_USED_PATH is deprecated on latest kernel, but to support
480                  * old kernel try with that if fails new node 'mm_stat'.
481                  */
482                 f = fopen(ZRAM_USED_PATH, "r");
483                 if (!f) {
484                         fprintf(stderr, "Fail to open zram file.\n");
485                         return -1;
486                 }
487                 fscanf_format = "%u";
488         }
489
490         ret = fscanf(f, fscanf_format, zram_used);
491         if (ret == EOF) {
492                 fprintf(stderr, "Fail to read file\n");
493                 fclose(f);
494                 return -1;
495         }
496
497         fclose(f);
498         return 0;
499 }
500
501 int fread_uint(const char *path, u_int32_t *number)
502 {
503         FILE *f = NULL;
504         int ret;
505
506         f = fopen(path, "r");
507
508         if (!f) {
509                 fprintf(stderr, "Fail to open %s file.\n", path);
510                 return -1;
511         }
512
513         ret = fscanf(f, "%u", number);
514         if (ret == EOF) {
515                 fprintf(stderr, "Fail to read file\n");
516                 fclose(f);
517                 return -1;
518         }
519
520         fclose(f);
521         return 0;
522 }
523
524 static int cgroup_read_node(const char *cgroup_name,
525                 const char *file_name, unsigned int *value)
526 {
527         char buf[PATH_MAX + NAME_MAX];
528         int ret;
529         snprintf(buf, sizeof(buf), "%s%s", cgroup_name, file_name);
530         ret = fread_uint(buf, value);
531         return ret;
532 }
533
534 /**
535  * @desc Provides usage in bytes for provided memory cgroup. Works
536  * with/without swap accounting.
537  *
538  * @param memcg_path[in] Full path to memory cgroup
539  * @param swap[in] Boolean value for deciding if account usage with swap
540  * @return current cgroup usage in bytes or 0 on error
541  */
542 static unsigned int get_memcg_usage(const char *memcg_path, bool swap)
543 {
544         int ret;
545         unsigned int usage;
546
547         if (swap) {
548                 ret = cgroup_read_node(memcg_path,
549                                 "/memory.memsw.usage_in_bytes", &usage);
550         } else {
551                 ret = cgroup_read_node(memcg_path, "/memory.usage_in_bytes",
552                                 &usage);
553         }
554
555         if (ret != 0)
556                 usage = 0;
557
558         return usage;
559 }
560
561 static void get_memcg_info(FILE *output_fp)
562 {
563         char buf[PATH_MAX];
564         DIR *pdir = NULL;
565         struct dirent *entry;
566         struct stat path_stat;
567         long usage_swap;
568         unsigned long usage, usage_with_swap;
569
570         fprintf(output_fp, "====================================================================\n");
571         fprintf(output_fp, "MEMORY CGROUPS USAGE INFO\n");
572
573         pdir = opendir(MEMCG_PATH);
574         if (pdir == NULL) {
575                 fprintf(stderr, "cannot read directory %s", MEMCG_PATH);
576                 return;
577         }
578
579         errno = 0;
580         while ((entry = readdir(pdir)) != NULL && !errno) {
581                 snprintf(buf, sizeof(buf), "%s/%s", MEMCG_PATH, entry->d_name);
582                 /* If can't stat then ignore */
583                 if (stat(buf, &path_stat) != 0)
584                         continue;
585
586                 /* If it's not directory or it's parent path then ignore */
587                 if (!(S_ISDIR(path_stat.st_mode) &&
588                         strncmp(entry->d_name, "..", 3)))
589                         continue;
590
591                 usage = get_memcg_usage(buf, false);
592                 usage_with_swap = get_memcg_usage(buf, true);
593                 /* It is posible by rounding errors to get negative value */
594                 usage_swap = usage_with_swap - usage;
595                 if (usage_swap < 0)
596                         usage_swap = 0;
597
598                 /* Case of root cgroup in hierarchy */
599                 if (!strncmp(entry->d_name, ".", 2))
600                         fprintf(output_fp, "%13s Mem %3ld MB (%6ld kB), Mem+Swap %3ld MB (%6ld kB), Swap %3ld MB (%6ld kB) \n\n",
601                                 MEMCG_PATH, BYTE_TO_MBYTE(usage),
602                                 BYTE_TO_KBYTE(usage),
603                                 BYTE_TO_MBYTE(usage_with_swap),
604                                 BYTE_TO_KBYTE(usage_with_swap),
605                                 BYTE_TO_MBYTE(usage_swap),
606                                 BYTE_TO_KBYTE(usage_swap));
607                 else
608                         fprintf(output_fp, "memcg: %13s  Mem %3ld MB (%6ld kB), Mem+Swap %3ld MB (%6ld kB), Swap %3ld MB (%6ld kB)\n",
609                                 entry->d_name, BYTE_TO_MBYTE(usage),
610                                 BYTE_TO_KBYTE(usage),
611                                 BYTE_TO_MBYTE(usage_with_swap),
612                                 BYTE_TO_KBYTE(usage_with_swap),
613                                 BYTE_TO_MBYTE(usage_swap),
614                                 BYTE_TO_KBYTE(usage_swap));
615
616         }
617
618         closedir(pdir);
619 }
620
621 static void get_mem_info(FILE *output_fp)
622 {
623         char buf[PATH_MAX];
624         FILE *fp;
625         char *idx;
626         unsigned int free = 0, cached = 0;
627         unsigned int total_mem = 0, available = 0, used;
628         unsigned int swap_total = 0, swap_free = 0, zram_used, swap_used;
629         unsigned int used_ratio;
630
631         if (output_fp == NULL)
632                 return;
633
634         fp = fopen("/proc/meminfo", "r");
635
636         if (!fp) {
637                 fprintf(stderr, "/proc/meminfo open failed, %p", fp);
638                 return;
639         }
640
641         while (fgets(buf, PATH_MAX, fp) != NULL) {
642                 if ((idx = strstr(buf, "MemTotal:"))) {
643                         idx += strlen("Memtotal:");
644                         while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
645                                 idx++;
646                         total_mem = atoi(idx);
647                 } else if ((idx = strstr(buf, "MemFree:"))) {
648                         idx += strlen("MemFree:");
649                         while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
650                                 idx++;
651                         free = atoi(idx);
652                 } else if ((idx = strstr(buf, "MemAvailable:"))) {
653                         idx += strlen("MemAvailable:");
654                         while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
655                                 idx++;
656                         available = atoi(idx);
657                 } else if ((idx = strstr(buf, "Cached:")) && !strstr(buf, "Swap")) {
658                         idx += strlen("Cached:");
659                         while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
660                                 idx++;
661                         cached = atoi(idx);
662                 } else if ((idx = strstr(buf, "SwapTotal:"))) {
663                         idx += strlen("SwapTotal:");
664                         while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
665                                 idx++;
666                         swap_total = atoi(idx);
667                 } else if ((idx = strstr(buf, "SwapFree:"))) {
668                         idx += strlen("SwapFree");
669                         while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
670                                 idx++;
671                         swap_free = atoi(idx);
672                         break;
673                 }
674         }
675
676         if (total_mem == 0) {
677                 fprintf(stderr, "cannot get total memory size\n");
678                 fclose(fp);
679                 return;
680         }
681
682         if (available == 0)
683                 available = free + cached;
684         used = total_mem - available;
685         used_ratio = used * 100 / total_mem;
686         swap_used = swap_total - swap_free;
687
688         if (get_zram_used(&zram_used) < 0)
689                 zram_used = 0;
690
691         fprintf(output_fp,
692                 "====================================================================\n");
693
694
695         fprintf(output_fp, "Total RAM size: \t%15d MB( %6d kB)\n",
696                         total_mem >> 10, total_mem);
697
698         fprintf(output_fp, "Used (Mem+Reclaimable): %15d MB( %6d kB)\n",
699                         (total_mem - free) >> 10, total_mem - free);
700
701         fprintf(output_fp, "Used (Mem+Swap): \t%15d MB( %6d kB)\n",
702                         used >> 10, used);
703
704         fprintf(output_fp, "Used (Mem):  \t\t%15d MB( %6d kB)\n",
705                         used >> 10, used);
706
707         fprintf(output_fp, "Used (Swap): \t\t%15d MB( %6d kB)\n",
708                         swap_used >> 10, swap_used);
709
710         fprintf(output_fp, "Used (Zram block device): %13d MB( %6d kB)\n",
711             BYTE_TO_MBYTE(zram_used), BYTE_TO_KBYTE(zram_used));
712
713         fprintf(output_fp, "Used Ratio: \t\t%15d  %%\n", used_ratio);
714
715         fprintf(output_fp, "Mem Free:\t\t%15d MB( %6d kB)\n",
716                         free >> 10, free);
717
718         fprintf(output_fp, "Available (Free+Reclaimable):%10d MB( %6d kB)\n",
719                         available >> 10,
720                         available);
721         fclose(fp);
722 }
723
724 static int get_tmpfs_info(FILE *output_fp)
725 {
726         FILE *fp;
727         char line[BUF_MAX];
728         char *tmpfs_mp; /* tmpfs mount point */
729         struct statfs tmpfs_info;
730
731         if (output_fp == NULL)
732                 return -1;
733
734         fp = fopen("/etc/mtab", "r");
735         if (fp == NULL)
736                 return -1;
737
738         fprintf(output_fp,
739                 "====================================================================\n");
740         fprintf(output_fp, "TMPFS INFO\n");
741
742         while (fgets(line, BUF_MAX, fp) != NULL) {
743                 if (sscanf(line, "tmpfs %ms tmpfs", &tmpfs_mp) == 1) {
744                         if (statfs(tmpfs_mp, &tmpfs_info) == 0) {
745                                 fprintf(output_fp,
746 #ifndef __USE_FILE_OFFSET64
747                                         "tmpfs %16s  Total %8ld KB, Used %8ld, Avail %8ld\n",
748 #else
749                                         "tmpfs %16s  Total %8"PRId64" KB, Used %8"PRId64", Avail %8"PRId64"\n",
750 #endif
751                                         tmpfs_mp,
752                                         /* 1 block is 4 KB */
753                                         tmpfs_info.f_blocks * 4,
754                                         (tmpfs_info.f_blocks - tmpfs_info.f_bfree) * 4,
755                                         tmpfs_info.f_bfree * 4);
756                         }
757                         free(tmpfs_mp);
758                         tmpfs_mp = NULL;
759                 }
760         }
761         fclose(fp);
762         return 0;
763 }
764
765 mapinfo *load_maps(int pid)
766 {
767         char* smaps;
768         char tmp[128];
769         mapinfo *milist = 0;
770         mapinfo *mi;
771
772         snprintf(tmp, sizeof(tmp), "/proc/%d/smaps", pid);
773         smaps = cread(tmp);
774         if (smaps == NULL)
775                 return 0;
776
777         while ((mi = read_mapinfo(&smaps)) != 0) {
778                 if (milist) {
779                         if ((!strcmp(mi->name, milist->name)
780                              && (mi->name[0] != '['))) {
781                                 milist->size += mi->size;
782                                 milist->swap += mi->swap;
783                                 milist->rss += mi->rss;
784                                 milist->pss += mi->pss;
785                                 milist->shared_clean += mi->shared_clean;
786                                 milist->shared_dirty += mi->shared_dirty;
787                                 milist->private_clean += mi->private_clean;
788                                 milist->private_dirty += mi->private_dirty;
789
790                                 milist->end = mi->end;
791                                 strncpy(milist->perm, mi->perm, 4);
792                                 free(mi->perm);
793                                 free(mi->name);
794                                 free(mi);
795                                 continue;
796                         }
797                 }
798                 mi->next = milist;
799                 milist = mi;
800         }
801
802         return milist;
803 }
804
805 static void init_trib_mapinfo(trib_mapinfo *tmi)
806 {
807         if (!tmi)
808                 return;
809         tmi->shared_clean = 0;
810         tmi->shared_dirty = 0;
811         tmi->private_clean = 0;
812         tmi->private_dirty = 0;
813         tmi->swap = 0;
814         tmi->shared_clean_pss = 0;
815         tmi->shared_dirty_pss = 0;
816         tmi->rss = 0;
817         tmi->pss = 0;
818         tmi->size = 0;
819         tmi->graphic_3d = 0;
820         tmi->gem_rss = 0;
821         tmi->gem_pss = 0;
822         tmi->peak_rss = 0;
823         tmi->other_devices = 0;
824         tmi->gem_mmap = 0;
825         tmi->render_gem_mmap = 0;
826 }
827
828 unsigned int get_graphic_3d_meminfo(unsigned int tgid)
829 {
830         char command[256], buf[256];
831         char *tmp[2];
832         unsigned int size = 0;
833         int tid, ret;
834         FILE *p_gpu;
835
836         snprintf(command, sizeof(command), "%s %d", STR_3D_UNIFIED_PATH, tgid);
837         p_gpu = popen(command, "r");
838         if (p_gpu) {
839                 if (fgets(buf, 256, p_gpu)) {
840                         ret = sscanf(buf, "%d %ms %d %ms", &tid, &tmp[0], &size, &tmp[1]);
841                         if (ret == 4) {
842                                 free(tmp[0]);
843                                 free(tmp[1]);
844                         }
845                 }
846                 pclose(p_gpu);
847         }
848         return size;
849 }
850
851 static int
852 get_trib_mapinfo(unsigned int tgid, mapinfo *milist,
853                  geminfo *gilist, geminfo *gpu_glist,
854                  trib_mapinfo *result)
855
856 {
857         mapinfo *mi;
858         mapinfo *temp = NULL;
859         geminfo *gi;
860
861         if (!result)
862                 return -EINVAL;
863
864         init_trib_mapinfo(result);
865
866         if (use_gpu_mem_info)
867                 result->graphic_3d = get_graphic_3d_meminfo(tgid);
868
869         for (mi = milist; mi;) {
870                 if (!use_gpu_mem_info && strstr(mi->name, STR_SGX_PATH)) {
871                         result->graphic_3d += mi->pss;
872                 } else if (!use_gpu_mem_info && (strstr(mi->name, STR_3D_PATH1) ||
873                         strstr(mi->name, STR_3D_PATH2))) {
874                         result->graphic_3d += mi->size;
875                 } else if (mi->rss != 0 && mi->pss == 0
876                            && mi->shared_clean == 0
877                            && mi->shared_dirty == 0
878                            && mi->private_clean == 0
879                            && mi->private_dirty == 0
880                            && mi->swap == 0) {
881                         result->other_devices += mi->size;
882                 } else if (!strncmp(mi->name, STR_DRM_PATH1,
883                                 sizeof(STR_DRM_PATH1)) ||
884                                 !strncmp(mi->name, STR_DRM_PATH2,
885                                 sizeof(STR_DRM_PATH2))) {
886                         result->gem_mmap += mi->rss;
887                 } else if (!strncmp(mi->name, STR_DRM_RENDER_PATH,
888                                 sizeof(STR_DRM_RENDER_PATH))) {
889                         result->render_gem_mmap += mi->rss;
890                 } else {
891                         result->shared_clean += mi->shared_clean;
892                         result->shared_dirty += mi->shared_dirty;
893                         result->private_clean += mi->private_clean;
894                         result->private_dirty += mi->private_dirty;
895                         result->swap += mi->swap;
896                         result->rss += mi->rss;
897                         result->pss += mi->pss;
898                         result->size += mi->size;
899
900                         if (mi->shared_clean != 0)
901                                 result->shared_clean_pss += mi->pss;
902                         else if (mi->shared_dirty != 0)
903                                 result->shared_dirty_pss += mi->pss;
904                 }
905
906                 temp = mi;
907                 mi = mi->next;
908                 free(temp->perm);
909                 free(temp->name);
910                 free(temp);
911                 temp = NULL;
912         }
913
914         result->peak_rss = get_peak_rss(tgid);
915         if (result->peak_rss < result->rss)
916                 result->peak_rss = result->rss;
917         if (result->gem_mmap > 0)
918                 result->peak_rss -= result->gem_mmap;
919         if (result->render_gem_mmap > 0)
920                 result->peak_rss -= result->render_gem_mmap;
921
922         gi = find_geminfo(tgid, gilist);
923         if (gi != NULL) {
924                 result->gem_rss = gi->rss_size;
925                 result->gem_pss = gi->pss_size;
926         }
927
928         if (gpu_glist) {
929                 /*
930                  * drm render has gpu_gem_info, then use gpua gem pss
931                  * as graphic 3d memory
932                  */
933                 gi = find_geminfo(tgid, gpu_glist);
934                 if (gi != NULL)
935                         result->graphic_3d += gi->pss_size;
936         }
937
938         return 0;
939 }
940
941 static int get_cmdline(unsigned int pid, char *cmdline)
942 {
943         FILE *fp;
944         char buf[NAME_MAX] = {0, };
945         int ret = -1;
946
947         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
948         fp = fopen(buf, "r");
949         if (fp == 0) {
950                 if (errno == ENOENT)
951                         errno = 0;
952                 fprintf(stderr, "cannot file open %s\n", buf);
953                 return ret;
954         }
955         if ((ret = fscanf(fp, "%4095s", cmdline)) < 1) {
956                 fclose(fp);
957                 return ret;
958         }
959         fclose(fp);
960
961         return ret;
962 }
963
964 static int get_oomscoreadj(unsigned int pid, const char *oom_string)
965 {
966         FILE *fp;
967         char tmp[256];
968         int oomadj_val;
969
970         snprintf(tmp, sizeof(tmp), "/proc/%d/%s", pid, oom_string);
971         fp = fopen(tmp, "r");
972
973         if (fp == NULL) {
974                 oomadj_val = -50;
975                 return oomadj_val;
976         }
977         if (fgets(tmp, sizeof(tmp), fp) == NULL) {
978                 oomadj_val = -100;
979                 fclose(fp);
980                 return oomadj_val;
981         }
982
983         oomadj_val = atoi(tmp);
984
985         fclose(fp);
986         return oomadj_val;
987 }
988
989 static void get_rss(pid_t pid, unsigned long *result)
990 {
991         FILE *fp;
992         char proc_path[PATH_MAX];
993         unsigned long rss = 0;
994
995         *result = 0;
996
997         snprintf(proc_path, sizeof(proc_path), "/proc/%d/statm", pid);
998         fp = fopen(proc_path, "r");
999         if (fp == NULL)
1000                 return;
1001
1002         if (fscanf(fp, "%*s %ld", &rss) < 1) {
1003                 fclose(fp);
1004                 return;
1005         }
1006
1007         fclose(fp);
1008
1009         /* convert page to Kb */
1010         *result = rss << 2;
1011         return;
1012 }
1013
1014 static const char* get_readable_oom_path(void)
1015 {
1016         FILE *fp = NULL;
1017         char tmp[256];
1018
1019         snprintf(tmp, sizeof(tmp), "/proc/1/%s", OOM_SCORE_ADJ_STR);
1020         fp = fopen(tmp, "r");
1021         if (fp) {
1022                 fclose(fp);
1023                 return OOM_SCORE_ADJ_STR;
1024         }
1025         snprintf(tmp, sizeof(tmp), "/proc/1/%s", OOM_SCORE_STR);
1026         fp = fopen(tmp, "r");
1027         if (fp) {
1028                 fclose(fp);
1029                 return OOM_SCORE_STR;
1030         }
1031         return NULL;
1032 }
1033
1034 static void show_rss(int output_type, char *output_path)
1035 {
1036         DIR *pDir = NULL;
1037         struct dirent *curdir;
1038         pid_t pid;
1039         char cmdline[PATH_MAX];
1040         FILE *output_file = NULL;
1041         int oom_score_adj;
1042         unsigned long rss;
1043         const char *oom_path = NULL;
1044
1045         oom_path = get_readable_oom_path();
1046         if (!oom_path) {
1047                 fprintf(stderr, "there is no readable oom path\n");
1048                 return;
1049         }
1050
1051         pDir = opendir("/proc");
1052         if (pDir == NULL) {
1053                 fprintf(stderr, "cannot read directory /proc.\n");
1054                 return;
1055         }
1056
1057         if (output_type == OUTPUT_FILE && output_path) {
1058                 output_file = fopen(output_path, "w+");
1059                 if (!output_file) {
1060                         fprintf(stderr, "cannot open output file(%s)\n",
1061                                 output_path);
1062                         closedir(pDir);
1063                         exit(1);
1064                 }
1065         } else
1066                 output_file = stdout;
1067
1068
1069         fprintf(output_file,
1070                         "     PID      RSS %14s    COMMAND\n", oom_path);
1071
1072         errno = 0;
1073         while ((curdir = readdir(pDir)) != NULL && !errno) {
1074                 pid = atoi(curdir->d_name);
1075                 if (pid < 1 || pid > pid_max || pid == getpid())
1076                         continue;
1077
1078                 if (get_cmdline(pid, cmdline) < 0)
1079                         continue;
1080                 get_rss(pid, &rss);
1081                 oom_score_adj = get_oomscoreadj(pid, oom_path);
1082
1083                 fprintf(output_file,
1084                                 "%8d %8lu       %8d    %s\n",
1085                                 pid,
1086                                 rss,
1087                                 oom_score_adj,
1088                                 cmdline);
1089
1090
1091         } /* end of while */
1092
1093         get_tmpfs_info(output_file);
1094         get_mem_info(output_file);
1095
1096         fclose(output_file);
1097         closedir(pDir);
1098
1099         return;
1100 }
1101
1102 static int show_map_all_new(int output_type, char *output_path)
1103 {
1104         DIR *pDir = NULL;
1105         struct dirent *curdir;
1106         unsigned int pid;
1107         mapinfo *milist;
1108         geminfo *glist;
1109         geminfo *gpu_glist;
1110         unsigned total_pss = 0;
1111         unsigned total_private = 0;
1112         unsigned total_private_code = 0;
1113         unsigned total_private_data = 0;
1114         unsigned total_shared_code = 0;
1115         unsigned total_shared_data = 0;
1116         unsigned total_shared_code_pss = 0;
1117         unsigned total_shared_data_pss = 0;
1118         unsigned total_swap = 0;
1119         unsigned total_rss = 0;
1120         unsigned total_graphic_3d = 0;
1121         unsigned total_gem_rss = 0;
1122         unsigned total_gem_pss = 0;
1123         unsigned total_peak_rss = 0;
1124         unsigned total_allocated_gem = 0;
1125         trib_mapinfo tmi;
1126         char cmdline[PATH_MAX];
1127         FILE *output_file = NULL;
1128         int oom_score_adj;
1129         const char *oom_path = NULL;
1130
1131         oom_path = get_readable_oom_path();
1132         if (!oom_path) {
1133                 fprintf(stderr, "there is no readable oom path\n");
1134                 return 0;
1135         }
1136
1137         use_gpu_mem_info = (!access(STR_3D_UNIFIED_PATH, F_OK | X_OK)) ? 1 : 0;
1138         errno = 0;
1139
1140         pDir = opendir("/proc");
1141         if (pDir == NULL) {
1142                 fprintf(stderr, "cannot read directory /proc.\n");
1143                 return 0;
1144         }
1145
1146         if (output_type == OUTPUT_FILE && output_path) {
1147                 output_file = fopen(output_path, "w+");
1148                 if (!output_file) {
1149                         fprintf(stderr, "cannot open output file(%s)\n",
1150                                 output_path);
1151                         closedir(pDir);
1152                         exit(1);
1153                 }
1154         } else
1155                 output_file = stdout;
1156
1157         glist = load_geminfo();
1158         gpu_glist = load_gpu_geminfo();
1159
1160         if (!sum) {
1161                 if (verbos)
1162                         fprintf(output_file,
1163                                         "     PID  S(CODE)  S(DATA)  P(CODE)  P(DATA) "
1164                                         "    PEAK      PSS       3D GEM(PSS) GEM(RSS) "
1165                                         "    SWAP %14s    COMMAND\n", oom_path);
1166                 else
1167                         fprintf(output_file,
1168                                         "     PID     CODE     DATA     PEAK      PSS "
1169                                         "      3D GEM(PSS)     SWAP    COMMAND\n");
1170         }
1171
1172         errno = 0;
1173         while ((curdir = readdir(pDir)) != NULL && !errno) {
1174                 pid = atoi(curdir->d_name);
1175                 if (pid < 1 || pid > pid_max || pid == getpid())
1176                         continue;
1177
1178                 if (get_cmdline(pid, cmdline) < 0)
1179                         continue;
1180
1181                 milist = load_maps(pid);
1182                 if (milist == 0)
1183                         continue;
1184
1185                 /* get classified map info */
1186                 get_trib_mapinfo(pid, milist, glist, gpu_glist, &tmi);
1187                 oom_score_adj = get_oomscoreadj(pid, oom_path);
1188
1189                 if (!sum) {
1190                         if (verbos)
1191                                 fprintf(output_file,
1192                                         "%8d %8d %8d %8d %8d "
1193                                         "%8d %8d %8d %8d %8d "
1194                                         "%8d       %8d    %s\n",
1195                                         pid,
1196                                         tmi.shared_clean,
1197                                         tmi.shared_dirty,
1198                                         tmi.private_clean,
1199                                         tmi.private_dirty,
1200                                         tmi.peak_rss,
1201                                         tmi.pss,
1202                                         tmi.graphic_3d,
1203                                         tmi.gem_pss,
1204                                         tmi.gem_rss,
1205                                         tmi.swap,
1206                                         oom_score_adj,
1207                                         cmdline);
1208                         else
1209                                 fprintf(output_file,
1210                                         "%8d %8d %8d %8d %8d "
1211                                         "%8d %8d %8d    %s\n",
1212                                         pid,
1213                                         tmi.shared_clean + tmi.private_clean,
1214                                         tmi.shared_dirty + tmi.private_dirty,
1215                                         tmi.peak_rss,
1216                                         tmi.pss,
1217                                         tmi.graphic_3d,
1218                                         tmi.gem_pss,
1219                                         tmi.swap,
1220                                         cmdline);
1221
1222                         if (tmi.other_devices != 0)
1223                                 fprintf(output_file,
1224                                         "%s(%d) %d KB may mapped by device(s).\n",
1225                                         cmdline, pid, tmi.other_devices);
1226                 }
1227
1228                 total_private += (tmi.private_clean + tmi.private_dirty);
1229                 total_pss += tmi.pss;
1230                 total_rss += tmi.rss;
1231                 total_graphic_3d += tmi.graphic_3d;
1232                 total_gem_rss += tmi.gem_rss;
1233                 total_gem_pss += tmi.gem_pss;
1234                 total_private_code += tmi.private_clean;
1235                 total_private_data += tmi.private_dirty;
1236                 total_swap += tmi.swap;
1237                 total_shared_code += tmi.shared_clean;
1238                 total_shared_data += tmi.shared_dirty;
1239                 total_peak_rss += tmi.peak_rss;
1240
1241                 total_shared_code_pss += tmi.shared_clean_pss;
1242                 total_shared_data_pss += tmi.shared_dirty_pss;
1243
1244         } /* end of while */
1245
1246         total_allocated_gem = KB(total_gem_memory());
1247         fprintf(output_file,
1248                         "==============================================="
1249                         "===============================================\n");
1250         if (verbos) {
1251                 fprintf(output_file,
1252                                 "TOTAL:    S(CODE)  S(DATA)  P(CODE)  P(DATA) "
1253                                 "    PEAK      PSS       3D GEM(PSS) GEM(RSS) "
1254                                 "GEM(ALLOC)     SWAP  TOTAL(KB)\n");
1255                 fprintf(output_file,
1256                         "         %8d %8d %8d %8d "
1257                         "%8d %8d %8d %8d %8d "
1258                         "%10d %8d %10d\n",
1259                         total_shared_code, total_shared_data,
1260                         total_private_code, total_private_data,
1261                         total_peak_rss, total_pss, total_graphic_3d,
1262                         total_gem_pss, total_gem_rss,
1263                         total_allocated_gem, total_swap,
1264                         total_pss + total_graphic_3d +
1265                         total_allocated_gem);
1266         } else {
1267                 fprintf(output_file,
1268                         "TOTAL:       CODE     DATA     PEAK      PSS "
1269                         "      3D GEM(PSS) GEM(ALLOC)     SWAP  TOTAL(KB)\n");
1270                 fprintf(output_file,
1271                         "         %8d %8d %8d %8d "
1272                         "%8d %8d %10d %8d %10d\n",
1273                         total_shared_code + total_private_code,
1274                         total_shared_data + total_private_data,
1275                         total_peak_rss, total_pss,
1276                         total_graphic_3d, total_gem_pss,
1277                         total_allocated_gem, total_swap,
1278                         total_pss + total_graphic_3d +
1279                         total_allocated_gem);
1280
1281         }
1282
1283         if (verbos)
1284                 fprintf(output_file,
1285                         "* S(CODE): shared clean memory, it includes"
1286                         " duplicated memory\n"
1287                         "* S(DATA): shared dirty memory, it includes"
1288                         " duplicated memory\n"
1289                         "* P(CODE): private clean memory\n"
1290                         "* P(DATA): private dirty memory\n"
1291                         "* PEAK: peak memory usage of S(CODE) + S(DATA)"
1292                         " + P(CODE) + P(DATA)\n"
1293                         "* PSS: Proportional Set Size\n"
1294                         "* 3D: memory allocated by GPU driver\n"
1295                         "* GEM(PSS): GEM memory divided by # of sharers\n"
1296                         "* GEM(RSS): GEM memory including duplicated memory\n"
1297                         "* GEM(ALLOC): sum of unique gem memory in the system\n"
1298                         "* TOTAL: PSS + 3D + GEM(ALLOC)\n");
1299         else
1300                 fprintf(output_file,
1301                         "* CODE: shared and private clean memory\n"
1302                         "* DATA: shared and private dirty memory\n"
1303                         "* PEAK: peak memory usage of CODE + DATA\n"
1304                         "* PSS: Proportional Set Size\n"
1305                         "* 3D: memory allocated by GPU driver\n"
1306                         "* GEM(PSS): GEM memory divided by # of sharers\n"
1307                         "* GEM(ALLOC): sum of unique GEM memory in the system\n"
1308                         "* TOTAL: PSS + 3D + GEM(ALLOC)\n");
1309
1310         get_tmpfs_info(output_file);
1311         get_memcg_info(output_file);
1312         get_mem_info(output_file);
1313
1314         fclose(output_file);
1315         if (glist)
1316                 free(glist);
1317         if (gpu_glist)
1318                 free(gpu_glist);
1319         closedir(pDir);
1320         return 1;
1321 }
1322
1323 static int show_map_new(int pid)
1324 {
1325         mapinfo *milist;
1326         mapinfo *mi;
1327         mapinfo *temp = NULL;
1328         unsigned shared_dirty = 0;
1329         unsigned shared_clean = 0;
1330         unsigned private_dirty = 0;
1331         unsigned private_clean = 0;
1332         unsigned pss = 0;
1333         unsigned long start = 0;
1334         unsigned long end = 0;
1335         unsigned private_clean_total = 0;
1336         unsigned private_dirty_total = 0;
1337         unsigned shared_clean_total = 0;
1338         unsigned shared_dirty_total = 0;
1339         int duplication = 0;
1340
1341         milist = load_maps(pid);
1342
1343         if (milist == 0) {
1344                 fprintf(stderr, "cannot get /proc/smaps for pid %d\n", pid);
1345                 return 1;
1346         }
1347
1348         if (!sum) {
1349                 if (sizeof(unsigned long) == 4) {
1350                         /* for 32-bit address */
1351                         printf(" S(CODE)  S(DATA)  P(CODE)  P(DATA)      PSS "
1352                                 "ADDR(start-end)   "
1353                                 "OBJECT NAME\n");
1354                         printf("-------- -------- -------- -------- -------- "
1355                                 "----------------- "
1356                                 "------------------------------\n");
1357                 } else {
1358                         /* for 64-bit address */
1359                         printf(" S(CODE)  S(DATA)  P(CODE)  P(DATA)      PSS "
1360                                 "ADDR(start-end)                   "
1361                                 "OBJECT NAME\n");
1362                         printf("-------- -------- -------- -------- -------- "
1363                                 "--------------------------------- "
1364                                 "------------------------------\n");
1365                 }
1366         } else {
1367                 printf(" S(CODE)  S(DATA)  P(CODE)  P(DATA)      PSS\n");
1368                 printf("-------- -------- -------- -------- --------\n");
1369         }
1370         for (mi = milist; mi;) {
1371                 shared_clean += mi->shared_clean;
1372                 shared_dirty += mi->shared_dirty;
1373                 private_clean += mi->private_clean;
1374                 private_dirty += mi->private_dirty;
1375                 pss += mi->pss;
1376
1377                 shared_clean_total += mi->shared_clean;
1378                 shared_dirty_total += mi->shared_dirty;
1379                 private_clean_total += mi->private_clean;
1380                 private_dirty_total += mi->private_dirty;
1381
1382                 if (!duplication)
1383                         start = mi->start;
1384
1385                 if ((mi->next && !strcmp(mi->next->name, mi->name)) &&
1386                     (mi->next->start == mi->end)) {
1387                         duplication = 1;
1388
1389                         temp = mi;
1390                         mi = mi->next;
1391                         free(temp->perm);
1392                         free(temp->name);
1393                         free(temp);
1394                         temp = NULL;
1395                         continue;
1396                 }
1397                 end = mi->end;
1398                 duplication = 0;
1399
1400                 if (!sum) {
1401                         if (sizeof(unsigned long) == 4) {
1402                                 /* for 32-bit address */
1403                                 printf("%8d %8d %8d %8d %8d %08lx-%08lx %s\n",
1404                                         shared_clean, shared_dirty,
1405                                         private_clean, private_dirty, mi->pss,
1406                                         start, end, mi->name);
1407                         } else {
1408                                 /* for 64-bit address */
1409                                 printf("%8d %8d %8d %8d %8d %016lx-%016lx %s\n",
1410                                         shared_clean, shared_dirty,
1411                                         private_clean, private_dirty, mi->pss,
1412                                         start, end, mi->name);
1413                         }
1414                 }
1415                 shared_clean = 0;
1416                 shared_dirty = 0;
1417                 private_clean = 0;
1418                 private_dirty = 0;
1419
1420                 temp = mi;
1421                 mi = mi->next;
1422                 free(temp->perm);
1423                 free(temp->name);
1424                 free(temp);
1425                 temp = NULL;
1426         }
1427         if (sum) {
1428                 printf("%8d %8d %8d %8d %8d\n",
1429                        shared_clean_total,
1430                        shared_dirty_total,
1431                        private_clean_total,
1432                        private_dirty_total,
1433                        pss);
1434         }
1435
1436         return 1;
1437 }
1438
1439 int main(int argc, char *argv[])
1440 {
1441         int usage = 1;
1442         sum = 0;
1443
1444         pid_max = get_pid_max();
1445
1446         if (argc > 1) {
1447                 if (!strncmp(argv[1], "-r", strlen("-r")+1)) {
1448                         if (argc >= 3)
1449                                 show_rss(OUTPUT_FILE, argv[2]);
1450                         else
1451                                 show_rss(OUTPUT_UART, NULL);
1452                         usage = 0;
1453                 } else if (!strncmp(argv[1], "-s", strlen("-s")+1)) {
1454                         sum = 1;
1455                         if (argc == 3 && atoi(argv[2]) > 0) {
1456                                 show_map_new(atoi(argv[2]));
1457                                 usage = 0;
1458                         }
1459                 } else if (!strncmp(argv[1], "-a", strlen("-a")+1)) {
1460                         verbos = 0;
1461                         show_map_all_new(OUTPUT_UART, NULL);
1462                         usage = 0;
1463                 } else if (!strncmp(argv[1], "-v", strlen("-v")+1)) {
1464                         verbos = 1;
1465                         show_map_all_new(OUTPUT_UART, NULL);
1466                         usage = 0;
1467                 } else if (!strncmp(argv[1], "-f", strlen("-f")+1)) {
1468                         if (argc >= 3) {
1469                                 verbos = 1;
1470                                 show_map_all_new(OUTPUT_FILE, argv[2]);
1471                                 usage = 0;
1472                         }
1473                 } else if (argc == 2 && atoi(argv[1]) > 0) {
1474                         show_map_new(atoi(argv[1]));
1475                         usage = 0;
1476                 }
1477         }
1478         if (usage) {
1479                 fprintf(stderr,
1480                         "memps [-a] | [-v] | [-r] | [-s] <pid> | <pid> | [-f] <output file full path>\n"
1481                         "        -s = sum (show only sum of each)\n"
1482                         "        -f = all (show all processes via output file)\n"
1483                         "        -a = all (show all processes)\n"
1484                         "        -r = all (show rss of all processes)\n"
1485                         "        -v = verbose (show all processes in detail)\n");
1486         }
1487
1488         return 0;
1489 }