svn commit: trunk/busybox: include libbb procps

vda at busybox.net vda at busybox.net
Sat Sep 8 16:51:20 UTC 2007


Author: vda
Date: 2007-09-08 09:51:19 -0700 (Sat, 08 Sep 2007)
New Revision: 19802

Log:
top: TOPMEM feature - 's(how sizes)' command. +2.5k when enabled,
+80 bytes when disabled (mainly because of text wrapping fixes
in display_process_list).



Modified:
   trunk/busybox/include/libbb.h
   trunk/busybox/libbb/procps.c
   trunk/busybox/procps/Config.in
   trunk/busybox/procps/top.c


Changeset:
Modified: trunk/busybox/include/libbb.h
===================================================================
--- trunk/busybox/include/libbb.h	2007-09-07 20:28:25 UTC (rev 19801)
+++ trunk/busybox/include/libbb.h	2007-09-08 16:51:19 UTC (rev 19802)
@@ -904,6 +904,15 @@
 	unsigned uid;
 	unsigned gid;
 	unsigned tty_major,tty_minor;
+#if ENABLE_FEATURE_TOPMEM
+	unsigned long mapped_rw;
+	unsigned long mapped_ro;
+	unsigned long shared_clean;
+	unsigned long shared_dirty;
+	unsigned long private_clean;
+	unsigned long private_dirty;
+	unsigned long stack;
+#endif
 	char state[4];
 	/* basename of executable in exec(2), read from /proc/N/stat
 	 * (if executable is symlink or script, it is NOT replaced
@@ -927,7 +936,8 @@
 	PSSCAN_STIME    = 1 << 12,
 	PSSCAN_UTIME    = 1 << 13,
 	PSSCAN_TTY      = 1 << 14,
-	USE_SELINUX(PSSCAN_CONTEXT  = 1 << 15,)
+	PSSCAN_SMAPS	= (1 << 15) * ENABLE_FEATURE_TOPMEM,
+	USE_SELINUX(PSSCAN_CONTEXT = 1 << 16,)
 	/* These are all retrieved from proc/NN/stat in one go: */
 	PSSCAN_STAT     = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
 	                | PSSCAN_COMM | PSSCAN_STATE

Modified: trunk/busybox/libbb/procps.c
===================================================================
--- trunk/busybox/libbb/procps.c	2007-09-07 20:28:25 UTC (rev 19801)
+++ trunk/busybox/libbb/procps.c	2007-09-08 16:51:19 UTC (rev 19802)
@@ -115,6 +115,28 @@
 	free(sp);
 }
 
+#if ENABLE_FEATURE_TOPMEM
+static unsigned long fast_strtoul_16(char **endptr)
+{
+	unsigned char c;
+	char *str = *endptr;
+	unsigned long n = 0;
+
+	while ((c = *str++) != ' ') {
+		c = ((c|0x20) - '0');
+		if (c > 9)
+			// c = c + '0' - 'a' + 10:
+			c = c - ('a' - '0' - 10);
+		n = n*16 + c;
+	}
+	*endptr = str; /* We skip trailing space! */
+	return n;
+}
+/* TOPMEM uses fast_strtoul_10, so... */
+#undef ENABLE_FEATURE_FAST_TOP
+#define ENABLE_FEATURE_FAST_TOP 1
+#endif
+
 #if ENABLE_FEATURE_FAST_TOP
 /* We cut a lot of corners here for speed */
 static unsigned long fast_strtoul_10(char **endptr)
@@ -278,6 +300,57 @@
 
 		}
 
