1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/types.h>
21 
22 #include <memtrack/memtrack.h>
23 
24 #include <pagemap/pagemap.h>
25 
26 #define DIV_ROUND_UP(x,y) (((x) + (y) - 1) / (y))
27 
getprocname(pid_t pid,char * buf,int len)28 static int getprocname(pid_t pid, char *buf, int len) {
29     char *filename;
30     FILE *f;
31     int rc = 0;
32     static const char* unknown_cmdline = "<unknown>";
33 
34     if (len <= 0) {
35         return -1;
36     }
37 
38     if (asprintf(&filename, "/proc/%d/cmdline", pid) < 0) {
39         rc = 1;
40         goto exit;
41     }
42 
43     f = fopen(filename, "r");
44     if (f == NULL) {
45         rc = 2;
46         goto releasefilename;
47     }
48 
49     if (fgets(buf, len, f) == NULL) {
50         rc = 3;
51         goto closefile;
52     }
53 
54 closefile:
55     (void) fclose(f);
56 releasefilename:
57     free(filename);
58 exit:
59     if (rc != 0) {
60         /*
61          * The process went away before we could read its process name. Try
62          * to give the user "<unknown>" here, but otherwise they get to look
63          * at a blank.
64          */
65         if (strlcpy(buf, unknown_cmdline, (size_t)len) >= (size_t)len) {
66             rc = 4;
67         }
68     }
69 
70     return rc;
71 }
72 
main(int argc,char * argv[])73 int main(int argc, char *argv[])
74 {
75     int ret;
76     pm_kernel_t *ker;
77     size_t num_procs;
78     pid_t *pids;
79     struct memtrack_proc *p;
80     size_t i;
81 
82     (void)argc;
83     (void)argv;
84 
85     ret = pm_kernel_create(&ker);
86     if (ret) {
87         fprintf(stderr, "Error creating kernel interface -- "
88                         "does this kernel have pagemap?\n");
89         exit(EXIT_FAILURE);
90     }
91 
92     ret = pm_kernel_pids(ker, &pids, &num_procs);
93     if (ret) {
94         fprintf(stderr, "Error listing processes.\n");
95         exit(EXIT_FAILURE);
96     }
97 
98     p = memtrack_proc_new();
99     if (ret) {
100         fprintf(stderr, "failed to create memtrack process handle\n");
101         exit(EXIT_FAILURE);
102     }
103 
104     for (i = 0; i < num_procs; i++) {
105         pid_t pid = pids[i];
106         char cmdline[256];
107         size_t v1;
108         size_t v2;
109         size_t v3;
110         size_t v4;
111         size_t v5;
112         size_t v6;
113 
114         getprocname(pid, cmdline, (int)sizeof(cmdline));
115 
116         ret = memtrack_proc_get(p, pid);
117         if (ret) {
118             fprintf(stderr, "failed to get memory info for pid %d: %s (%d)\n",
119                     pid, strerror(-ret), ret);
120             continue;
121         }
122 
123         v1 = DIV_ROUND_UP(memtrack_proc_graphics_total(p), 1024);
124         v2 = DIV_ROUND_UP(memtrack_proc_graphics_pss(p), 1024);
125         v3 = DIV_ROUND_UP(memtrack_proc_gl_total(p), 1024);
126         v4 = DIV_ROUND_UP(memtrack_proc_gl_pss(p), 1024);
127         v5 = DIV_ROUND_UP(memtrack_proc_other_total(p), 1024);
128         v6 = DIV_ROUND_UP(memtrack_proc_other_pss(p), 1024);
129 
130         if (v1 | v2 | v3 | v4 | v5 | v6) {
131             printf("%5d %6zu %6zu %6zu %6zu %6zu %6zu %s\n", pid,
132                    v1, v2, v3, v4, v5, v6, cmdline);
133         }
134     }
135 
136     memtrack_proc_destroy(p);
137 
138     return 0;
139 }
140