1 /* Copyright 2014 Samsung Electronics Co., Ltd All Rights Reserved
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/types.h>
27 #include <linux/limits.h>
34 #include <sys/utsname.h>
36 #define STR_SGX_PATH "/dev/pvrsrvkm"
37 #define STR_3D_PATH1 "/dev/mali"
38 #define STR_3D_PATH2 "/dev/kgsl-3d0"
39 #define STR_3D_UNIFIED_PATH "/usr/bin/gpu_mem_info"
40 #define STR_DRM_PATH1 "/drm mm object (deleted)"
41 #define STR_DRM_PATH2 "/dev/dri/card0"
42 #define MEMCG_PATH "/sys/fs/cgroup/memory"
43 #define ZRAM_USED_PATH "/sys/block/zram0/mem_used_total"
44 #define ZRAM_MM_STAT_PATH "/sys/block/zram0/mm_stat"
45 #define OOM_SCORE_ADJ_STR "oom_score_adj"
46 #define OOM_SCORE_STR "oom_score"
48 #define BUF_MAX (BUFSIZ) /* most optimal for libc::stdio */
49 #define BUF_INC_SIZE (512 * 1024) /* maximal SMAPS I saw 2 MB */
50 #define KB(bytes) ((bytes)/1024)
52 #define BYTE_TO_KBYTE(b) ((b) >> 10)
53 #define BYTE_TO_MBYTE(b) ((b) >> 20)
54 #define BYTE_TO_GBYTE(b) ((b) >> 30)
56 #define KBYTE_TO_BYTE(k) ((k) << 10)
57 #define KBYTE_TO_MBYTE(k) ((k) >> 10)
58 #define KBYTE_TO_GBYTE(k) ((k) >> 20)
60 #define GBYTE_TO_BYTE(g) ((g) << 30)
61 #define GBYTE_TO_KBYTE(g) ((g) << 20)
62 #define GBYTE_TO_MBYTE(g) ((g) << 10)
64 typedef struct geminfo geminfo;
65 typedef struct mapinfo mapinfo;
66 typedef struct trib_mapinfo trib_mapinfo;
82 unsigned shared_clean;
83 unsigned shared_dirty;
84 unsigned private_clean;
85 unsigned private_dirty;
90 /* classify normal, graphic and other devices memory */
92 unsigned shared_clean;
93 unsigned shared_dirty;
94 unsigned private_clean;
95 unsigned private_dirty;
96 unsigned shared_clean_pss;
97 unsigned shared_dirty_pss;
106 unsigned other_devices;
120 static int use_gpu_mem_info = 0;
122 /* reads file contents into memory */
123 static char* cread(const char* path)
125 /* once allocated area for reads */
126 static char* text = NULL;
127 static size_t size = 0;
132 int fd = open(path, O_RDONLY);
138 /* ensure we have enough space */
140 ptr = (char*)realloc(text, size + BUF_INC_SIZE);
149 size += BUF_INC_SIZE;
151 ret = read(fd, ptr, cap);
154 } else if (ret > 0) {
161 return (ret < 0 ? NULL : text);
164 /* like fgets/gets but adjusting contents pointer */
165 static inline char* cgets(char** contents)
167 if (contents && *contents && **contents) {
168 char* bos = *contents; /* begin of string */
169 char* eos = strchr(bos, '\n'); /* end of string */
184 static unsigned get_peak_rss(unsigned int pid)
186 static const char field[] = "VmHWM:";
191 snprintf(tmp, sizeof(tmp), "/proc/%d/status", pid);
194 fprintf(stderr, "cannot open %s\n", tmp);
198 value = strstr(line, field);
200 value += sizeof(field);
201 return strtoul(value, NULL, 10);
206 #define NUM_GEM_FIELD 6
208 static geminfo *read_geminfo(FILE *fp)
212 unsigned int pid, tgid, handle, refcount, hcount;
215 if (fgets(line, BUF_MAX, fp) != NULL) {
216 if (sscanf(line, "%d %d %d %d %d 0x%x",
217 &pid, &tgid, &handle, &refcount,
218 &hcount, &gem_size) != NUM_GEM_FIELD)
223 tgeminfo = malloc(sizeof(geminfo));
224 if (tgeminfo == NULL)
226 tgeminfo->tgid = tgid;
227 tgeminfo->hcount = hcount;
228 tgeminfo->rss_size = KB(gem_size);
229 tgeminfo->pss_size = KB(gem_size/tgeminfo->hcount);
237 static geminfo *find_geminfo(unsigned int tgid, geminfo *gilist)
240 for (gi = gilist; gi; ) {
241 if (gi->tgid == tgid)
249 static geminfo *load_geminfo(void)
252 geminfo *gilist = NULL;
253 geminfo *exist_ginfo = NULL;
258 drm_fp = fopen("/sys/kernel/debug/dri/0/gem_info", "r");
260 if (drm_fp == NULL) {
262 "cannot open /sys/kernel/debug/dri/0/gem_info\n");
266 if (fgets(line, BUF_MAX, drm_fp) == NULL) {
270 /* we should count a number of whitespace separated fields */
271 int in_field = (line[0] && !isblank(line[0]));
272 unsigned int size = (unsigned)in_field;
273 const char* ptr = &line[1];
275 /* sscanf() was used in original code, so number of fields */
276 /* in string is expected to be at least NUM_GEM_FIELD */
277 while (*ptr && size < NUM_GEM_FIELD) {
278 if (isblank(*ptr++)) {
285 /* next field started */
292 if (size != NUM_GEM_FIELD) {
298 while ((ginfo = read_geminfo(drm_fp)) != NULL) {
299 if (gilist && ginfo->tgid == gilist->tgid) {
300 gilist->pss_size += ginfo->pss_size;
301 gilist->rss_size += ginfo->rss_size;
304 } else if (gilist && ((exist_ginfo = find_geminfo(ginfo->tgid, gilist)) != NULL)) {
305 exist_ginfo->pss_size += ginfo->pss_size;
306 exist_ginfo->rss_size += ginfo->rss_size;
310 ginfo->next = gilist;
320 /* b6e82000-b6e83000 rw-p 00020000 b3:19 714 /usr/lib/ld-2.20-2014.11.so : TM1
321 * 7f9389d000-7f9389e000 rw-p 0001f000 b3:12 618 /usr/lib64/ld-2.20-2014.11.so : TM2
322 * 7fae2e4b2000-7fae2e4b3000 r--p 00021000 fe:01 603 /usr/lib64/ld-2.20-2014.11.so : x86-64 Emulator
323 * 01234567890123456789012345678901234567890123456789012345678901234567890123456789
326 mapinfo *read_mapinfo(char** smaps)
333 if ((line = cgets(smaps)) == 0)
340 mi = malloc(sizeof(mapinfo));
344 n = sscanf(line, "%lx-%lx %ms %*s %*s %*s %m[^\n]",
345 &mi->start, &mi->end, &mi->perm, &mi->name);
347 if (n == 3 && !mi->name)
348 mi->name = strndup("[anon]", strlen("[anon]"));
350 fprintf(stderr, "Fail to parse smaps\n");
355 while ((line = cgets(smaps))) {
356 if (sscanf(line, "Size: %d kB", &mi->size) == 1)
358 else if (sscanf(line, "Rss: %d kB", &mi->rss) == 1)
360 else if (sscanf(line, "Pss: %d kB", &mi->pss) == 1)
362 else if (sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) == 1)
364 else if (sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) == 1)
366 else if (sscanf(line, "Private_Clean: %d kB", &mi->private_clean) == 1)
368 else if (sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) == 1)
370 else if (sscanf(line, "Swap: %d kB", &mi->swap) == 1)
373 /* Drain lines until it meets next VMA address */
375 if ((next >= '0' && next <= '9') || (next >= 'a' && next <= 'f'))
383 static unsigned total_gem_memory(void)
386 unsigned total_gem_mem = 0;
387 unsigned name, size, handles, refcount;
390 gem_fp = fopen("/sys/kernel/debug/dri/0/gem_names", "r");
391 if (gem_fp == NULL) {
393 "cannot open /sys/kernel/debug/dri/0/gem_names\n");
397 if (fgets(line, BUF_MAX, gem_fp) == NULL) {
402 while (fgets(line, BUF_MAX, gem_fp) != NULL) {
403 if (sscanf(line, "%d %d %d %d\n",
404 &name, &size, &handles, &refcount) == 4) {
405 if (total_gem_mem <= UINT_MAX - size) {
406 total_gem_mem += size;
412 return total_gem_mem;
415 int get_zram_used(u_int32_t *zram_used)
418 char *fscanf_format = "%u";
421 f = fopen(ZRAM_USED_PATH, "r");
424 * ZRAM_USED_PATH is deprecated on latest kernel, but to support
425 * old kernel first try with that and if fails then use new node
428 f = fopen(ZRAM_MM_STAT_PATH, "r");
430 fprintf(stderr, "Fail to open zram stat file.\n");
433 /* only read 3rd value */
434 fscanf_format = "%*d %*d %d %*d %*d %*d %*d %*d";
437 ret = fscanf(f, fscanf_format, zram_used);
439 fprintf(stderr, "Fail to read file\n");
448 int fread_uint(const char *path, u_int32_t *number)
453 f = fopen(path, "r");
456 fprintf(stderr, "Fail to open %s file.\n", path);
460 ret = fscanf(f, "%u", number);
462 fprintf(stderr, "Fail to read file\n");
471 static int cgroup_read_node(const char *cgroup_name,
472 const char *file_name, unsigned int *value)
474 char buf[PATH_MAX + NAME_MAX];
476 snprintf(buf, sizeof(buf), "%s%s", cgroup_name, file_name);
477 ret = fread_uint(buf, value);
482 * @desc Provides usage in bytes for provided memory cgroup. Works
483 * with/without swap accounting.
485 * @param memcg_path[in] Full path to memory cgroup
486 * @param swap[in] Boolean value for deciding if account usage with swap
487 * @return current cgroup usage in bytes or 0 on error
489 static unsigned int get_memcg_usage(const char *memcg_path, bool swap)
495 ret = cgroup_read_node(memcg_path,
496 "/memory.memsw.usage_in_bytes", &usage);
498 ret = cgroup_read_node(memcg_path, "/memory.usage_in_bytes",
508 static void get_memcg_info(FILE *output_fp)
512 struct dirent *entry;
513 struct stat path_stat;
515 unsigned long usage, usage_with_swap;
517 fprintf(output_fp, "====================================================================\n");
518 fprintf(output_fp, "MEMORY CGROUPS USAGE INFO\n");
520 pdir = opendir(MEMCG_PATH);
522 fprintf(stderr, "cannot read directory %s", MEMCG_PATH);
527 while ((entry = readdir(pdir)) != NULL && !errno) {
528 snprintf(buf, sizeof(buf), "%s/%s", MEMCG_PATH, entry->d_name);
529 /* If can't stat then ignore */
530 if (stat(buf, &path_stat) != 0)
533 /* If it's not directory or it's parent path then ignore */
534 if (!(S_ISDIR(path_stat.st_mode) &&
535 strncmp(entry->d_name, "..", 3)))
538 usage = get_memcg_usage(buf, false);
539 usage_with_swap = get_memcg_usage(buf, true);
540 /* It is posible by rounding errors to get negative value */
541 usage_swap = usage_with_swap - usage;
545 /* Case of root cgroup in hierarchy */
546 if (!strncmp(entry->d_name, ".", 2))
547 fprintf(output_fp, "%13s Mem %3ld MB (%6ld kB), Mem+Swap %3ld MB (%6ld kB), Swap %3ld MB (%6ld kB) \n\n",
548 MEMCG_PATH, BYTE_TO_MBYTE(usage),
549 BYTE_TO_KBYTE(usage),
550 BYTE_TO_MBYTE(usage_with_swap),
551 BYTE_TO_KBYTE(usage_with_swap),
552 BYTE_TO_MBYTE(usage_swap),
553 BYTE_TO_KBYTE(usage_swap));
555 fprintf(output_fp, "memcg: %13s Mem %3ld MB (%6ld kB), Mem+Swap %3ld MB (%6ld kB), Swap %3ld MB (%6ld kB)\n",
556 entry->d_name, BYTE_TO_MBYTE(usage),
557 BYTE_TO_KBYTE(usage),
558 BYTE_TO_MBYTE(usage_with_swap),
559 BYTE_TO_KBYTE(usage_with_swap),
560 BYTE_TO_MBYTE(usage_swap),
561 BYTE_TO_KBYTE(usage_swap));
568 static void get_mem_info(FILE *output_fp)
573 unsigned int free = 0, cached = 0;
574 unsigned int total_mem = 0, available = 0, used;
575 unsigned int swap_total = 0, swap_free = 0, zram_used, swap_used;
576 unsigned int used_ratio;
578 if (output_fp == NULL)
581 fp = fopen("/proc/meminfo", "r");
584 fprintf(stderr, "/proc/meminfo open failed, %p", fp);
588 while (fgets(buf, PATH_MAX, fp) != NULL) {
589 if ((idx = strstr(buf, "MemTotal:"))) {
590 idx += strlen("Memtotal:");
591 while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
593 total_mem = atoi(idx);
594 } else if ((idx = strstr(buf, "MemFree:"))) {
595 idx += strlen("MemFree:");
596 while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
599 } else if ((idx = strstr(buf, "MemAvailable:"))) {
600 idx += strlen("MemAvailable:");
601 while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
603 available = atoi(idx);
604 } else if ((idx = strstr(buf, "Cached:")) && !strstr(buf, "Swap")) {
605 idx += strlen("Cached:");
606 while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
609 } else if ((idx = strstr(buf, "SwapTotal:"))) {
610 idx += strlen("SwapTotal:");
611 while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
613 swap_total = atoi(idx);
614 } else if ((idx = strstr(buf, "SwapFree:"))) {
615 idx += strlen("SwapFree");
616 while ((idx < buf + PATH_MAX) && (*idx < '0' || *idx > '9'))
618 swap_free = atoi(idx);
623 if (total_mem == 0) {
624 fprintf(stderr, "cannot get total memory size\n");
630 available = free + cached;
631 used = total_mem - available;
632 used_ratio = used * 100 / total_mem;
633 swap_used = swap_total - swap_free;
635 if (get_zram_used(&zram_used) < 0)
639 "====================================================================\n");
642 fprintf(output_fp, "Total RAM size: \t%15d MB( %6d kB)\n",
643 total_mem >> 10, total_mem);
645 fprintf(output_fp, "Used (Mem+Reclaimable): %15d MB( %6d kB)\n",
646 (total_mem - free) >> 10, total_mem - free);
648 fprintf(output_fp, "Used (Mem+Swap): \t%15d MB( %6d kB)\n",
651 fprintf(output_fp, "Used (Mem): \t\t%15d MB( %6d kB)\n",
654 fprintf(output_fp, "Used (Swap): \t\t%15d MB( %6d kB)\n",
655 swap_used >> 10, swap_used);
657 fprintf(output_fp, "Used (Zram block device): %13d MB( %6d kB)\n",
658 BYTE_TO_MBYTE(zram_used), BYTE_TO_KBYTE(zram_used));
660 fprintf(output_fp, "Used Ratio: \t\t%15d %%\n", used_ratio);
662 fprintf(output_fp, "Mem Free:\t\t%15d MB( %6d kB)\n",
665 fprintf(output_fp, "Available (Free+Reclaimable):%10d MB( %6d kB)\n",
671 static int get_tmpfs_info(FILE *output_fp)
675 char *tmpfs_mp; /* tmpfs mount point */
676 struct statfs tmpfs_info;
678 if (output_fp == NULL)
681 fp = fopen("/etc/mtab", "r");
686 "====================================================================\n");
687 fprintf(output_fp, "TMPFS INFO\n");
689 while (fgets(line, BUF_MAX, fp) != NULL) {
690 if (sscanf(line, "tmpfs %ms tmpfs", &tmpfs_mp) == 1) {
691 if (statfs(tmpfs_mp, &tmpfs_info) == 0) {
693 #ifndef __USE_FILE_OFFSET64
694 "tmpfs %16s Total %8ld KB, Used %8ld, Avail %8ld\n",
696 "tmpfs %16s Total %8lld KB, Used %8lld, Avail %8lld\n",
699 /* 1 block is 4 KB */
700 tmpfs_info.f_blocks * 4,
701 (tmpfs_info.f_blocks - tmpfs_info.f_bfree) * 4,
702 tmpfs_info.f_bfree * 4);
712 mapinfo *load_maps(int pid)
719 snprintf(tmp, sizeof(tmp), "/proc/%d/smaps", pid);
724 while ((mi = read_mapinfo(&smaps)) != 0) {
726 if ((!strcmp(mi->name, milist->name)
727 && (mi->name[0] != '['))) {
728 milist->size += mi->size;
729 milist->swap += mi->swap;
730 milist->rss += mi->rss;
731 milist->pss += mi->pss;
732 milist->shared_clean += mi->shared_clean;
733 milist->shared_dirty += mi->shared_dirty;
734 milist->private_clean += mi->private_clean;
735 milist->private_dirty += mi->private_dirty;
737 milist->end = mi->end;
738 strncpy(milist->perm, mi->perm, 4);
752 static void init_trib_mapinfo(trib_mapinfo *tmi)
756 tmi->shared_clean = 0;
757 tmi->shared_dirty = 0;
758 tmi->private_clean = 0;
759 tmi->private_dirty = 0;
761 tmi->shared_clean_pss = 0;
762 tmi->shared_dirty_pss = 0;
770 tmi->other_devices = 0;
774 unsigned int get_graphic_3d_meminfo(unsigned int tgid)
776 char command[256], buf[256];
778 unsigned int size = 0;
782 snprintf(command, sizeof(command), "%s %d", STR_3D_UNIFIED_PATH, tgid);
783 p_gpu = popen(command, "r");
785 if (fgets(buf, 256, p_gpu)) {
786 ret = sscanf(buf, "%d %ms %d %ms", &tid, &tmp[0], &size, &tmp[1]);
798 get_trib_mapinfo(unsigned int tgid, mapinfo *milist,
799 geminfo *gilist, trib_mapinfo *result)
803 mapinfo *temp = NULL;
809 init_trib_mapinfo(result);
811 if (use_gpu_mem_info)
812 result->graphic_3d = get_graphic_3d_meminfo(tgid);
814 for (mi = milist; mi;) {
815 if (!use_gpu_mem_info && strstr(mi->name, STR_SGX_PATH)) {
816 result->graphic_3d += mi->pss;
817 } else if (!use_gpu_mem_info && (strstr(mi->name, STR_3D_PATH1) ||
818 strstr(mi->name, STR_3D_PATH2))) {
819 result->graphic_3d += mi->size;
820 } else if (mi->rss != 0 && mi->pss == 0
821 && mi->shared_clean == 0
822 && mi->shared_dirty == 0
823 && mi->private_clean == 0
824 && mi->private_dirty == 0
826 result->other_devices += mi->size;
827 } else if (!strncmp(mi->name, STR_DRM_PATH1,
828 sizeof(STR_DRM_PATH1)) ||
829 !strncmp(mi->name, STR_DRM_PATH2,
830 sizeof(STR_DRM_PATH2))) {
831 result->gem_mmap += mi->rss;
833 result->shared_clean += mi->shared_clean;
834 result->shared_dirty += mi->shared_dirty;
835 result->private_clean += mi->private_clean;
836 result->private_dirty += mi->private_dirty;
837 result->swap += mi->swap;
838 result->rss += mi->rss;
839 result->pss += mi->pss;
840 result->size += mi->size;
842 if (mi->shared_clean != 0)
843 result->shared_clean_pss += mi->pss;
844 else if (mi->shared_dirty != 0)
845 result->shared_dirty_pss += mi->pss;
856 result->peak_rss = get_peak_rss(tgid);
857 if (result->peak_rss < result->rss)
858 result->peak_rss = result->rss;
859 if (result->gem_mmap > 0)
860 result->peak_rss -= result->gem_mmap;
862 gi = find_geminfo(tgid, gilist);
864 result->gem_rss = gi->rss_size;
865 result->gem_pss = gi->pss_size;
871 static int get_cmdline(unsigned int pid, char *cmdline)
874 char buf[NAME_MAX] = {0, };
877 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
878 fp = fopen(buf, "r");
882 fprintf(stderr, "cannot file open %s\n", buf);
885 if ((ret = fscanf(fp, "%4095s", cmdline)) < 1) {
894 static int get_oomscoreadj(unsigned int pid, const char *oom_string)
900 snprintf(tmp, sizeof(tmp), "/proc/%d/%s", pid, oom_string);
901 fp = fopen(tmp, "r");
907 if (fgets(tmp, sizeof(tmp), fp) == NULL) {
913 oomadj_val = atoi(tmp);
919 static void get_rss(pid_t pid, unsigned long *result)
922 char proc_path[PATH_MAX];
923 unsigned long rss = 0;
927 snprintf(proc_path, sizeof(proc_path), "/proc/%d/statm", pid);
928 fp = fopen(proc_path, "r");
932 if (fscanf(fp, "%*s %ld", &rss) < 1) {
939 /* convert page to Kb */
944 static const char* get_readable_oom_path(void)
949 snprintf(tmp, sizeof(tmp), "/proc/1/%s", OOM_SCORE_ADJ_STR);
950 fp = fopen(tmp, "r");
953 return OOM_SCORE_ADJ_STR;
955 snprintf(tmp, sizeof(tmp), "/proc/1/%s", OOM_SCORE_STR);
956 fp = fopen(tmp, "r");
959 return OOM_SCORE_STR;
964 static void show_rss(int output_type, char *output_path)
967 struct dirent *curdir;
969 char cmdline[PATH_MAX];
970 FILE *output_file = NULL;
973 const char *oom_path = NULL;
975 oom_path = get_readable_oom_path();
977 fprintf(stderr, "there is no readable oom path\n");
981 pDir = opendir("/proc");
983 fprintf(stderr, "cannot read directory /proc.\n");
987 if (output_type == OUTPUT_FILE && output_path) {
988 output_file = fopen(output_path, "w+");
990 fprintf(stderr, "cannot open output file(%s)\n",
996 output_file = stdout;
1000 " PID RSS %14s COMMAND\n", oom_path);
1003 while ((curdir = readdir(pDir)) != NULL && !errno) {
1004 pid = atoi(curdir->d_name);
1005 if (pid < 1 || pid > 32768 || pid == getpid())
1008 if (get_cmdline(pid, cmdline) < 0)
1011 oom_score_adj = get_oomscoreadj(pid, oom_path);
1013 fprintf(output_file,
1014 "%8d %8lu %8d %s\n",
1021 } /* end of while */
1023 get_tmpfs_info(output_file);
1024 get_mem_info(output_file);
1026 fclose(output_file);
1032 static int show_map_all_new(int output_type, char *output_path)
1035 struct dirent *curdir;
1039 unsigned total_pss = 0;
1040 unsigned total_private = 0;
1041 unsigned total_private_code = 0;
1042 unsigned total_private_data = 0;
1043 unsigned total_shared_code = 0;
1044 unsigned total_shared_data = 0;
1045 unsigned total_shared_code_pss = 0;
1046 unsigned total_shared_data_pss = 0;
1047 unsigned total_swap = 0;
1048 unsigned total_rss = 0;
1049 unsigned total_graphic_3d = 0;
1050 unsigned total_gem_rss = 0;
1051 unsigned total_gem_pss = 0;
1052 unsigned total_peak_rss = 0;
1053 unsigned total_allocated_gem = 0;
1055 char cmdline[PATH_MAX];
1056 FILE *output_file = NULL;
1058 const char *oom_path = NULL;
1060 oom_path = get_readable_oom_path();
1062 fprintf(stderr, "there is no readable oom path\n");
1066 use_gpu_mem_info = (!access(STR_3D_UNIFIED_PATH, F_OK | X_OK)) ? 1 : 0;
1069 pDir = opendir("/proc");
1071 fprintf(stderr, "cannot read directory /proc.\n");
1075 if (output_type == OUTPUT_FILE && output_path) {
1076 output_file = fopen(output_path, "w+");
1078 fprintf(stderr, "cannot open output file(%s)\n",
1084 output_file = stdout;
1086 glist = load_geminfo();
1090 fprintf(output_file,
1091 " PID S(CODE) S(DATA) P(CODE) P(DATA) "
1092 " PEAK PSS 3D GEM(PSS) GEM(RSS) "
1093 " SWAP %14s COMMAND\n", oom_path);
1095 fprintf(output_file,
1096 " PID CODE DATA PEAK PSS "
1097 " 3D GEM(PSS) SWAP COMMAND\n");
1101 while ((curdir = readdir(pDir)) != NULL && !errno) {
1102 pid = atoi(curdir->d_name);
1103 if (pid < 1 || pid > 32768 || pid == getpid())
1106 if (get_cmdline(pid, cmdline) < 0)
1109 milist = load_maps(pid);
1113 /* get classified map info */
1114 get_trib_mapinfo(pid, milist, glist, &tmi);
1115 oom_score_adj = get_oomscoreadj(pid, oom_path);
1119 fprintf(output_file,
1120 "%8d %8d %8d %8d %8d "
1121 "%8d %8d %8d %8d %8d "
1137 fprintf(output_file,
1138 "%8d %8d %8d %8d %8d "
1141 tmi.shared_clean + tmi.private_clean,
1142 tmi.shared_dirty + tmi.private_dirty,
1150 if (tmi.other_devices != 0)
1151 fprintf(output_file,
1152 "%s(%d) %d KB may mapped by device(s).\n",
1153 cmdline, pid, tmi.other_devices);
1156 total_private += (tmi.private_clean + tmi.private_dirty);
1157 total_pss += tmi.pss;
1158 total_rss += tmi.rss;
1159 total_graphic_3d += tmi.graphic_3d;
1160 total_gem_rss += tmi.gem_rss;
1161 total_gem_pss += tmi.gem_pss;
1162 total_private_code += tmi.private_clean;
1163 total_private_data += tmi.private_dirty;
1164 total_swap += tmi.swap;
1165 total_shared_code += tmi.shared_clean;
1166 total_shared_data += tmi.shared_dirty;
1167 total_peak_rss += tmi.peak_rss;
1169 total_shared_code_pss += tmi.shared_clean_pss;
1170 total_shared_data_pss += tmi.shared_dirty_pss;
1172 } /* end of while */
1174 total_allocated_gem = KB(total_gem_memory());
1175 fprintf(output_file,
1176 "==============================================="
1177 "===============================================\n");
1179 fprintf(output_file,
1180 "TOTAL: S(CODE) S(DATA) P(CODE) P(DATA) "
1181 " PEAK PSS 3D GEM(PSS) GEM(RSS) "
1182 "GEM(ALLOC) SWAP TOTAL(KB)\n");
1183 fprintf(output_file,
1185 "%8d %8d %8d %8d %8d "
1187 total_shared_code, total_shared_data,
1188 total_private_code, total_private_data,
1189 total_peak_rss, total_pss, total_graphic_3d,
1190 total_gem_pss, total_gem_rss,
1191 total_allocated_gem, total_swap,
1192 total_pss + total_graphic_3d +
1193 total_allocated_gem);
1195 fprintf(output_file,
1196 "TOTAL: CODE DATA PEAK PSS "
1197 " 3D GEM(PSS) GEM(ALLOC) SWAP TOTAL(KB)\n");
1198 fprintf(output_file,
1200 "%8d %8d %10d %8d %10d\n",
1201 total_shared_code + total_private_code,
1202 total_shared_data + total_private_data,
1203 total_peak_rss, total_pss,
1204 total_graphic_3d, total_gem_pss,
1205 total_allocated_gem, total_swap,
1206 total_pss + total_graphic_3d +
1207 total_allocated_gem);
1212 fprintf(output_file,
1213 "* S(CODE): shared clean memory, it includes"
1214 " duplicated memory\n"
1215 "* S(DATA): shared dirty memory, it includes"
1216 " duplicated memory\n"
1217 "* P(CODE): private clean memory\n"
1218 "* P(DATA): private dirty memory\n"
1219 "* PEAK: peak memory usage of S(CODE) + S(DATA)"
1220 " + P(CODE) + P(DATA)\n"
1221 "* PSS: Proportional Set Size\n"
1222 "* 3D: memory allocated by GPU driver\n"
1223 "* GEM(PSS): GEM memory divided by # of sharers\n"
1224 "* GEM(RSS): GEM memory including duplicated memory\n"
1225 "* GEM(ALLOC): sum of unique gem memory in the system\n"
1226 "* TOTAL: PSS + 3D + GEM(ALLOC)\n");
1228 fprintf(output_file,
1229 "* CODE: shared and private clean memory\n"
1230 "* DATA: shared and private dirty memory\n"
1231 "* PEAK: peak memory usage of CODE + DATA\n"
1232 "* PSS: Proportional Set Size\n"
1233 "* 3D: memory allocated by GPU driver\n"
1234 "* GEM(PSS): GEM memory divided by # of sharers\n"
1235 "* GEM(ALLOC): sum of unique GEM memory in the system\n"
1236 "* TOTAL: PSS + 3D + GEM(ALLOC)\n");
1238 get_tmpfs_info(output_file);
1239 get_memcg_info(output_file);
1240 get_mem_info(output_file);
1242 fclose(output_file);
1249 static int show_map_new(int pid)
1253 mapinfo *temp = NULL;
1254 unsigned shared_dirty = 0;
1255 unsigned shared_clean = 0;
1256 unsigned private_dirty = 0;
1257 unsigned private_clean = 0;
1259 unsigned long start = 0;
1260 unsigned long end = 0;
1261 unsigned private_clean_total = 0;
1262 unsigned private_dirty_total = 0;
1263 unsigned shared_clean_total = 0;
1264 unsigned shared_dirty_total = 0;
1265 int duplication = 0;
1267 milist = load_maps(pid);
1270 fprintf(stderr, "cannot get /proc/smaps for pid %d\n", pid);
1275 printf(" S(CODE) S(DATA) P(CODE) P(DATA) PSS "
1276 "ADDR(start-end) OBJECT NAME\n");
1277 printf("-------- -------- -------- -------- -------- "
1278 "----------------- ------------------------------\n");
1280 printf(" S(CODE) S(DATA) P(CODE) P(DATA) "
1282 printf("-------- -------- -------- -------- "
1283 "------------------\n");
1285 for (mi = milist; mi;) {
1286 shared_clean += mi->shared_clean;
1287 shared_dirty += mi->shared_dirty;
1288 private_clean += mi->private_clean;
1289 private_dirty += mi->private_dirty;
1292 shared_clean_total += mi->shared_clean;
1293 shared_dirty_total += mi->shared_dirty;
1294 private_clean_total += mi->private_clean;
1295 private_dirty_total += mi->private_dirty;
1300 if ((mi->next && !strcmp(mi->next->name, mi->name)) &&
1301 (mi->next->start == mi->end)) {
1316 printf("%8d %8d %8d %8d %8d %08lx-%08lx %s\n",
1317 shared_clean, shared_dirty, private_clean,
1318 private_dirty, mi->pss, start, end, mi->name);
1333 printf("%8d %8d %8d %8d %18d\n",
1336 private_clean_total,
1337 private_dirty_total,
1344 int main(int argc, char *argv[])
1350 if (!strncmp(argv[1], "-r", strlen("-r")+1)) {
1352 show_rss(OUTPUT_FILE, argv[2]);
1354 show_rss(OUTPUT_UART, NULL);
1356 } else if (!strncmp(argv[1], "-s", strlen("-s")+1)) {
1358 if (argc == 3 && atoi(argv[2]) > 0) {
1359 show_map_new(atoi(argv[2]));
1362 } else if (!strncmp(argv[1], "-a", strlen("-a")+1)) {
1364 show_map_all_new(OUTPUT_UART, NULL);
1366 } else if (!strncmp(argv[1], "-v", strlen("-v")+1)) {
1368 show_map_all_new(OUTPUT_UART, NULL);
1370 } else if (!strncmp(argv[1], "-f", strlen("-f")+1)) {
1373 show_map_all_new(OUTPUT_FILE, argv[2]);
1376 } else if (argc == 2 && atoi(argv[1]) > 0) {
1377 show_map_new(atoi(argv[1]));
1383 "memps [-a] | [-v] | [-r] | [-s] <pid> | <pid> | [-f] <output file full path>\n"
1384 " -s = sum (show only sum of each)\n"
1385 " -f = all (show all processes via output file)\n"
1386 " -a = all (show all processes)\n"
1387 " -r = all (show rss of all processes)\n"
1388 " -v = verbos (show all processes in detail)\n");