[PATCH] top: fix parsing of /proc/meminfo

Timo Teräs timo.teras at iki.fi
Fri Jul 18 19:07:06 UTC 2014


and do it in smaller code:

function                                             old     new   delta
.rodata                                           120254  120205     -49
display_process_list                                1705    1563    -142
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-191)           Total: -191 bytes

Signed-off-by: Timo Teräs <timo.teras at iki.fi>
---
 procps/top.c | 80 +++++++++++++++++++++++++++++++++---------------------------
 1 file changed, 44 insertions(+), 36 deletions(-)

diff --git a/procps/top.c b/procps/top.c
index 530f45f..e60dab6 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -501,10 +501,27 @@ static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)
 
 static unsigned long display_header(int scr_width, int *lines_rem_p)
 {
+	static const char *fields =
+		"MemTotal\0"
+		"MemFree\0"
+		"Shmem\0"
+		"Buffers\0"
+		"Cached\0"
+		"Mem\0";
+	enum {
+		Hdr_Total,
+		Hdr_Free,
+		Hdr_Shared,
+		Hdr_Buffers,
+		Hdr_Cached,
+		Hdr_Legacy,
+		Hdr_Used,
+		Hdr_Max
+	};
 	FILE *fp;
-	char buf[80];
-	char scrbuf[80];
-	unsigned long total, used, mfree, shared, buffers, cached;
+	char scrbuf[80], buf[80], *c;
+	unsigned long vals[Hdr_Max];
+	int i;
 
 	/* read memory info */
 	fp = xfopen_for_read("meminfo");
@@ -519,38 +536,28 @@ static unsigned long display_header(int scr_width, int *lines_rem_p)
 	 * out with MemTotal:
 	 *                              -- PFM.
 	 */
-	if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
-		fgets(buf, sizeof(buf), fp);    /* skip first line */
-
-		fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
-			&total, &used, &mfree, &shared, &buffers, &cached);
-		/* convert to kilobytes */
-		used /= 1024;
-		mfree /= 1024;
-		shared /= 1024;
-		buffers /= 1024;
-		cached /= 1024;
-		total /= 1024;
-	} else {
-		/*
-		 * Revert to manual parsing, which incidentally already has the
-		 * sizes in kilobytes. This should be safe for both 2.4 and
-		 * 2.6.
-		 */
-		fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
-
-		/*
-		 * MemShared: is no longer present in 2.6. Report this as 0,
-		 * to maintain consistent behavior with normal procps.
-		 */
-		if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
-			shared = 0;
-
-		fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
-		fscanf(fp, "Cached: %lu %s\n", &cached, buf);
-
-		used = total - mfree;
+	memset(vals, 0, sizeof(vals));
+	while (fgets(buf, sizeof(buf), fp)) {
+		c = strchr(buf, ':');
+		if (!c) continue;
+		*c = 0;
+
+		i = index_in_strings(fields, buf);
+		if (i < 0) continue;
+		if (i == Hdr_Legacy) {
+			sscanf(c+1, "%lu %lu %lu %lu %lu %lu",
+				&vals[Hdr_Total], &vals[Hdr_Used],
+				&vals[Hdr_Free], &vals[Hdr_Shared],
+				&vals[Hdr_Buffers], &vals[Hdr_Cached]);
+			/* convert to kilobytes */
+			for (i = 0; i < Hdr_Max; i++)
+				vals[i] /= 1024;
+			goto got_meminfo;
+		}
+		vals[i] = strtoul(c+1, NULL, 0);
 	}
+	vals[Hdr_Used] = vals[Hdr_Total] - vals[Hdr_Free];
+got_meminfo:
 	fclose(fp);
 
 	/* output memory info */
@@ -558,7 +565,8 @@ static unsigned long display_header(int scr_width, int *lines_rem_p)
 		scr_width = sizeof(scrbuf);
 	snprintf(scrbuf, scr_width,
 		"Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
-		used, mfree, shared, buffers, cached);
+		vals[Hdr_Used], vals[Hdr_Free], vals[Hdr_Shared],
+		vals[Hdr_Buffers], vals[Hdr_Cached]);
 	/* go to top & clear to the end of screen */
 	printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf);
 	(*lines_rem_p)--;
@@ -577,7 +585,7 @@ static unsigned long display_header(int scr_width, int *lines_rem_p)
 	puts(scrbuf);
 	(*lines_rem_p)--;
 
-	return total;
+	return vals[Hdr_Total];
 }
 
 static NOINLINE void display_process_list(int lines_rem, int scr_width)
-- 
2.0.2



More information about the busybox mailing list