aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorAlexander Shishkin <virtuoso@slind.org>2010-08-28 23:20:34 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-08-28 23:20:34 +0200
commit0834a6d3b9daec1f460c3cc836136ace12c53df0 (patch)
tree5a1ff91bf23113224ee2a54334c020ff97e0f19a /libbb
parent74c992af5c6b8cfe6214e705bc04f8c2f9d8a304 (diff)
downloadbusybox-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.c160
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 */
147static unsigned long fast_strtoul_10(char **endptr) 144static 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
178int 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
180void BUG_comm_size(void); 282void BUG_comm_size(void);
181procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) 283procps_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) {