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