From 0834a6d3b9daec1f460c3cc836136ace12c53df0 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Sat, 28 Aug 2010 23:20:34 +0200 Subject: 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 Signed-off-by: Denys Vlasenko --- procps/pmap.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ procps/top.c | 16 ++++----- 2 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 procps/pmap.c (limited to 'procps') diff --git a/procps/pmap.c b/procps/pmap.c new file mode 100644 index 000000000..cfa94ed82 --- /dev/null +++ b/procps/pmap.c @@ -0,0 +1,111 @@ +/* + * pmap implementation for busybox + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * Written by Alexander Shishkin + * + * Licensed under GPLv2 or later, see the LICENSE file in this source tree + * for details. + */ + +//applet:IF_PMAP(APPLET(pmap, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_PMAP) += pmap.o + +//config:config PMAP +//config: bool "pmap" +//config: default y +//config: help +//config: Display processes' memory mappings. + +//usage:#define pmap_trivial_usage +//usage: "[-x][-q] PID" +//usage:#define pmap_full_usage "\n\n" +//usage: "Display detailed precesses' memory usage\n" +//usage: "\nOptions:" +//usage: "\n -x show details" +//usage: "\n -q quiet" + +#include "libbb.h" + +#if ULONG_MAX == 0xffffffff +# define TABS "\t" +# define AFMT "8" +# define DASHES "" +#else +# define TABS "\t\t" +# define AFMT "16" +# define DASHES "--------" +#endif + +enum { + OPT_x = 1 << 0, + OPT_q = 1 << 1, +}; + +static void print_smaprec(struct smaprec *currec, void *data) +{ + unsigned opt = (unsigned)data; + + printf("%0" AFMT "lx ", currec->smap_start); + + if (opt & OPT_x) + printf("%7lu %7lu %7lu %7lu ", + currec->smap_size, + currec->smap_pss, + currec->private_dirty, + currec->smap_swap); + else + printf("%7luK", currec->smap_size); + + printf(" %.4s %s\n", currec->smap_mode, currec->smap_name); +} + +static int procps_get_maps(pid_t pid, unsigned opt) +{ + struct smaprec total; + int ret; + char buf[256]; + + read_cmdline(buf, sizeof(buf), pid, "no such process"); + printf("%u: %s\n", (int)pid, buf); + + if (!(opt & OPT_q) && (opt & OPT_x)) + puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping"); + + memset(&total, 0, sizeof(total)); + + ret = procps_read_smaps(pid, &total, print_smaprec, (void*)opt); + if (ret) + return ret; + + if (!(opt & OPT_q)) { + if (opt & OPT_x) + printf("--------" DASHES " ------ ------ ------ ------\n" + "total" TABS " %7lu %7lu %7lu %7lu\n", + total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); + else + printf("mapped: %luK\n", total.smap_size); + } + + return 0; +} + +int pmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pmap_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + int ret; + + opts = getopt32(argv, "xq"); + argv += optind; + + ret = 0; + while (*argv) { + pid_t pid = xatoi_positive(*argv++); + /* GNU pmap returns 42 if any of the pids failed */ + if (procps_get_maps(pid, opts) != 0) + ret = 42; + } + + return ret; +} diff --git a/procps/top.c b/procps/top.c index fd758099e..4f37878de 100644 --- a/procps/top.c +++ b/procps/top.c @@ -942,20 +942,20 @@ int top_main(int argc UNUSED_PARAM, char **argv) } #if ENABLE_FEATURE_TOPMEM else { /* TOPMEM */ - if (!(p->mapped_ro | p->mapped_rw)) + if (!(p->smaps.mapped_ro | p->smaps.mapped_rw)) continue; /* kernel threads are ignored */ n = ntop; /* No bug here - top and topmem are the same */ top = xrealloc_vector(topmem, 6, ntop++); strcpy(topmem[n].comm, p->comm); topmem[n].pid = p->pid; - topmem[n].vsz = p->mapped_rw + p->mapped_ro; - topmem[n].vszrw = p->mapped_rw; - topmem[n].rss_sh = p->shared_clean + p->shared_dirty; - topmem[n].rss = p->private_clean + p->private_dirty + topmem[n].rss_sh; - topmem[n].dirty = p->private_dirty + p->shared_dirty; - topmem[n].dirty_sh = p->shared_dirty; - topmem[n].stack = p->stack; + topmem[n].vsz = p->smaps.mapped_rw + p->smaps.mapped_ro; + topmem[n].vszrw = p->smaps.mapped_rw; + topmem[n].rss_sh = p->smaps.shared_clean + p->smaps.shared_dirty; + topmem[n].rss = p->smaps.private_clean + p->smaps.private_dirty + topmem[n].rss_sh; + topmem[n].dirty = p->smaps.private_dirty + p->smaps.shared_dirty; + topmem[n].dirty_sh = p->smaps.shared_dirty; + topmem[n].stack = p->smaps.stack; } #endif } /* end of "while we read /proc" */ -- cgit v1.2.3