+#if ENABLE_FEATURE_TOPMEM
+		if (flags & (PSSCAN_SMAPS)) {
+			FILE *file;
+
+			strcpy(filename_tail, "/smaps");
+			file = fopen(filename, "r");
+			if (!file)
+				break;
+			while (fgets(buf, sizeof(buf), file)) {
+				unsigned long sz;
+				char *tp;
+				char w;
+#define SCAN(str, name) \
+	if (strncmp(buf, str, sizeof(str)-1) == 0) { \
+		tp = skip_whitespace(buf + sizeof(str)-1); \
+		sp->name += fast_strtoul_10(&tp); \
+		continue; \
+	}
+				SCAN("Shared_Clean:" , shared_clean );
+				SCAN("Shared_Dirty:" , shared_dirty );
+				SCAN("Private_Clean:", private_clean);
+				SCAN("Private_Dirty:", private_dirty);
+#undef SCAN
+				// f7d29000-f7d39000 rw-s ADR M:m OFS FILE
+				tp = strchr(buf, '-');
+				if (tp) {
+					*tp = ' ';
+					tp = buf;
+					sz = fast_strtoul_16(&tp); /* start */
+					sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */
+					// tp -> "rw-s" string
+					w = tp[1];
+					// skipping "rw-s ADR M:m OFS "
+					tp = skip_whitespace(skip_fields(tp, 4));
+					// filter out /dev/something (something != zero)
+					if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) {
+						if (w == 'w') {
+							sp->mapped_rw += sz;
+						} else if (w == '-') {
+							sp->mapped_ro += sz;
+						}
+					}
+//else printf("DROPPING %s (%s)\n", buf, tp);
+					if (strcmp(tp, "[stack]\n") == 0)
+						sp->stack += sz;
+				}
+			}
+			fclose(file);
+		}
+#endif /* TOPMEM */
+
 #if 0 /* PSSCAN_CMD is not used */
 		if (flags & (PSSCAN_CMD|PSSCAN_ARGV0)) {
 			if (sp->argv0) {

Modified: trunk/busybox/procps/Config.in
===================================================================
--- trunk/busybox/procps/Config.in	2007-09-07 20:28:25 UTC (rev 19801)
+++ trunk/busybox/procps/Config.in	2007-09-08 16:51:19 UTC (rev 19802)
@@ -128,6 +128,13 @@
 	help
 	  Show 1/10th of a percent in CPU/mem statistics.
 
+config FEATURE_TOPMEM
+	bool "topmem"
+	default n
+	depends on TOP
+	help
+	  Enable 's' in top (gives lots of memory info)
+
 config UPTIME
 	bool "uptime"
 	default n

Modified: trunk/busybox/procps/top.c
===================================================================
--- trunk/busybox/procps/top.c	2007-09-07 20:28:25 UTC (rev 19801)
+++ trunk/busybox/procps/top.c	2007-09-08 16:51:19 UTC (rev 19802)
@@ -58,11 +58,17 @@
 
 typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
 
+
 enum { SORT_DEPTH = 3 };
 
+
 struct globals {
 	top_status_t *top;
 	int ntop;
+#if ENABLE_FEATURE_TOPMEM
+	smallint sort_field;
+	smallint inverted;
+#endif
 #if ENABLE_FEATURE_USE_TERMIOS
 	struct termios initial_settings;
 #endif
@@ -81,7 +87,9 @@
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define top              (G.top               )
 #define ntop             (G.ntop              )
-#define initial_settings (G. initial_settings )
+#define sort_field       (G.sort_field        )
+#define inverted         (G.inverted          )
+#define initial_settings (G.initial_settings  )
 #define sort_function    (G.sort_function     )
 #define prev_hist        (G.prev_hist         )
 #define prev_hist_count  (G.prev_hist_count   )
@@ -371,15 +379,11 @@
 	/* what info of the processes is shown */
 	printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
 		"  PID  PPID USER     STAT   VSZ %MEM %CPU COMMAND");
-#define MIN_WIDTH \
-	sizeof( "  PID  PPID USER     STAT   VSZ %MEM %CPU C")
 #else
 
 	/* !CPU_USAGE_PERCENTAGE */
 	printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
 		"  PID  PPID USER     STAT   VSZ %MEM COMMAND");
-#define MIN_WIDTH \
-	sizeof( "  PID  PPID USER     STAT   VSZ %MEM C")
 #endif
 
 #if ENABLE_FEATURE_TOP_DECIMALS
@@ -434,20 +438,23 @@
 	/* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */
 #endif
 
-	/* Ok, all prelim data is ready, go thru the list */
+	scr_width += 2; /* account for leading '\n' and trailing NUL */
+	/* Ok, all preliminary data is ready, go thru the list */
 	while (count-- > 0) {
-		int col = scr_width;
+		char buf[scr_width];
+		unsigned col;
 		CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
 		CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift);
 #endif
 
-		if (s->vsz >= 100*1024)
+		if (s->vsz >= 100000)
 			sprintf(vsz_str_buf, "%6ldm", s->vsz/1024);
 		else
 			sprintf(vsz_str_buf, "%7ld", s->vsz);
 		// PID PPID USER STAT VSZ %MEM [%CPU] COMMAND
-		col -= printf("\n" "%5u%6u %-8.8s %s%s" FMT
+		col = snprintf(buf, scr_width,
+				"\n" "%5u%6u %-8.8s %s%s" FMT
 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
 				FMT
 #endif
@@ -459,11 +466,9 @@
 				, SHOW_STAT(pcpu)
 #endif
 		);
-		if (col > 0) {
-			char buf[col + 1];
-			read_cmdline(buf, col, s->pid, s->comm);
-			fputs(buf, stdout);
-		}
+		if (col < scr_width)
+			read_cmdline(buf + col, scr_width - col, s->pid, s->comm);
+		fputs(buf, stdout);
 		/* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
 			jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
 		s++;
@@ -481,7 +486,7 @@
 {
 	clear_username_cache();
 	free(top);
-	top = 0;
+	top = NULL;
 	ntop = 0;
 }
 
@@ -508,13 +513,298 @@
 #endif /* FEATURE_USE_TERMIOS */
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+typedef unsigned long mem_t;
+
+typedef struct topmem_status_t {
+	unsigned pid;
+	char comm[COMM_LEN];
+	/* vsz doesn't count /dev/xxx mappings except /dev/zero */
+	mem_t vsz     ;
+	mem_t vszrw   ;
+	mem_t rss     ;
+	mem_t rss_sh  ;
+	mem_t dirty   ;
+	mem_t dirty_sh;
+	mem_t stack   ;
+} topmem_status_t;
+
+enum { NUM_SORT_FIELD = 7 };
+
+#define topmem ((topmem_status_t*)top)
+
+#if ENABLE_FEATURE_TOPMEM
+static int topmem_sort(char *a, char *b)
+{
+	int n;
+	mem_t l, r;
+
+	n = offsetof(topmem_status_t, vsz) + (sort_field * sizeof(mem_t));
+	l = *(mem_t*)(a + n);
+	r = *(mem_t*)(b + n);
+//	if (l == r) {
+//		l = a->mapped_rw;
+//		r = b->mapped_rw;
+//	}
+	/* We want to avoid unsigned->signed and truncation errors */
+	/* l>r: -1, l=r: 0, l<r: 1 */
+	n = (l > r) ? -1 : (l != r);
+	return inverted ? -n : n;
+}
+
+/* Cut "NNNN " out of "    NNNN kb" */
+static char *grab_number(char *str, const char *match, unsigned sz)
+{
+	if (strncmp(str, match, sz) == 0) {
+		str = skip_whitespace(str + sz);
+		(skip_non_whitespace(str))[1] = '\0';
+		return xstrdup(str);
+	}
+	return NULL;
+}
+
+/* display header info (meminfo / loadavg) */
+static void display_topmem_header(int scr_width)
+{
+	char linebuf[128];
+	int i;
+	FILE *fp;
+	union {
+		struct {
+			/*  1 */ char *total;
+			/*  2 */ char *mfree;
+			/*  3 */ char *buf;
+			/*  4 */ char *cache;
+			/*  5 */ char *swaptotal;
+			/*  6 */ char *swapfree;
+			/*  7 */ char *dirty;
+			/*  8 */ char *mwrite;
+			/*  9 */ char *anon;
+			/* 10 */ char *map;
+			/* 11 */ char *slab;
+		};
+		char *str[11];
+	} Z;
+#define total     Z.total
+#define mfree     Z.mfree
+#define buf       Z.buf
+#define cache     Z.cache
+#define swaptotal Z.swaptotal
+#define swapfree  Z.swapfree
+#define dirty     Z.dirty
+#define mwrite    Z.mwrite
+#define anon      Z.anon
+#define map       Z.map
+#define slab      Z.slab
+#define str       Z.str
+
+	memset(&Z, 0, sizeof(Z));
+
+	/* read memory info */
+	fp = xfopen("meminfo", "r");
+	while (fgets(linebuf, sizeof(linebuf), fp)) {
+		char *p;
+
+#define SCAN(match, name) \
+		p = grab_number(linebuf, match, sizeof(match)-1); \
+		if (p) { name = p; continue; }
+
+		SCAN("MemTotal:", total);
+		SCAN("MemFree:", mfree);
+		SCAN("Buffers:", buf);
+		SCAN("Cached:", cache);
+		SCAN("SwapTotal:", swaptotal);
+		SCAN("SwapFree:", swapfree);
+		SCAN("Dirty:", dirty);
+		SCAN("Writeback:", mwrite);
+		SCAN("AnonPages:", anon);
+		SCAN("Mapped:", map);
+		SCAN("Slab:", slab);
+#undef SCAN
+	}
+	fclose(fp);
+
+#define S(s) (s ? s : "0")
+	snprintf(linebuf, sizeof(linebuf),
+		"Mem %stotal %sanon %smap %sfree",
+		S(total), S(anon), S(map), S(mfree));
+	printf(OPT_BATCH_MODE ? "%.*s\n" : "\e[H\e[J%.*s\n", scr_width, linebuf);
+
+	snprintf(linebuf, sizeof(linebuf),
+		" %sslab %sbuf %scache %sdirty %swrite",
+		S(slab), S(buf), S(cache), S(dirty), S(mwrite));
+	printf("%.*s\n", scr_width, linebuf);
+
+	snprintf(linebuf, sizeof(linebuf),
+		"Swap %stotal %sfree", // TODO: % used?
+		S(swaptotal), S(swapfree));
+	printf("%.*s\n", scr_width, linebuf);
+#undef S
+
+	for (i = 0; i < ARRAY_SIZE(str); i++)
+		free(str[i]);
+#undef total
+#undef free
+#undef buf
+#undef cache
+#undef swaptotal
+#undef swapfree
+#undef dirty
+#undef write
+#undef anon
+#undef map
+#undef slab
+#undef str
+}
+
+// Converts unsigned long long value into compact 5-char
+// representation. Sixth char is always ' '
+static void smart_ulltoa6(unsigned long long ul, char buf[6])
+{
+	const char *fmt;
+	char c;
+	unsigned v, u, idx = 0;
+
+	if (ul > 99999) { // do not scale if 99999 or less
+		ul *= 10;
+		do {
+			ul /= 1024;
+			idx++;
+		} while (ul >= 100000);
+	}
+	v = ul; // ullong divisions are expensive, avoid them
+
+	fmt = " 123456789";
+	u = v / 10;
+	v = v % 10;
+	if (!idx) {
+		// 99999 or less: use "12345" format
+		// u is value/10, v is last digit
+		c = buf[0] = " 123456789"[u/1000];
+		if (c != ' ') fmt = "0123456789";
+		c = buf[1] = fmt[u/100%10];
+		if (c != ' ') fmt = "0123456789";
+		c = buf[2] = fmt[u/10%10];
+		if (c != ' ') fmt = "0123456789";
+		buf[3] = fmt[u%10];
+		buf[4] = "0123456789"[v];
+	} else {
+		// value has been scaled into 0..9999.9 range
+		// u is value, v is 1/10ths (allows for 92.1M format)
+		if (u >= 100) {
+			// value is >= 100: use "1234M', " 123M" formats
+			c = buf[0] = " 123456789"[u/1000];
+			if (c != ' ') fmt = "0123456789";
+			c = buf[1] = fmt[u/100%10];
+			if (c != ' ') fmt = "0123456789";
+			v = u % 10;
+			u = u / 10;
+			buf[2] = fmt[u%10];
+		} else {
+			// value is < 100: use "92.1M" format
+			c = buf[0] = " 123456789"[u/10];
+			if (c != ' ') fmt = "0123456789";
+			buf[1] = fmt[u%10];
+			buf[2] = '.';
+		}
+		buf[3] = "0123456789"[v];
+		// see http://en.wikipedia.org/wiki/Tera
+		buf[4] = " mgtpezy"[idx];
+	}
+	buf[5] = ' ';
+}
+
+static void display_topmem_process_list(int count, int scr_width)
+{
+#define HDR_STR "  PID   VSZ VSZRW   RSS (SHR) DIRTY (SHR) STACK"
+#define MIN_WIDTH sizeof(HDR_STR)
+	const topmem_status_t *s = topmem;
+	char buf[scr_width | MIN_WIDTH]; /* a|b is a cheap max(a,b) */
+
+	display_topmem_header(scr_width);
+	strcpy(buf, HDR_STR " COMMAND");
+	buf[5 + sort_field * 6] = '*';
+	printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, buf);
+
+	while (--count >= 0) {
+		// PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND
+		smart_ulltoa6(s->pid     , &buf[0*6]);
+		smart_ulltoa6(s->vsz     , &buf[1*6]);
+		smart_ulltoa6(s->vszrw   , &buf[2*6]);
+		smart_ulltoa6(s->rss     , &buf[3*6]);
+		smart_ulltoa6(s->rss_sh  , &buf[4*6]);
+		smart_ulltoa6(s->dirty   , &buf[5*6]);
+		smart_ulltoa6(s->dirty_sh, &buf[6*6]);
+		smart_ulltoa6(s->stack   , &buf[7*6]);
+		buf[8*6] = '\0';
+		if (scr_width > MIN_WIDTH) {
+			read_cmdline(&buf[8*6], scr_width - MIN_WIDTH, s->pid, s->comm);
+		}
+		printf("\n""%.*s", scr_width, buf);
+		s++;
+	}
+	putchar(OPT_BATCH_MODE ? '\n' : '\r');
+	fflush(stdout);
+#undef HDR_STR
+#undef MIN_WIDTH
+}
+#else
+void display_topmem_process_list(int count, int scr_width);
+int topmem_sort(char *a, char *b);
+#endif /* TOPMEM */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+enum {
+	TOP_MASK = 0
+		| PSSCAN_PID
+		| PSSCAN_PPID
+		| PSSCAN_VSZ
+		| PSSCAN_STIME
+		| PSSCAN_UTIME
+		| PSSCAN_STATE
+		| PSSCAN_COMM
+		| PSSCAN_UIDGID,
+	TOPMEM_MASK = 0
+		| PSSCAN_PID
+		| PSSCAN_SMAPS
+		| PSSCAN_COMM,
+};
+
 int top_main(int argc, char **argv);
 int top_main(int argc, char **argv)
 {
 	int count, lines, col;
 	unsigned interval;
-	int iterations = -1; /* infinite */
+	int iterations = 0; /* infinite */
 	char *sinterval, *siterations;
+	SKIP_FEATURE_TOPMEM(const) unsigned scan_mask = TOP_MASK;
 #if ENABLE_FEATURE_USE_TERMIOS
 	struct termios new_settings;
 	struct pollfd pfd[1];
@@ -563,62 +853,82 @@
 		procps_status_t *p = NULL;
 
 		/* Default */
-		lines = 24 - 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( - 1);
+		lines = 24;
 		col = 79;
 #if ENABLE_FEATURE_USE_TERMIOS
 		get_terminal_width_height(0, &col, &lines);
-		/* We wrap horribly if width is too narrow (TODO) */
-		if (lines < 5 || col < MIN_WIDTH) {
+		if (lines < 5 || col < 10) {
 			sleep(interval);
 			continue;
 		}
-		lines -= 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( + 1);
 #endif /* FEATURE_USE_TERMIOS */
+		if (!ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && scan_mask == TOP_MASK)
+			lines -= 3;
+		else
+			lines -= 4;
 
 		/* read process IDs & status for all the processes */
-		while ((p = procps_scan(p, 0
-				| PSSCAN_PID
-				| PSSCAN_PPID
-				| PSSCAN_VSZ
-				| PSSCAN_STIME
-				| PSSCAN_UTIME
-				| PSSCAN_STATE
-				| PSSCAN_COMM
-				| PSSCAN_UIDGID
-		)) != NULL) {
-			int n = ntop;
-			top = xrealloc(top, (++ntop) * sizeof(*top));
-			top[n].pid = p->pid;
-			top[n].ppid = p->ppid;
-			top[n].vsz = p->vsz;
+		while ((p = procps_scan(p, scan_mask)) != NULL) {
+			int n;
+			if (scan_mask == TOP_MASK) {
+				n = ntop;
+				top = xrealloc(top, (++ntop) * sizeof(*top));
+				top[n].pid = p->pid;
+				top[n].ppid = p->ppid;
+				top[n].vsz = p->vsz;
 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
-			top[n].ticks = p->stime + p->utime;
+				top[n].ticks = p->stime + p->utime;
 #endif
-			top[n].uid = p->uid;
-			strcpy(top[n].state, p->state);
-			strcpy(top[n].comm, p->comm);
+				top[n].uid = p->uid;
+				strcpy(top[n].state, p->state);
+				strcpy(top[n].comm, p->comm);
+			} else { /* TOPMEM */
+#if ENABLE_FEATURE_TOPMEM
+				if (!(p->mapped_ro | p->mapped_rw))
+					continue; /* kernel threads are ignored */
+				n = ntop;
+				top = xrealloc(topmem, (++ntop) * sizeof(*topmem));
+				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;
+#endif
+			}
 		}
 		if (ntop == 0) {
 			bb_error_msg_and_die("no process info in /proc");
 		}
+
+		if (scan_mask == TOP_MASK) {
 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
-		if (!prev_hist_count) {
+			if (!prev_hist_count) {
+				do_stats();
+				usleep(100000);
+				clearmems();
+				continue;
+			}
 			do_stats();
-			sleep(1);
-			clearmems();
-			continue;
-		}
-		do_stats();
 /* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
-		qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
+			qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
 #else
-		qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0]));
+			qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0]));
 #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
+		} else { /* TOPMEM */
+			qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
+		}
 		count = lines;
 		if (OPT_BATCH_MODE || count > ntop) {
 			count = ntop;
 		}
-		display_process_list(count, col);
+		if (scan_mask == TOP_MASK)
+			display_process_list(count, col);
+		else
+			display_topmem_process_list(count, col);
 		clearmems();
 		if (iterations >= 0 && !--iterations)
 			break;
@@ -628,11 +938,17 @@
 		if (poll(pfd, 1, interval * 1000) != 0) {
 			if (read(0, &c, 1) != 1)    /* signal */
 				break;
-			if (c == 'q' || c == initial_settings.c_cc[VINTR])
+			if (c == initial_settings.c_cc[VINTR])
 				break;
-			if (c == 'N')
+			c |= 0x20; /* lowercase */
+			if (c == 'q')
+				break;
+			if (c == 'n') {
+				USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
 				sort_function[0] = pid_sort;
-			if (c == 'M') {
+			}
+			if (c == 'm') {
+				USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
 				sort_function[0] = mem_sort;
 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
 				sort_function[1] = pcpu_sort;
@@ -640,17 +956,30 @@
 #endif
 			}
 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
-			if (c == 'P') {
+			if (c == 'p') {
+				USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
 				sort_function[0] = pcpu_sort;
 				sort_function[1] = mem_sort;
 				sort_function[2] = time_sort;
 			}
-			if (c == 'T') {
+			if (c == 't') {
+				USE_FEATURE_TOPMEM(scan_mask = TOP_MASK;)
 				sort_function[0] = time_sort;
 				sort_function[1] = mem_sort;
 				sort_function[2] = pcpu_sort;
 			}
+#if ENABLE_FEATURE_TOPMEM
+			if (c == 's') {
+				scan_mask = TOPMEM_MASK;
+				free(prev_hist);
+				prev_hist = NULL;
+				prev_hist_count = 0;
+				sort_field = (sort_field + 1) % NUM_SORT_FIELD;
+			}
+			if (c == 'r')
+				inverted ^= 1;
 #endif
+#endif
 		}
 #endif /* FEATURE_USE_TERMIOS */
 	}




More information about the busybox-cvs mailing list