diff options
author | Alexander Shishkin <virtuoso@slind.org> | 2010-08-28 23:20:34 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-08-28 23:20:34 +0200 |
commit | 0834a6d3b9daec1f460c3cc836136ace12c53df0 (patch) | |
tree | 5a1ff91bf23113224ee2a54334c020ff97e0f19a /libbb | |
parent | 74c992af5c6b8cfe6214e705bc04f8c2f9d8a304 (diff) | |
download | busybox-w32-0834a6d3b9daec1f460c3cc836136ace12c53df0.tar.gz busybox-w32-0834a6d3b9daec1f460c3cc836136ace12c53df0.tar.bz2 busybox-w32-0834a6d3b9daec1f460c3cc836136ace12c53df0.zip |
pmap: new applet. +1k.
pmap is a tool used to look at processes' memory maps, normally found
in procps package. It provides more readable and easily sortable output
(one line per mapping) from maps/smaps files in /proc/PID/. This would
help in debugging memory usage issues, especially on devices where lots
of typing is not a viable option.
This patch does'n implement -d and -A command line options of GNU pmap,
since those are not that must have features and I was afraid of going
blind from looking at its code.
The implementation takes smaps scanning part out of procps_scan() function
and moves it into procps_read_smaps(), which does more detailed processing
of a single PID's smaps data.
Signed-off-by: Alexander Shishkin <virtuoso@slind.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/procps.c | 160 |
1 files changed, 108 insertions, 52 deletions
diff --git a/libbb/procps.c b/libbb/procps.c index 16992b670..14d4481bd 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -137,12 +137,9 @@ static unsigned long fast_strtoul_16(char **endptr) | |||
137 | *endptr = str; /* We skip trailing space! */ | 137 | *endptr = str; /* We skip trailing space! */ |
138 | return n; | 138 | return n; |
139 | } | 139 | } |
140 | /* TOPMEM uses fast_strtoul_10, so... */ | ||
141 | # undef ENABLE_FEATURE_FAST_TOP | ||
142 | # define ENABLE_FEATURE_FAST_TOP 1 | ||
143 | #endif | 140 | #endif |
144 | 141 | ||
145 | #if ENABLE_FEATURE_FAST_TOP | 142 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
146 | /* We cut a lot of corners here for speed */ | 143 | /* We cut a lot of corners here for speed */ |
147 | static unsigned long fast_strtoul_10(char **endptr) | 144 | static unsigned long fast_strtoul_10(char **endptr) |
148 | { | 145 | { |
@@ -177,6 +174,111 @@ static char *skip_fields(char *str, int count) | |||
177 | } | 174 | } |
178 | #endif | 175 | #endif |
179 | 176 | ||
177 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | ||
178 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
179 | void (*cb)(struct smaprec *, void *), void *data) | ||
180 | { | ||
181 | FILE *file; | ||
182 | struct smaprec currec; | ||
183 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; | ||
184 | char buf[PROCPS_BUFSIZE]; | ||
185 | #if !ENABLE_PMAP | ||
186 | void (*cb)(struct smaprec *, void *) = NULL; | ||
187 | void *data = NULL; | ||
188 | #endif | ||
189 | |||
190 | sprintf(filename, "/proc/%u/smaps", (int)pid); | ||
191 | |||
192 | file = fopen_for_read(filename); | ||
193 | if (!file) | ||
194 | return 1; | ||
195 | |||
196 | memset(&currec, 0, sizeof(currec)); | ||
197 | while (fgets(buf, PROCPS_BUFSIZE, file)) { | ||
198 | // Each mapping datum has this form: | ||
199 | // f7d29000-f7d39000 rw-s ADR M:m OFS FILE | ||
200 | // Size: nnn kB | ||
201 | // Rss: nnn kB | ||
202 | // ..... | ||
203 | |||
204 | char *tp = buf, *p; | ||
205 | |||
206 | #define SCAN(S, X) \ | ||
207 | if (strncmp(tp, S, sizeof(S)-1) == 0) { \ | ||
208 | tp = skip_whitespace(tp + sizeof(S)-1); \ | ||
209 | total->X += currec.X = fast_strtoul_10(&tp); \ | ||
210 | continue; \ | ||
211 | } | ||
212 | if (cb) { | ||
213 | SCAN("Pss:" , smap_pss ); | ||
214 | SCAN("Swap:" , smap_swap ); | ||
215 | } | ||
216 | SCAN("Private_Dirty:", private_dirty); | ||
217 | SCAN("Private_Clean:", private_clean); | ||
218 | SCAN("Shared_Dirty:" , shared_dirty ); | ||
219 | SCAN("Shared_Clean:" , shared_clean ); | ||
220 | #undef SCAN | ||
221 | tp = strchr(buf, '-'); | ||
222 | if (tp) { | ||
223 | // We reached next mapping - the line of this form: | ||
224 | // f7d29000-f7d39000 rw-s ADR M:m OFS FILE | ||
225 | |||
226 | if (cb) { | ||
227 | /* If we have a previous record, there's nothing more | ||
228 | * for it, call the callback and clear currec | ||
229 | */ | ||
230 | if (currec.smap_size) | ||
231 | cb(&currec, data); | ||
232 | free(currec.smap_name); | ||
233 | } | ||
234 | memset(&currec, 0, sizeof(currec)); | ||
235 | |||
236 | *tp = ' '; | ||
237 | tp = buf; | ||
238 | currec.smap_start = fast_strtoul_16(&tp); | ||
239 | currec.smap_size = (fast_strtoul_16(&tp) - currec.smap_start) >> 10; | ||
240 | |||
241 | strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); | ||
242 | |||
243 | // skipping "rw-s ADR M:m OFS " | ||
244 | tp = skip_whitespace(skip_fields(tp, 4)); | ||
245 | // filter out /dev/something (something != zero) | ||
246 | if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { | ||
247 | if (currec.smap_mode[1] == 'w') { | ||
248 | currec.mapped_rw = currec.smap_size; | ||
249 | total->mapped_rw += currec.smap_size; | ||
250 | } else if (currec.smap_mode[1] == '-') { | ||
251 | currec.mapped_ro = currec.smap_size; | ||
252 | total->mapped_ro += currec.smap_size; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if (strcmp(tp, "[stack]\n") == 0) | ||
257 | total->stack += currec.smap_size; | ||
258 | if (cb) { | ||
259 | p = skip_non_whitespace(tp); | ||
260 | if (p == tp) { | ||
261 | currec.smap_name = xstrdup(" [ anon ]"); | ||
262 | } else { | ||
263 | *p = '\0'; | ||
264 | currec.smap_name = xstrdup(tp); | ||
265 | } | ||
266 | } | ||
267 | total->smap_size += currec.smap_size; | ||
268 | } | ||
269 | } | ||
270 | fclose(file); | ||
271 | |||
272 | if (cb) { | ||
273 | if (currec.smap_size) | ||
274 | cb(&currec, data); | ||
275 | free(currec.smap_name); | ||
276 | } | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | #endif | ||
281 | |||
180 | void BUG_comm_size(void); | 282 | void BUG_comm_size(void); |
181 | procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | 283 | procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) |
182 | { | 284 | { |
@@ -365,54 +467,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
365 | } | 467 | } |
366 | 468 | ||
367 | #if ENABLE_FEATURE_TOPMEM | 469 | #if ENABLE_FEATURE_TOPMEM |
368 | if (flags & (PSSCAN_SMAPS)) { | 470 | if (flags & PSSCAN_SMAPS) |
369 | FILE *file; | 471 | procps_read_smaps(pid, &sp->smaps, NULL, NULL); |
370 | |||
371 | strcpy(filename_tail, "smaps"); | ||
372 | file = fopen_for_read(filename); | ||
373 | if (file) { | ||
374 | while (fgets(buf, sizeof(buf), file)) { | ||
375 | unsigned long sz; | ||
376 | char *tp; | ||
377 | char w; | ||
378 | #define SCAN(str, name) \ | ||
379 | if (strncmp(buf, str, sizeof(str)-1) == 0) { \ | ||
380 | tp = skip_whitespace(buf + sizeof(str)-1); \ | ||
381 | sp->name += fast_strtoul_10(&tp); \ | ||
382 | continue; \ | ||
383 | } | ||
384 | SCAN("Shared_Clean:" , shared_clean ); | ||
385 | SCAN("Shared_Dirty:" , shared_dirty ); | ||
386 | SCAN("Private_Clean:", private_clean); | ||
387 | SCAN("Private_Dirty:", private_dirty); | ||
388 | #undef SCAN | ||
389 | // f7d29000-f7d39000 rw-s ADR M:m OFS FILE | ||
390 | tp = strchr(buf, '-'); | ||
391 | if (tp) { | ||
392 | *tp = ' '; | ||
393 | tp = buf; | ||
394 | sz = fast_strtoul_16(&tp); /* start */ | ||
395 | sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */ | ||
396 | // tp -> "rw-s" string | ||
397 | w = tp[1]; | ||
398 | // skipping "rw-s ADR M:m OFS " | ||
399 | tp = skip_whitespace(skip_fields(tp, 4)); | ||
400 | // filter out /dev/something (something != zero) | ||
401 | if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { | ||
402 | if (w == 'w') { | ||
403 | sp->mapped_rw += sz; | ||
404 | } else if (w == '-') { | ||
405 | sp->mapped_ro += sz; | ||
406 | } | ||
407 | } | ||
408 | //else printf("DROPPING %s (%s)\n", buf, tp); | ||
409 | if (strcmp(tp, "[stack]\n") == 0) | ||
410 | sp->stack += sz; | ||
411 | } | ||
412 | } | ||
413 | fclose(file); | ||
414 | } | ||
415 | } | ||
416 | #endif /* TOPMEM */ | 472 | #endif /* TOPMEM */ |
417 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 473 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
418 | if (flags & PSSCAN_RUIDGID) { | 474 | if (flags & PSSCAN_RUIDGID) { |