aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--procps/top.c196
1 files changed, 86 insertions, 110 deletions
diff --git a/procps/top.c b/procps/top.c
index 530f45fa1..62f9421af 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -499,85 +499,94 @@ static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p)
499# define display_cpus(scr_width, scrbuf, lines_rem) ((void)0) 499# define display_cpus(scr_width, scrbuf, lines_rem) ((void)0)
500#endif 500#endif
501 501
502static unsigned long display_header(int scr_width, int *lines_rem_p) 502enum {
503{ 503 MI_MEMTOTAL,
504 FILE *fp; 504 MI_MEMFREE,
505 char buf[80]; 505 MI_MEMSHARED,
506 char scrbuf[80]; 506 MI_SHMEM,
507 unsigned long total, used, mfree, shared, buffers, cached; 507 MI_BUFFERS,
508 MI_CACHED,
509 MI_SWAPTOTAL,
510 MI_SWAPFREE,
511 MI_DIRTY,
512 MI_WRITEBACK,
513 MI_ANONPAGES,
514 MI_MAPPED,
515 MI_SLAB,
516 MI_MAX
517};
508 518
509 /* read memory info */ 519static void parse_meminfo(unsigned long meminfo[MI_MAX])
510 fp = xfopen_for_read("meminfo"); 520{
521 static const char fields[] =
522 "MemTotal\0"
523 "MemFree\0"
524 "MemShared\0"
525 "Shmem\0"
526 "Buffers\0"
527 "Cached\0"
528 "SwapTotal\0"
529 "SwapFree\0"
530 "Dirty\0"
531 "Writeback\0"
532 "AnonPages\0"
533 "Mapped\0"
534 "Slab\0";
535 char buf[60]; /* actual lines we expect are ~30 chars or less */
536 FILE *f;
537 int i;
511 538
512 /* 539 memset(meminfo, 0, sizeof(meminfo));
513 * Old kernels (such as 2.4.x) had a nice summary of memory info that 540 f = xfopen_for_read("meminfo");
514 * we could parse, however this is gone entirely in 2.6. Try parsing 541 while (fgets(buf, sizeof(buf), f) != NULL) {
515 * the old way first, and if that fails, parse each field manually. 542 char *c = strchr(buf, ':');
516 * 543 if (!c)
517 * First, we read in the first line. Old kernels will have bogus 544 continue;
518 * strings we don't care about, whereas new kernels will start right 545 *c = '\0';
519 * out with MemTotal: 546 i = index_in_strings(fields, buf);
520 * -- PFM. 547 if (i >= 0)
521 */ 548 meminfo[i] = strtoul(c+1, NULL, 10);
522 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) { 549 }
523 fgets(buf, sizeof(buf), fp); /* skip first line */ 550 fclose(f);
524 551}
525 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
526 &total, &used, &mfree, &shared, &buffers, &cached);
527 /* convert to kilobytes */
528 used /= 1024;
529 mfree /= 1024;
530 shared /= 1024;
531 buffers /= 1024;
532 cached /= 1024;
533 total /= 1024;
534 } else {
535 /*
536 * Revert to manual parsing, which incidentally already has the
537 * sizes in kilobytes. This should be safe for both 2.4 and
538 * 2.6.
539 */
540 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
541 552
542 /*
543 * MemShared: is no longer present in 2.6. Report this as 0,
544 * to maintain consistent behavior with normal procps.
545 */
546 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
547 shared = 0;
548 553
549 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf); 554static unsigned long display_header(int scr_width, int *lines_rem_p)
550 fscanf(fp, "Cached: %lu %s\n", &cached, buf); 555{
556 char scrbuf[100]; /* [80] was a bit too low on 8Gb ram box */
557 char *buf;
558 unsigned long meminfo[MI_MAX];
551 559
552 used = total - mfree; 560 parse_meminfo(meminfo);
553 }
554 fclose(fp);
555 561
556 /* output memory info */ 562 /* Output memory info */
557 if (scr_width > (int)sizeof(scrbuf)) 563 if (scr_width > (int)sizeof(scrbuf))
558 scr_width = sizeof(scrbuf); 564 scr_width = sizeof(scrbuf);
559 snprintf(scrbuf, scr_width, 565 snprintf(scrbuf, scr_width,
560 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached", 566 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
561 used, mfree, shared, buffers, cached); 567 meminfo[MI_MEMTOTAL] - meminfo[MI_MEMFREE],
562 /* go to top & clear to the end of screen */ 568 meminfo[MI_MEMFREE],
569 meminfo[MI_MEMSHARED] + meminfo[MI_SHMEM],
570 meminfo[MI_BUFFERS],
571 meminfo[MI_CACHED]);
572 /* Go to top & clear to the end of screen */
563 printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf); 573 printf(OPT_BATCH_MODE ? "%s\n" : "\033[H\033[J%s\n", scrbuf);
564 (*lines_rem_p)--; 574 (*lines_rem_p)--;
565 575
566 /* Display CPU time split as percentage of total time 576 /* Display CPU time split as percentage of total time.
567 * This displays either a cumulative line or one line per CPU 577 * This displays either a cumulative line or one line per CPU.
568 */ 578 */
569 display_cpus(scr_width, scrbuf, lines_rem_p); 579 display_cpus(scr_width, scrbuf, lines_rem_p);
570 580
571 /* read load average as a string */ 581 /* Read load average as a string */
572 buf[0] = '\0'; 582 buf = stpcpy(scrbuf, "Load average: ");
573 open_read_close("loadavg", buf, sizeof(buf) - 1); 583 open_read_close("loadavg", buf, sizeof(scrbuf) - sizeof("Load average: "));
574 buf[sizeof(buf) - 1] = '\n'; 584 scrbuf[scr_width - 1] = '\0';
575 *strchr(buf, '\n') = '\0'; 585 strchrnul(buf, '\n')[0] = '\0';
576 snprintf(scrbuf, scr_width, "Load average: %s", buf);
577 puts(scrbuf); 586 puts(scrbuf);
578 (*lines_rem_p)--; 587 (*lines_rem_p)--;
579 588
580 return total; 589 return meminfo[MI_MEMTOTAL];
581} 590}
582 591
583static NOINLINE void display_process_list(int lines_rem, int scr_width) 592static NOINLINE void display_process_list(int lines_rem, int scr_width)
@@ -781,64 +790,31 @@ static int topmem_sort(char *a, char *b)
781/* display header info (meminfo / loadavg) */ 790/* display header info (meminfo / loadavg) */
782static void display_topmem_header(int scr_width, int *lines_rem_p) 791static void display_topmem_header(int scr_width, int *lines_rem_p)
783{ 792{
784 enum { 793 unsigned long meminfo[MI_MAX];
785 TOTAL = 0, MFREE, BUF, CACHE, 794
786 SWAPTOTAL, SWAPFREE, DIRTY, 795 parse_meminfo(meminfo);
787 MWRITE, ANON, MAP, SLAB,
788 NUM_FIELDS
789 };
790 static const char match[NUM_FIELDS][12] = {
791 "\x09" "MemTotal:", // TOTAL
792 "\x08" "MemFree:", // MFREE
793 "\x08" "Buffers:", // BUF
794 "\x07" "Cached:", // CACHE
795 "\x0a" "SwapTotal:", // SWAPTOTAL
796 "\x09" "SwapFree:", // SWAPFREE
797 "\x06" "Dirty:", // DIRTY
798 "\x0a" "Writeback:", // MWRITE
799 "\x0a" "AnonPages:", // ANON
800 "\x07" "Mapped:", // MAP
801 "\x05" "Slab:", // SLAB
802 };
803 char meminfo_buf[4 * 1024];
804 const char *Z[NUM_FIELDS];
805 unsigned i;
806 int sz;
807
808 for (i = 0; i < NUM_FIELDS; i++)
809 Z[i] = "?";
810
811 /* read memory info */
812 sz = open_read_close("meminfo", meminfo_buf, sizeof(meminfo_buf) - 1);
813 if (sz >= 0) {
814 char *p = meminfo_buf;
815 meminfo_buf[sz] = '\0';
816 /* Note that fields always appear in the match[] order */
817 for (i = 0; i < NUM_FIELDS; i++) {
818 char *found = strstr(p, match[i] + 1);
819 if (found) {
820 /* Cut "NNNN" out of " NNNN kb" */
821 char *s = skip_whitespace(found + match[i][0]);
822 p = skip_non_whitespace(s);
823 *p++ = '\0';
824 Z[i] = s;
825 }
826 }
827 }
828 796
829 snprintf(line_buf, LINE_BUF_SIZE, 797 snprintf(line_buf, LINE_BUF_SIZE,
830 "Mem total:%s anon:%s map:%s free:%s", 798 "Mem total:%lu anon:%lu map:%lu free:%lu",
831 Z[TOTAL], Z[ANON], Z[MAP], Z[MFREE]); 799 meminfo[MI_MEMTOTAL],
800 meminfo[MI_ANONPAGES],
801 meminfo[MI_MAPPED],
802 meminfo[MI_MEMFREE]);
832 printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, line_buf); 803 printf(OPT_BATCH_MODE ? "%.*s\n" : "\033[H\033[J%.*s\n", scr_width, line_buf);
833 804
834 snprintf(line_buf, LINE_BUF_SIZE, 805 snprintf(line_buf, LINE_BUF_SIZE,
835 " slab:%s buf:%s cache:%s dirty:%s write:%s", 806 " slab:%lu buf:%lu cache:%lu dirty:%lu write:%lu",
836 Z[SLAB], Z[BUF], Z[CACHE], Z[DIRTY], Z[MWRITE]); 807 meminfo[MI_SLAB],
808 meminfo[MI_BUFFERS],
809 meminfo[MI_CACHED],
810 meminfo[MI_DIRTY],
811 meminfo[MI_WRITEBACK]);
837 printf("%.*s\n", scr_width, line_buf); 812 printf("%.*s\n", scr_width, line_buf);
838 813
839 snprintf(line_buf, LINE_BUF_SIZE, 814 snprintf(line_buf, LINE_BUF_SIZE,
840 "Swap total:%s free:%s", // TODO: % used? 815 "Swap total:%lu free:%lu", // TODO: % used?
841 Z[SWAPTOTAL], Z[SWAPFREE]); 816 meminfo[MI_SWAPTOTAL],
817 meminfo[MI_SWAPFREE]);
842 printf("%.*s\n", scr_width, line_buf); 818 printf("%.*s\n", scr_width, line_buf);
843 819
844 (*lines_rem_p) -= 3; 820 (*lines_rem_p) -= 3;