blob: 0a9a58abd79ddc6e8558f38e3954056f1b5276c1 [file] [log] [blame]
The Android Open Source Projecte16cb842009-03-03 19:32:58 -08001#include <stdio.h>
2#include <stdlib.h>
3#include <math.h>
4#include <string.h>
5#include <errno.h>
6#include <unistd.h>
7#include <fcntl.h>
8
9#include <ctype.h>
10#include <stddef.h>
11
12typedef struct mapinfo mapinfo;
13
14struct mapinfo {
15 mapinfo *next;
16 unsigned start;
17 unsigned end;
18 unsigned size;
19 unsigned rss;
20 unsigned pss;
21 unsigned shared_clean;
22 unsigned shared_dirty;
23 unsigned private_clean;
24 unsigned private_dirty;
25 char name[1];
26};
27
28// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /android/lib/libcomposer.so
29// 012345678901234567890123456789012345678901234567890123456789
30// 0 1 2 3 4 5
31
Kenny Rootfda77ea2011-07-06 14:59:57 -070032int parse_header(char* line, int len, mapinfo** mi) {
33 unsigned long start;
34 unsigned long end;
35 char name[128];
36
37 name[0] = '\0';
38
39 // Sometimes the name is missing.
40 if (sscanf(line, "%lx-%lx %*s %*lx %*x:%*x %*ld %127s", &start, &end, name) < 2) {
41 return 0;
42 }
43
44 if (name[0] == '\0') {
45 if ((start >= 0x10000000) && (start < 0x40000000)) {
46 strlcpy(name, "[stack]", sizeof(name));
47 } else if (start > 0x50000000) {
48 strlcpy(name, "[lib_bss]", sizeof(name));
49 } else {
50 strlcpy(name, "[anon]", sizeof(name));
51 }
52 }
53
54 const int name_size = strlen(name) + 1;
55 struct mapinfo* info = calloc(1, sizeof(mapinfo) + name_size);
56 if (info == NULL) {
57 return -1;
58 }
59
60 info->start = start;
61 info->end = end;
62 strlcpy(info->name, name, name_size);
63
64 *mi = info;
65
66 return 0;
67}
68
69int parse_field(mapinfo* mi, char* line) {
70 char field[64];
71 int size;
72
73 if (sscanf(line, "%63s %d kB", field, &size) != 2) {
74 return -1;
75 }
76
77 if (!strcmp(field, "Size:")) {
78 mi->size = size;
79 } else if (!strcmp(field, "Rss:")) {
80 mi->rss = size;
81 } else if (!strcmp(field, "Pss:")) {
82 mi->pss = size;
83 } else if (!strcmp(field, "Shared_Clean:")) {
84 mi->shared_clean = size;
85 } else if (!strcmp(field, "Shared_Dirty:")) {
86 mi->shared_dirty = size;
87 } else if (!strcmp(field, "Private_Clean:")) {
88 mi->private_clean = size;
89 } else if (!strcmp(field, "Private_Dirty:")) {
90 mi->private_dirty = size;
91 }
92
93 return 0;
94}
95
The Android Open Source Projecte16cb842009-03-03 19:32:58 -080096mapinfo *read_mapinfo(FILE *fp)
97{
98 char line[1024];
Kenny Rootfda77ea2011-07-06 14:59:57 -070099 mapinfo *current = NULL;
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800100 int len;
101 int skip;
102
Kenny Rootfda77ea2011-07-06 14:59:57 -0700103 while (fgets(line, sizeof(line), fp) != 0) {
104 if (current != NULL) {
105 parse_field(current, line);
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800106 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700107
108 len = strlen(line);
109 if (len < 1) {
110 return NULL;
111 }
112 line[--len] = 0;
113
114 mapinfo *next = NULL;
115 if (parse_header(line, len, &next) < 0) {
116 goto err;
117 } else if (next != NULL) {
118 next->next = current;
119 current = next;
120 continue;
121 }
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800122 }
123
Kenny Rootfda77ea2011-07-06 14:59:57 -0700124 return current;
San Mehat89f9b912009-05-18 11:15:24 -0700125
Kenny Rootfda77ea2011-07-06 14:59:57 -0700126err:
127 while (current != NULL) {
128 mapinfo* next = current->next;
129 free(current);
130 current = next;
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800131 }
132
Kenny Rootfda77ea2011-07-06 14:59:57 -0700133 return NULL;
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800134}
135
136
137mapinfo *load_maps(int pid, int verbose)
138{
139 char tmp[128];
140 FILE *fp;
141 mapinfo *milist = 0;
142 mapinfo *mi;
143
Kenny Rootfda77ea2011-07-06 14:59:57 -0700144 snprintf(tmp, sizeof(tmp), "/proc/%d/smaps", pid);
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800145 fp = fopen(tmp, "r");
Kenny Rootfda77ea2011-07-06 14:59:57 -0700146 if (fp == 0) {
147 fprintf(stderr, "cannot open /proc/%d/smaps: %s\n", pid, strerror(errno));
148 return NULL;
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800149 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700150
151 milist = read_mapinfo(fp);
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800152 fclose(fp);
Kenny Rootfda77ea2011-07-06 14:59:57 -0700153
154 if (!milist) {
155 fprintf(stderr, "could not read /proc/%d/smaps\n", pid);
156 return NULL;
157 }
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800158
Kenny Rootfda77ea2011-07-06 14:59:57 -0700159 /* if not verbose, coalesce mappings from the same entity */
160 if (!verbose) {
161 mapinfo* current = milist;
162 mapinfo* last = NULL;
163
164 while (current != NULL) {
165 mapinfo* next = current->next;
166
167 if (last != NULL
168 && ((current->name[0] != '[' && !strcmp(last->name, current->name))
169 || !strcmp(current->name, "[lib_bss]"))) {
170 last->size += current->size;
171 last->rss += current->rss;
172 last->pss += current->pss;
173 last->shared_clean += current->shared_clean;
174 last->shared_dirty += current->shared_dirty;
175 last->private_clean += current->private_clean;
176 last->private_dirty += current->private_dirty;
177 last->end = current->end;
178
179 last->next = next;
180 free(current);
181 } else {
182 last = current;
183 }
184
185 current = next;
186 }
187 }
188
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800189 return milist;
190}
191
192static int verbose = 0;
193static int terse = 0;
194static int addresses = 0;
195
196int show_map(int pid)
197{
198 mapinfo *milist;
199 mapinfo *mi;
200 unsigned shared_dirty = 0;
201 unsigned shared_clean = 0;
202 unsigned private_dirty = 0;
203 unsigned private_clean = 0;
204 unsigned rss = 0;
205 unsigned pss = 0;
206 unsigned size = 0;
207
208 milist = load_maps(pid, verbose);
Kenny Rootfda77ea2011-07-06 14:59:57 -0700209 if (milist == NULL) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800210 return 1;
211 }
212
Kenny Rootfda77ea2011-07-06 14:59:57 -0700213 if (addresses) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800214 printf("start end shared private object\n");
215 printf("-------- -------- -------- -------- ------------------------------\n");
216 } else {
217 printf("virtual shared shared private private\n");
218 printf("size RSS PSS clean dirty clean dirty object\n");
219 printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
220 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700221
222 for (mi = milist; mi;) {
223 mapinfo* last = mi;
224
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800225 shared_clean += mi->shared_clean;
226 shared_dirty += mi->shared_dirty;
227 private_clean += mi->private_clean;
228 private_dirty += mi->private_dirty;
229 rss += mi->rss;
230 pss += mi->pss;
231 size += mi->size;
232
Kenny Rootfda77ea2011-07-06 14:59:57 -0700233 if (terse && !mi->private_dirty) {
234 goto out;
235 }
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800236
Kenny Rootfda77ea2011-07-06 14:59:57 -0700237 if (addresses) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800238 printf("%08x %08x %8d %8d %s\n", mi->start, mi->end,
239 mi->shared_clean + mi->shared_dirty,
240 mi->private_clean + mi->private_dirty,
241 mi->name);
242 } else {
243 printf("%8d %8d %8d %8d %8d %8d %8d %s\n", mi->size,
244 mi->rss,
245 mi->pss,
246 mi->shared_clean, mi->shared_dirty,
247 mi->private_clean, mi->private_dirty,
248 mi->name);
249 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700250
251out:
252 mi = mi->next;
253 free(last);
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800254 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700255
256 if (addresses) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800257 printf("-------- -------- -------- -------- ------------------------------\n");
258 printf(" %8d %8d TOTAL\n",
259 shared_dirty + shared_clean,
260 private_dirty + private_clean);
261 } else {
262 printf("-------- -------- -------- -------- -------- -------- -------- ------------------------------\n");
263 printf("%8d %8d %8d %8d %8d %8d %8d TOTAL\n", size,
264 rss, pss,
265 shared_clean, shared_dirty,
266 private_clean, private_dirty);
267 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700268
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800269 return 0;
270}
271
272int main(int argc, char *argv[])
273{
274 int usage = 1;
275
Kenny Rootfda77ea2011-07-06 14:59:57 -0700276 for (argc--, argv++; argc > 0; argc--, argv++) {
277 if (!strcmp(argv[0],"-v")) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800278 verbose = 1;
279 continue;
280 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700281 if (!strcmp(argv[0],"-t")) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800282 terse = 1;
283 continue;
284 }
Kenny Rootfda77ea2011-07-06 14:59:57 -0700285 if (!strcmp(argv[0],"-a")) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800286 addresses = 1;
287 continue;
288 }
289 show_map(atoi(argv[0]));
290 usage = 0;
291 }
292
Kenny Rootfda77ea2011-07-06 14:59:57 -0700293 if (usage) {
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800294 fprintf(stderr,
295 "showmap [-t] [-v] [-c] <pid>\n"
296 " -t = terse (show only items with private pages)\n"
297 " -v = verbose (don't coalesce adjacant maps)\n"
298 " -a = addresses (show virtual memory map)\n"
299 );
300 }
301
Kenny Rootfda77ea2011-07-06 14:59:57 -0700302 return 0;
The Android Open Source Projecte16cb842009-03-03 19:32:58 -0800303}