2 Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License
22 #include <sys/types.h>
24 #include <linux/limits.h>
30 #include <sys/utsname.h>
32 #define STR_SGX_PATH "/dev/pvrsrvkm"
33 #define STR_3D_PATH1 "/dev/mali"
34 #define STR_3D_PATH2 "/dev/kgsl-3d0"
35 #define STR_DRM_PATH1 "/drm mm object (deleted)"
36 #define STR_DRM_PATH2 "/dev/dri/card0"
38 #define BUF_MAX (BUFSIZ) /* most optimal for libc::stdio */
39 #define BUF_INC_SIZE (512 * 1024) /* maximal SMAPS I saw 2 MB */
40 #define KB(bytes) ((bytes)/1024)
42 typedef struct geminfo geminfo;
43 typedef struct mapinfo mapinfo;
44 typedef struct trib_mapinfo trib_mapinfo;
59 unsigned shared_clean;
60 unsigned shared_dirty;
61 unsigned private_clean;
62 unsigned private_dirty;
67 /* classify normal, graphic and other devices memory */
69 unsigned shared_clean;
70 unsigned shared_dirty;
71 unsigned private_clean;
72 unsigned private_dirty;
73 unsigned shared_clean_pss;
74 unsigned shared_dirty_pss;
82 unsigned other_devices;
94 static int ignore_smaps_field;
98 /* reads file contents into memory */
99 static char* cread(const char* path)
101 /* once allocated area for reads */
102 static char* text = NULL;
103 static size_t size = 0;
108 int fd = open(path, O_RDONLY);
115 /* ensure we have enough space */
117 ptr = (char*)realloc(text, size + BUF_INC_SIZE);
126 size += BUF_INC_SIZE;
128 ret = read(fd, ptr, cap);
131 } else if (ret > 0) {
138 return (ret < 0 ? NULL : text);
141 /* like fgets/gets but adjusting contents pointer */
142 static inline char* cgets(char** contents)
144 if (contents && *contents && **contents) {
145 char* bos = *contents; /* begin of string */
146 char* eos = strchr(bos, '\n'); /* end of string */
161 static unsigned get_peak_rss(unsigned int pid)
163 static const char field[] = "VmHWM:";
168 sprintf(tmp, "/proc/%d/status", pid);
171 fprintf(stderr, "cannot open %s\n", tmp);
175 value = strstr(line, field);
177 value += sizeof(field);
178 return strtoul(value, NULL, 10);
183 #define NUM_GEM_FIELD 6
185 static geminfo *read_geminfo(FILE *fp)
189 unsigned int pid, tgid, handle, refcount, hcount;
192 if (fgets(line, BUF_MAX, fp) != NULL) {
193 if (sscanf(line, "%d %d %d %d %d 0x%x",
194 &pid, &tgid, &handle, &refcount,
195 &hcount, &gem_size) != NUM_GEM_FIELD)
198 tgeminfo = malloc(sizeof(geminfo));
199 if (tgeminfo == NULL)
201 tgeminfo->tgid = tgid;
202 tgeminfo->hcount = hcount;
203 tgeminfo->rss_size = KB(gem_size);
204 tgeminfo->pss_size = KB(gem_size/tgeminfo->hcount);
212 static geminfo *load_geminfo(void)
215 geminfo *gilist = NULL;
219 drm_fp = fopen("/sys/kernel/debug/dri/0/gem_info", "r");
221 if (drm_fp == NULL) {
223 "cannot open /sys/kernel/debug/dri/0/gem_info\n");
227 if (fgets(line, BUF_MAX, drm_fp) == NULL) {
231 /* we should count a number of whitespace separated fields */
232 int in_field = (line[0] && !isblank(line[0]));
233 unsigned int size = (unsigned)in_field;
234 const char* ptr = &line[1];
236 /* sscanf() was used in original code, so number of fields */
237 /* in string is expected to be at least NUM_GEM_FIELD */
238 while (*ptr && size < NUM_GEM_FIELD) {
239 if (isblank(*ptr++)) {
246 /* next field started */
253 if (size != NUM_GEM_FIELD) {
259 while ((ginfo = read_geminfo(drm_fp)) != NULL) {
260 if (gilist && ginfo->tgid == gilist->tgid) {
261 gilist->pss_size += ginfo->pss_size;
262 gilist->rss_size += ginfo->rss_size;
266 ginfo->next = gilist;
276 /* 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /android/lib/libcomposer.so
277 * 012345678901234567890123456789012345678901234567890123456789
281 mapinfo *read_mapinfo(char** smaps, int rest_line)
288 if ((line = cgets(smaps)) == 0)
295 mi = malloc(sizeof(mapinfo) + len + 16);
299 mi->start = strtoul(line, 0, 16);
300 mi->end = strtoul(line + 9, 0, 16);
302 mi->perm[0] = line[18]; /* read */
303 mi->perm[1] = line[19]; /* write */
304 mi->perm[2] = line[20]; /* execute */
305 mi->perm[3] = line[21]; /* may share or private */
308 strcpy(mi->name, "[anon]");
310 strcpy(mi->name, line + 49);
312 if ((line = cgets(smaps)) == 0)
314 if (sscanf(line, "Size: %d kB", &mi->size) != 1)
316 if ((line = cgets(smaps)) == 0)
318 if (sscanf(line, "Rss: %d kB", &mi->rss) != 1)
320 if ((line = cgets(smaps)) == 0)
322 if (sscanf(line, "Pss: %d kB", &mi->pss) == 1)
323 if ((line = cgets(smaps)) == 0)
325 if (sscanf(line, "Shared_Clean: %d kB", &mi->shared_clean) != 1)
327 if ((line = cgets(smaps)) == 0)
329 if (sscanf(line, "Shared_Dirty: %d kB", &mi->shared_dirty) != 1)
331 if ((line = cgets(smaps)) == 0)
333 if (sscanf(line, "Private_Clean: %d kB", &mi->private_clean) != 1)
335 if ((line = cgets(smaps)) == 0)
337 if (sscanf(line, "Private_Dirty: %d kB", &mi->private_dirty) != 1)
340 while (rest_line-- && (line = cgets(smaps))) {
341 if (sscanf(line, "PSwap: %d kB", &tmp) == 1)
347 printf("mi get error\n");
352 static unsigned total_gem_memory(void)
355 unsigned total_gem_mem = 0;
356 unsigned name, size, handles, refcount;
359 gem_fp = fopen("/proc/dri/0/gem_names", "r");
362 "cannot open /proc/dir/0/gem_names\n");
366 if (fgets(line, BUF_MAX, gem_fp) == NULL) {
371 while (fgets(line, BUF_MAX, gem_fp) != NULL)
372 if (sscanf(line, "%d %d %d %d\n",
373 &name, &size, &handles, &refcount) == 4)
374 total_gem_mem += size;
377 return total_gem_mem;
380 static void get_mem_info(FILE *output_fp)
385 unsigned int free = 0, cached = 0;
386 unsigned int total_mem = 0, available = 0, used;
387 unsigned int swap_total = 0, swap_free = 0, swap_used;
388 unsigned int used_ratio;
390 if (output_fp == NULL)
393 fp = fopen("/proc/meminfo", "r");
396 fprintf(stderr, "%s open failed, %p", buf, fp);
400 while (fgets(buf, PATH_MAX, fp) != NULL) {
401 if ((idx = strstr(buf, "MemTotal:"))) {
402 idx += strlen("Memtotal:");
403 while (*idx < '0' || *idx > '9')
405 total_mem = atoi(idx);
406 } else if ((idx = strstr(buf, "MemFree:"))) {
407 idx += strlen("MemFree:");
408 while (*idx < '0' || *idx > '9')
411 } else if ((idx = strstr(buf, "MemAvailable:"))) {
412 idx += strlen("MemAvailable:");
413 while (*idx < '0' || *idx > '9')
415 available = atoi(idx);
416 } else if((idx = strstr(buf, "Cached:")) && !strstr(buf, "Swap")) {
417 idx += strlen("Cached:");
418 while (*idx < '0' || *idx > '9')
421 } else if((idx = strstr(buf, "SwapTotal:"))) {
422 idx += strlen("SwapTotal:");
423 while (*idx < '0' || *idx > '9')
425 swap_total = atoi(idx);
426 } else if((idx = strstr(buf, "SwapFree:"))) {
427 idx += strlen("SwapFree");
428 while (*idx < '0' || *idx > '9')
430 swap_free = atoi(idx);
436 available = free + cached;
437 used = total_mem - available;
438 used_ratio = used * 100 / total_mem;
439 swap_used = swap_total - swap_free;
442 "====================================================================\n");
445 fprintf(output_fp, "Total RAM size: \t%15d MB( %6d kB)\n",
446 total_mem >> 10, total_mem);
448 fprintf(output_fp, "Used (Mem+Reclaimable): %15d MB( %6d kB)\n",
449 (total_mem - free) >> 10, total_mem - free);
451 fprintf(output_fp, "Used (Mem+Swap): \t%15d MB( %6d kB)\n",
454 fprintf(output_fp, "Used (Mem): \t\t%15d MB( %6d kB)\n",
457 fprintf(output_fp, "Used (Swap): \t\t%15d MB( %6d kB)\n",
458 swap_used >> 10, swap_used);
460 fprintf(output_fp, "Used Ratio: \t\t%15d %%\n", used_ratio);
462 fprintf(output_fp, "Mem Free:\t\t%15d MB( %6d kB)\n",
465 fprintf(output_fp, "Available (Free+Reclaimable):%10d MB( %6d kB)\n",
471 static int get_tmpfs_info(FILE *output_fp)
475 char tmpfs_mp[NAME_MAX]; /* tmpfs mount point */
476 struct statfs tmpfs_info;
478 if (output_fp == NULL)
481 fp = fopen("/etc/mtab", "r");
486 "====================================================================\n");
487 fprintf(output_fp, "TMPFS INFO\n");
489 while (fgets(line, BUF_MAX, fp) != NULL) {
490 if (sscanf(line, "tmpfs %s tmpfs", tmpfs_mp) == 1) {
491 statfs(tmpfs_mp, &tmpfs_info);
493 "tmpfs %16s Total %8ld KB, Used %8ld, Avail %8ld\n",
495 /* 1 block is 4 KB */
496 tmpfs_info.f_blocks * 4,
497 (tmpfs_info.f_blocks - tmpfs_info.f_bfree) * 4,
498 tmpfs_info.f_bfree * 4);
505 mapinfo *load_maps(int pid)
512 sprintf(tmp, "/proc/%d/smaps", pid);
517 while ((mi = read_mapinfo(&smaps, ignore_smaps_field)) != 0) {
519 if ((!strcmp(mi->name, milist->name)
520 && (mi->name[0] != '['))) {
521 milist->size += mi->size;
522 milist->rss += mi->rss;
523 milist->pss += mi->pss;
524 milist->shared_clean += mi->shared_clean;
525 milist->shared_dirty += mi->shared_dirty;
526 milist->private_clean += mi->private_clean;
527 milist->private_dirty += mi->private_dirty;
529 milist->perm[0] = mi->perm[0];
530 milist->perm[1] = mi->perm[1];
531 milist->perm[2] = mi->perm[2];
532 milist->perm[3] = mi->perm[3];
533 milist->end = mi->end;
534 strncpy(milist->perm, mi->perm, 4);
546 static geminfo *find_geminfo(unsigned int tgid, geminfo *gilist)
549 for (gi = gilist; gi; ) {
550 if (gi->tgid == tgid)
558 static void init_trib_mapinfo(trib_mapinfo *tmi)
562 tmi->shared_clean = 0;
563 tmi->shared_dirty = 0;
564 tmi->private_clean = 0;
565 tmi->private_dirty = 0;
566 tmi->shared_clean_pss = 0;
567 tmi->shared_dirty_pss = 0;
575 tmi->other_devices = 0;
580 get_trib_mapinfo(unsigned int tgid, mapinfo *milist,
581 geminfo *gilist, trib_mapinfo *result)
585 mapinfo *temp = NULL;
591 init_trib_mapinfo(result);
592 for (mi = milist; mi;) {
593 if (strstr(mi->name, STR_SGX_PATH)) {
594 result->graphic_3d += mi->pss;
595 } else if (strstr(mi->name, STR_3D_PATH1) ||
596 strstr(mi->name, STR_3D_PATH2)) {
597 result->graphic_3d += mi->size;
598 } else if (mi->rss != 0 && mi->pss == 0
599 && mi->shared_clean == 0
600 && mi->shared_dirty == 0
601 && mi->private_clean == 0
602 && mi->private_dirty == 0) {
603 result->other_devices += mi->size;
604 } else if (!strncmp(mi->name, STR_DRM_PATH1,
605 sizeof(STR_DRM_PATH1)) ||
606 !strncmp(mi->name, STR_DRM_PATH2,
607 sizeof(STR_DRM_PATH2))) {
608 result->gem_mmap += mi->rss;
610 result->shared_clean += mi->shared_clean;
611 result->shared_dirty += mi->shared_dirty;
612 result->private_clean += mi->private_clean;
613 result->private_dirty += mi->private_dirty;
614 result->rss += mi->rss;
615 result->pss += mi->pss;
616 result->size += mi->size;
618 if(mi->shared_clean != 0)
619 result->shared_clean_pss += mi->pss;
620 else if (mi->shared_dirty != 0)
621 result->shared_dirty_pss += mi->pss;
630 result->peak_rss = get_peak_rss(tgid);
631 if (result->peak_rss < result->rss)
632 result->peak_rss = result->rss;
633 if (result->gem_mmap > 0)
634 result->peak_rss -= result->gem_mmap;
636 gi = find_geminfo(tgid, gilist);
638 result->gem_rss = gi->rss_size;
639 result->gem_pss = gi->pss_size;
645 static int get_cmdline(unsigned int pid, char *cmdline)
648 char buf[NAME_MAX] = {0, };
651 sprintf(buf, "/proc/%d/cmdline", pid);
652 fp = fopen(buf, "r");
654 fprintf(stderr, "cannot file open %s\n", buf);
657 if ((ret = fscanf(fp, "%s", cmdline)) < 1) {
666 static int get_oomscoreadj(unsigned int pid)
672 sprintf(tmp, "/proc/%d/oom_score_adj", pid);
673 fp = fopen(tmp, "r");
679 if (fgets(tmp, sizeof(tmp), fp) == NULL) {
685 oomadj_val = atoi(tmp);
691 static void get_rss(pid_t pid, unsigned int *result)
694 char proc_path[PATH_MAX];
699 sprintf(proc_path, "/proc/%d/statm", pid);
700 fp = fopen(proc_path, "r");
704 if (fscanf(fp, "%*s %d", &rss) < 1) {
711 /* convert page to Kb */
716 static void show_rss(int output_type, char *output_path)
719 struct dirent *curdir;
721 char cmdline[PATH_MAX];
722 FILE *output_file = NULL;
726 pDir = opendir("/proc");
728 fprintf(stderr, "cannot read directory /proc.\n");
732 if (output_type == OUTPUT_FILE && output_path) {
733 output_file = fopen(output_path, "w+");
735 fprintf(stderr, "cannot open output file(%s)\n",
741 output_file = stdout;
745 " PID RSS OOM_SCORE COMMAND\n");
747 while ((curdir = readdir(pDir)) != NULL) {
748 pid = atoi(curdir->d_name);
749 if (pid < 1 || pid > 32768 || pid == getpid())
752 if (get_cmdline(pid, cmdline) < 0)
755 oom_score_adj = get_oomscoreadj(pid);
767 get_tmpfs_info(output_file);
768 get_mem_info(output_file);
776 static int show_map_all_new(int output_type, char *output_path)
779 struct dirent *curdir;
783 unsigned total_pss = 0;
784 unsigned total_private = 0;
785 unsigned total_private_code = 0;
786 unsigned total_private_data = 0;
787 unsigned total_shared_code = 0;
788 unsigned total_shared_data = 0;
789 unsigned total_shared_code_pss = 0;
790 unsigned total_shared_data_pss = 0;
791 unsigned total_rss = 0;
792 unsigned total_graphic_3d = 0;
793 unsigned total_gem_rss = 0;
794 unsigned total_gem_pss = 0;
795 unsigned total_peak_rss = 0;
796 unsigned total_allocated_gem = 0;
798 char cmdline[PATH_MAX];
799 FILE *output_file = NULL;
802 pDir = opendir("/proc");
804 fprintf(stderr, "cannot read directory /proc.\n");
808 if (output_type == OUTPUT_FILE && output_path) {
809 output_file = fopen(output_path, "w+");
811 fprintf(stderr, "cannot open output file(%s)\n",
817 output_file = stdout;
819 glist = load_geminfo();
824 " PID S(CODE) S(DATA) P(CODE) P(DATA)"
827 " OOM_SCORE_ADJ COMMAND\n");
830 " PID CODE DATA PEAK PSS"
831 " 3D GEM(PSS) COMMAND\n");
834 while ((curdir = readdir(pDir)) != NULL) {
835 pid = atoi(curdir->d_name);
836 if (pid < 1 || pid > 32768 || pid == getpid())
839 if (get_cmdline(pid, cmdline) < 0)
842 milist = load_maps(pid);
846 /* get classified map info */
847 get_trib_mapinfo(pid, milist, glist, &tmi);
848 oom_score_adj = get_oomscoreadj(pid);
853 "%8d %8d %8d %8d %8d %8d %8d %8d %8d %8d"
856 tmi.shared_clean, tmi.shared_dirty,
857 tmi.private_clean, tmi.private_dirty,
858 tmi.peak_rss, tmi.pss, tmi.graphic_3d,
859 tmi.gem_pss, tmi.gem_rss, oom_score_adj, cmdline);
862 "%8d %8d %8d %8d %8d %8d %8d %s\n",
866 tmi.shared_dirty + tmi.private_dirty,
870 tmi.gem_pss, cmdline);
872 if (tmi.other_devices != 0)
874 "%s(%d) %d KB may mapped by device(s).\n",
875 cmdline, pid, tmi.other_devices);
878 total_private += (tmi.private_clean + tmi.private_dirty);
879 total_pss += tmi.pss;
880 total_rss += tmi.rss;
881 total_graphic_3d += tmi.graphic_3d;
882 total_gem_rss += tmi.gem_rss;
883 total_gem_pss += tmi.gem_pss;
884 total_private_code += tmi.private_clean;
885 total_private_data += tmi.private_dirty;
886 total_shared_code += tmi.shared_clean;
887 total_shared_data += tmi.shared_dirty;
888 total_peak_rss += tmi.peak_rss;
890 total_shared_code_pss += tmi.shared_clean_pss;
891 total_shared_data_pss += tmi.shared_dirty_pss;
894 total_allocated_gem = KB(total_gem_memory());
896 "==============================================="
897 "===============================================\n");
900 "TOTAL: S(CODE) S(DATA) P(CODE) P(DATA)"
902 "GEM(PSS) GEM(RSS) GEM(ALLOC) TOTAL(KB)\n");
904 " %8d %8d %8d %8d %8d %8d %8d"
905 " %8d %8d %8d %8d\n",
906 total_shared_code, total_shared_data,
907 total_private_code, total_private_data,
908 total_peak_rss, total_pss, total_graphic_3d,
909 total_gem_pss, total_gem_rss,
911 total_pss + total_graphic_3d +
912 total_allocated_gem);
915 "TOTAL: CODE DATA PEAK PSS "
916 "3D GEM(PSS) GEM(ALLOC) TOTAL(KB)\n");
917 fprintf(output_file, " %8d %8d %8d %8d %8d %8d %7d %8d\n",
918 total_shared_code + total_private_code,
919 total_shared_data + total_private_data,
920 total_peak_rss, total_pss,
921 total_graphic_3d, total_gem_pss,
923 total_pss + total_graphic_3d +
924 total_allocated_gem);
930 "* S(CODE): shared clean memory, it includes"
931 " duplicated memory\n"
932 "* S(DATA): shared dirty memory, it includes"
933 " duplicated memory\n"
934 "* P(CODE): private clean memory\n"
935 "* P(DATA): private dirty memory\n"
936 "* PEAK: peak memory usage of S(CODE) + S(DATA)"
937 " + P(CODE) + P(DATA)\n"
938 "* PSS: Proportional Set Size\n"
939 "* 3D: memory allocated by GPU driver\n"
940 "* GEM(PSS): GEM memory devided by # of sharers\n"
941 "* GEM(RSS): GEM memory including duplicated memory\n"
942 "* GEM(ALLOC): sum of unique gem memory in the system\n"
943 "* TOTAL: PSS + 3D + GEM(ALLOC) \n");
946 "* CODE: shared and private clean memory\n"
947 "* DATA: shared and private dirty memory\n"
948 "* PEAK: peak memory usage of CODE + DATA\n"
949 "* PSS: Proportional Set Size\n"
950 "* 3D: memory allocated by GPU driver\n"
951 "* GEM(PSS): GEM memory deviced by # of sharers\n"
952 "* GEM(ALLOC): sum of unique GEM memory in the system\n"
953 "* TOTAL: PSS + 3D + GEM(ALLOC)\n");
955 get_tmpfs_info(output_file);
956 get_mem_info(output_file);
964 static int show_map_new(int pid)
968 unsigned shared_dirty = 0;
969 unsigned shared_clean = 0;
970 unsigned private_dirty = 0;
971 unsigned private_clean = 0;
975 unsigned private_clean_total = 0;
976 unsigned private_dirty_total = 0;
977 unsigned shared_clean_total = 0;
978 unsigned shared_dirty_total = 0;
981 milist = load_maps(pid);
984 fprintf(stderr, "cannot get /proc/smaps for pid %d\n", pid);
989 printf(" S(CODE) S(DATA) P(CODE) P(DATA) ADDR(start-end)"
991 printf("-------- -------- -------- -------- -----------------"
992 "------------------------------\n");
994 printf(" S(CODE) S(DATA) P(CODE) P(DATA) PSS\n");
995 printf("-------- -------- -------------------"
996 "------------------\n");
998 for (mi = milist; mi; mi = mi->next) {
999 shared_clean += mi->shared_clean;
1000 shared_dirty += mi->shared_dirty;
1001 private_clean += mi->private_clean;
1002 private_dirty += mi->private_dirty;
1005 shared_clean_total += mi->shared_clean;
1006 shared_dirty_total += mi->shared_dirty;
1007 private_clean_total += mi->private_clean;
1008 private_dirty_total += mi->private_dirty;
1013 if ((mi->next && !strcmp(mi->next->name, mi->name)) &&
1014 (mi->next->start == mi->end)) {
1022 printf("%8d %8d %8d %8d %08x-%08x %s\n",
1023 shared_clean, shared_dirty, private_clean, private_dirty,
1024 start, end, mi->name);
1032 printf("%8d %8d %8d %8d %18d\n",
1035 private_clean_total,
1036 private_dirty_total,
1043 void check_kernel_version(void)
1051 if (buf.release[0] == '3') {
1055 pch = strstr(buf.release, ".");
1056 strncpy(str, pch+1, 2);
1057 sub_version = atoi(str);
1059 if (sub_version >= 10)
1060 ignore_smaps_field = 8; /* Referenced, Anonymous, AnonHugePages,
1061 Swap, KernelPageSize, MMUPageSize,
1065 ignore_smaps_field = 7; /* Referenced, Anonymous, AnonHugePages,
1066 Swap, KernelPageSize, MMUPageSize,
1069 ignore_smaps_field = 4; /* Referenced, Swap, KernelPageSize,
1075 int main(int argc, char *argv[])
1081 check_kernel_version();
1083 if (!strcmp(argv[1], "-r")) {
1085 show_rss(OUTPUT_FILE, argv[2]);
1087 show_rss(OUTPUT_UART, NULL);
1089 } else if (!strcmp(argv[1], "-s")) {
1091 if (argc == 3 && atoi(argv[2]) > 0) {
1092 show_map_new(atoi(argv[2]));
1095 } else if (!strcmp(argv[1], "-a")) {
1097 show_map_all_new(OUTPUT_UART, NULL);
1099 } else if (!strcmp(argv[1], "-v")) {
1101 show_map_all_new(OUTPUT_UART, NULL);
1103 } else if (!strcmp(argv[1], "-f")) {
1106 show_map_all_new(OUTPUT_FILE, argv[2]);
1109 } else if (argc == 2 && atoi(argv[1]) > 0) {
1110 show_map_new(atoi(argv[1]));
1116 "memps [-a] | [-v] | [-s] <pid> | [-f] <output file full path>\n"
1117 " -s = sum (show only sum of each)\n"
1118 " -f = all (show all processes via output file)\n"
1119 " -a = all (show all processes)\n"
1120 " -v = verbos (show all processes in detail)\n");