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