# define display_cpus(scr_width, scrbuf, lines_rem) ((void)0)
#endif
-static unsigned long display_header(int scr_width, int *lines_rem_p)
-{
- FILE *fp;
- char buf[80];
- char scrbuf[80];
- unsigned long total, used, mfree, shared, buffers, cached;
+enum {
+ MI_MEMTOTAL,
+ MI_MEMFREE,
+ MI_MEMSHARED,
+ MI_SHMEM,
+ MI_BUFFERS,
+ MI_CACHED,
+ MI_SWAPTOTAL,
+ MI_SWAPFREE,
+ MI_DIRTY,
+ MI_WRITEBACK,
+ MI_ANONPAGES,
+ MI_MAPPED,
+ MI_SLAB,
+ MI_MAX
+};
- /* read memory info */
- fp = xfopen_for_read("meminfo");
+static void parse_meminfo(unsigned long meminfo[MI_MAX])
+{
+ static const char fields[] =
+ "MemTotal\0"
+ "MemFree\0"
+ "MemShared\0"
+ "Shmem\0"
+ "Buffers\0"
+ "Cached\0"
+ "SwapTotal\0"
+ "SwapFree\0"
+ "Dirty\0"
+ "Writeback\0"
+ "AnonPages\0"
+ "Mapped\0"
+ "Slab\0";
+ char buf[60]; /* actual lines we expect are ~30 chars or less */
+ FILE *f;
+ int i;
- /*
- * Old kernels (such as 2.4.x) had a nice summary of memory info that
- * we could parse, however this is gone entirely in 2.6. Try parsing
- * the old way first, and if that fails, parse each field manually.
- *
- * First, we read in the first line. Old kernels will have bogus
- * strings we don't care about, whereas new kernels will start right
- * 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);
+ memset(meminfo, 0, sizeof(meminfo));
+ f = xfopen_for_read("meminfo");
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ char *c = strchr(buf, ':');
+ if (!c)
+ continue;
+ *c = '\0';
+ i = index_in_strings(fields, buf);
+ if (i >= 0)
+ meminfo[i] = strtoul(c+1, NULL, 10);
+ }
+ fclose(f);
+}
- /*
- * 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);
+static unsigned long display_header(int scr_width, int *lines_rem_p)
+{
+ char scrbuf[100]; /* [80] was a bit too low on 8Gb ram box */
+ char *buf;
+ unsigned long meminfo[MI_MAX];
- used = total - mfree;
- }
- fclose(fp);
+ parse_meminfo(meminfo);
- /* output memory info */
+ /* Output memory info */
if (scr_width > (int)sizeof(scrbuf))
scr_width = sizeof(scrbuf);
snprintf(scrbuf, scr_width,
"Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
- used, mfree, shared, buffers, cached);
- /* go to top & clear to the end of screen */
+ meminfo[MI_MEMTOTAL] - meminfo[MI_MEMFREE],
+ meminfo[MI_MEMFREE],
+ meminfo[MI_MEMSHARED] + meminfo[MI_SHMEM],
+ meminfo[MI_BUFFERS],
+ meminfo[MI_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)--;
- /* Display CPU time split as percentage of total time
- * This displays either a cumulative line or one line per CPU
+ /* Display CPU time split as percentage of total time.
+ * This displays either a cumulative line or one line per CPU.
*/
display_cpus(scr_width, scrbuf, lines_rem_p);
- /* read load average as a string */
- buf[0] = '\0';
- open_read_close("loadavg", buf, sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\n';
- *strchr(buf, '\n') = '\0';
- snprintf(scrbuf, scr_width, "Load average: %s", buf);
+ /* Read load average as a string */
+ buf = stpcpy(scrbuf, "Load average: ");
+ open_read_close("loadavg", buf, sizeof(scrbuf) - sizeof("Load average: "));
+ scrbuf[scr_width - 1] = '\0';
+ strchrnul(buf, '\n')[0] = '\0';
puts(scrbuf);
(*lines_rem_p)--;
- return total;
+ return meminfo[MI_MEMTOTAL];
}
static NOINLINE void display_process_list(int lines_rem, int scr_width)
/* display header info (meminfo / loadavg) */
static void display_topmem_header(int scr_width, int *lines_rem_p)
{
- enum {
- TOTAL = 0, MFREE, BUF, CACHE,
- SWAPTOTAL, SWAPFREE, DIRTY,
- MWRITE, ANON, MAP, SLAB,
- NUM_FIELDS
- };
- static const char match[NUM_FIELDS][12] = {
- "\x09" "MemTotal:", // TOTAL
- "\x08" "MemFree:", // MFREE
- "\x08" "Buffers:", // BUF
- "\x07" "Cached:", // CACHE
- "\x0a" "SwapTotal:", // SWAPTOTAL
- "\x09" "SwapFree:", // SWAPFREE
- "\x06" "Dirty:", // DIRTY
- "\x0a" "Writeback:", // MWRITE
- "\x0a" "AnonPages:", // ANON
- "\x07" "Mapped:", // MAP
- "\x05" "Slab:", // SLAB
- };
- char meminfo_buf[4 * 1024];
- const char *Z[NUM_FIELDS];
- unsigned i;
- int sz;
-
- for (i = 0; i < NUM_FIELDS; i++)
- Z[i] = "?";
-
- /* read memory info */
- sz = open_read_close("meminfo", meminfo_buf, sizeof(meminfo_buf) - 1);
- if (sz >= 0) {
- char *p = meminfo_buf;
- meminfo_buf[sz] = '\0';
- /* Note that fields always appear in the match[] order */
- for (i = 0; i < NUM_FIELDS; i++) {
- char *found = strstr(p, match[i] + 1);
- if (found) {
- /* Cut "NNNN" out of " NNNN kb" */
- char *s = skip_whitespace(found + match[i][0]);
- p = skip_non_whitespace(s);
- *p++ = '\0';
- Z[i] = s;
- }
- }
- }
+ unsigned long meminfo[MI_MAX];
+
+ parse_meminfo(meminfo);
snprintf(line_buf, LINE_BUF_SIZE,
- "Mem total:%s anon:%s map:%s free:%s",
- Z[TOTAL], Z[ANON], Z[MAP], Z[MFREE]);
+ "Mem total:%lu anon:%lu map:%lu free:%lu",
+ meminfo[MI_MEMTOTAL],
+ meminfo[MI_ANONPAGES],
+ meminfo[MI_MAPPED],
+ meminfo[MI_MEMFREE]);
printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, line_buf);
snprintf(line_buf, LINE_BUF_SIZE,
- " slab:%s buf:%s cache:%s dirty:%s write:%s",
- Z[SLAB], Z[BUF], Z[CACHE], Z[DIRTY], Z[MWRITE]);
+ " slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu",
+ meminfo[MI_SLAB],
+ meminfo[MI_BUFFERS],
+ meminfo[MI_CACHED],
+ meminfo[MI_DIRTY],
+ meminfo[MI_WRITEBACK]);
printf("%.*s\n", scr_width, line_buf);
snprintf(line_buf, LINE_BUF_SIZE,
- "Swap total:%s free:%s", // TODO: % used?
- Z[SWAPTOTAL], Z[SWAPFREE]);
+ "Swap total:%lu free:%lu", // TODO: % used?
+ meminfo[MI_SWAPTOTAL],
+ meminfo[MI_SWAPFREE]);
printf("%.*s\n", scr_width, line_buf);
(*lines_rem_p) -= 3;