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