Subject: bin/36542: better "systat vm" output
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: Greg A. Woods <woods@planix.com>
List: netbsd-bugs
Date: 06/23/2007 23:35:00
>Number: 36542
>Category: bin
>Synopsis: better "systat vm" output
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sat Jun 23 23:35:00 +0000 2007
>Originator: Greg A. Woods
>Release: netbsd-current 2007/06/22
>Organization:
Planix, Inc.; Toronto, Ontario; Canada
>Environment:
System: NetBSD
>Description:
this change primarily adds some of the more useful "bufcache"
values to the more commonly used "vm" output
the manual page is also cleaned up significantly
minor bug fixes are also offered
>How-To-Repeat:
>Fix:
cvs diff: Diffing usr.bin/systat
Index: usr.bin/systat/bufcache.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.bin/systat/bufcache.c,v
retrieving revision 1.20
diff -u -r1.20 bufcache.c
--- usr.bin/systat/bufcache.c 22 Oct 2006 16:43:24 -0000 1.20
+++ usr.bin/systat/bufcache.c 28 Mar 2007 02:02:11 -0000
@@ -128,8 +128,8 @@
wmove(wnd, i, 0);
wclrtoeol(wnd);
}
- mvwaddstr(wnd, PAGEINFO_ROWS + 1, 0, "File System Bufs used"
- " % kB in use % Bufsize kB % Util %");
+ mvwaddstr(wnd, PAGEINFO_ROWS + 1, 0,
+"File System Bufs used % kB in use % Bufsize kB % Util %");
wclrtoeol(wnd);
}
@@ -229,6 +229,10 @@
nlisterr(namelist);
return(0);
}
+ if (namelist[0].n_type == 0) {
+ error("No namelist");
+ return(0);
+ }
}
fetchuvmexp();
Index: usr.bin/systat/cmdtab.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.bin/systat/cmdtab.c,v
retrieving revision 1.23
diff -u -r1.23 cmdtab.c
--- usr.bin/systat/cmdtab.c 18 Feb 2007 17:00:08 -0000 1.23
+++ usr.bin/systat/cmdtab.c 22 Feb 2007 23:53:21 -0000
@@ -52,6 +52,7 @@
{ "quit", global_quit, "exit systat"},
{ "start", global_interval, "restart updating display"},
{ "stop", global_stop, "stop updating display"},
+ { "?", global_help, "show help"},
{ .c_name = NULL }
};
@@ -117,7 +118,7 @@
{ "names", netstat_names, "show names instead of addresses"},
{ "numbers", netstat_numbers, "show addresses instead of names"},
{ "reset", netstat_reset, "return to default display"},
- { "show", netstat_show, "show current display/ignore settings"},
+ { "show", netstat_show, "show current display/ignore settings"},
{ "tcp", netstat_tcp, "show only tcp connections"},
{ "udp", netstat_udp, "show only udp connections"},
{ .c_name = NULL }
Index: usr.bin/systat/main.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.bin/systat/main.c,v
retrieving revision 1.40
diff -u -r1.40 main.c
--- usr.bin/systat/main.c 22 Oct 2006 16:43:24 -0000 1.40
+++ usr.bin/systat/main.c 12 Feb 2007 17:08:11 -0000
@@ -74,7 +74,7 @@
sig_t sigtstpdfl;
double avenrun[3];
int col;
-int naptime = 5;
+int naptime = 1;
int verbose = 1; /* to report kvm read errs */
int hz, stathz, maxslp;
char c;
@@ -173,10 +173,8 @@
(void)setegid(egid);
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
- if (kd == NULL) {
- error("%s", errbuf);
- exit(1);
- }
+ if (kd == NULL)
+ errx(1, "%s", errbuf);
/* Get rid of privs for now. */
if (nlistf == NULL && memf == NULL)
@@ -201,19 +199,24 @@
* routines to minimize update work by curses.
*/
if (initscr() == NULL)
- {
- warnx("couldn't initialize screen");
- exit(0);
- }
+ errx(1, "couldn't initialize screen");
CMDLINE = LINES - 1;
wnd = (*curmode->c_open)();
if (wnd == NULL) {
+ move(CMDLINE, 0);
+ clrtoeol();
+ refresh();
+ endwin();
warnx("couldn't initialize display");
die(0);
}
wload = newwin(1, 0, 3, 20);
if (wload == NULL) {
+ move(CMDLINE, 0);
+ clrtoeol();
+ refresh();
+ endwin();
warnx("couldn't set up load average window");
die(0);
}
@@ -385,7 +388,6 @@
move(CMDLINE, 0);
clrtoeol();
refresh();
- sleep(5);
endwin();
exit(1);
}
Index: usr.bin/systat/systat.1
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.bin/systat/systat.1,v
retrieving revision 1.37
diff -u -r1.37 systat.1
--- usr.bin/systat/systat.1 18 Feb 2007 17:29:26 -0000 1.37
+++ usr.bin/systat/systat.1 22 Feb 2007 23:53:21 -0000
@@ -410,7 +410,22 @@
The upper left quadrant of the screen shows the number
of users logged in and the load average over the last one, five,
and fifteen minute intervals.
-Below this is a list of the
+Below this are statistics on memory utilization.
+The first row of the table reports memory usage only among
+active processes, that is processes that have run in the previous
+twenty seconds.
+The second row reports on memory usage of all processes.
+The first column reports on the number of physical pages
+claimed by processes.
+The second column reports the number of physical pages that
+are devoted to read only text pages.
+The third and fourth columns report the same two figures for
+virtual pages, that is the number of pages that would be
+needed if all processes had all of their pages.
+Finally the last column shows the number of physical pages
+on the free list.
+.Pp
+Below the memory display is a list of the
average number of processes (over the last refresh interval)
that are runnable (`r'), in page wait (`p'),
in disk wait other than paging (`d'),
@@ -422,9 +437,9 @@
.Pp
To the right of the process statistics is a column that
lists the average number of context switches (`Csw'),
-traps (`Trp'; includes page faults), system calls (`Sys'), interrupts (`Int'),
-network software interrupts (`Sof'),
-page faults (`Flt').
+traps (`Traps'; includes page faults), system calls (`SysCa'), interrupts (`Intr'),
+network software interrupts (`Soft'),
+page faults (`Fault').
.Pp
Below this are statistics on memory utilization.
The first row of the table reports memory usage only among
@@ -466,16 +481,75 @@
number of pages transferred per second over the last refresh interval.
.Pp
Below the paging statistics is another columns of paging data.
-From top to bottom, these represent average numbers of copy on write faults
-(`cow'), object cache lookups (`objlk'), object cache hits (`objht'),
-pages zero filled on demand (`zfodw'), number zfod's created (`nzfod'),
-percentage of zfod's used (`%zfod'), number of kernel pages (`kern'),
-number of wired pages (`wire'), number of active pages (`act'), number
-of inactive pages (`inact'), number of free pages (`free'), pages freed
-by daemon (`daefr'), pages freed by exiting processes (`prcfr'), number
-of pages reactivated from freelist (`react'), scans in page out daemon
-(`scan'), revolutions of the hand (`hdrev'), and in-transit blocking page
-faults (`intrn'), per second over the refresh period.
+From top to bottom, these represent:
+.Pp
+.Bl -tag -width Fl -compact
+.It Ic Sq forks
+number of fork() calls
+.It Ic Sq fkppw
+number of fork() calls where parent waits
+.It Ic Sq fksvm
+number of fork() calls where vmspace is shared
+.It Ic Sq pwait
+number of times fault had to wait on a page
+.It Ic Sq relck
+number of times uvmfault_relock() is called
+.It Ic Sq rlkok
+number of times uvmfault_relock() is a success
+.It Ic Sq noram
+number of times fault was out of RAM
+.It Ic Sq ndcpy
+number of times fault clears ``needs copy''
+.It Ic Sq fltcp
+number of times fault promotes with copy (2b)
+.It Ic Sq zfod
+number of times fault promotes with zerofill (2b)
+.It Ic Sq cow
+number of times faulted for anonymous for Copy-On-Write (case 1b)
+.It Ic Sq fmin
+min number of free pages
+.It Ic Sq ftarg
+target number of free pages
+.It Ic Sq itarg
+target number of inactive pages
+.\".It Ic Sq objlk
+.\"object cache lookups
+.\".It Ic Sq objht
+.\"object cache hits
+.\".It Ic Sq zfodw
+.\"pages zero filled on demand
+.\".It Ic Sq nzfod
+.\"number of zfod's created
+.\".It Ic Sq %zfod
+.\"percentage of zfod's used
+.\".It Ic Sq kern
+.\"number of kernel pages
+.It Ic Sq flnan
+number of times fault was out of anonymous pages
+.\".It Ic Sq act
+.\"number of active pages
+.\".It Ic Sq inact
+.\"number of inactive pages
+.\".It Ic Sq free
+.\"number of free pages
+.\".It Ic Sq daefr
+.\"pages freed by daemon
+.\".It Ic Sq prcfr
+.\"pages freed by exiting processes
+.\".It Ic Sq react
+.\"number of pages reactivated from freelist
+.\".It Ic Sq scan
+.\"scans in page out daemon
+.\".It Ic Sq hdrev
+.\"revolutions of the hand
+.\".It Ic Sq intrn
+.\"in-transit blocking page faults per second over the refresh period.
+.It Ic Sq pdfre
+number of pages daemon freed since boot
+.It Ic Sq pdscn
+number of pages daemon scaned since boot
+.El
+.Pp
Note that the `%zfod' percentage is usually less than 100%,
however it may exceed 100% if a large number of requests
are actually used long after they were set up during a
Index: usr.bin/systat/systat.h
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.bin/systat/systat.h,v
retrieving revision 1.11
diff -u -r1.11 systat.h
--- usr.bin/systat/systat.h 26 Feb 2005 22:12:34 -0000 1.11
+++ usr.bin/systat/systat.h 11 Feb 2007 22:29:35 -0000
@@ -61,4 +61,3 @@
#define NVAL(indx) namelist[(indx)].n_value
#define NPTR(indx) (void *)NVAL((indx))
#define NREAD(indx, buf, len) kvm_ckread(NPTR((indx)), (buf), (len), # indx)
-#define LONG (sizeof (long))
Index: usr.bin/systat/vmstat.c
===================================================================
RCS file: /cvs/master/m-NetBSD/main/src/usr.bin/systat/vmstat.c,v
retrieving revision 1.69
diff -u -r1.69 vmstat.c
--- usr.bin/systat/vmstat.c 22 Oct 2006 16:43:24 -0000 1.69
+++ usr.bin/systat/vmstat.c 28 Mar 2007 17:56:32 -0000
@@ -87,6 +87,7 @@
static char **intrname;
static int nextintsrow;
static int disk_horiz = 1;
+static u_int nbuf;
WINDOW *
openvmstat(void)
@@ -118,7 +119,6 @@
{ .n_name = "_eintrcnt" },
#define X_ALLEVENTS 5
{ .n_name = "_allevents" },
- { .n_name = NULL }
};
/*
@@ -126,7 +126,7 @@
*/
#define STATROW 0 /* uses 1 row and 68 cols */
#define STATCOL 2
-#define MEMROW 9 /* uses 4 rows and 31 cols */
+#define MEMROW 9 /* uses 5 rows and 31 cols */
#define MEMCOL 0
#define PAGEROW 2 /* uses 4 rows and 26 cols */
#define PAGECOL 54
@@ -141,9 +141,9 @@
#define VMSTATCOL 64
#define GRAPHROW 5 /* uses 3 rows and 51 cols */
#define GRAPHCOL 0
-#define NAMEIROW 14 /* uses 3 rows and 38 cols */
+#define NAMEIROW 15 /* uses 3 rows and 38 cols (must be MEMROW + 5 + 1) */
#define NAMEICOL 0
-#define DISKROW 18 /* uses 5 rows and 50 cols (for 9 drives) */
+#define DISKROW 19 /* uses 5 rows and 50 cols (for 9 drives) */
#define DISKCOL 0
#define DISKCOLWIDTH 6
#define DISKCOLEND INTSCOL
@@ -325,7 +325,7 @@
mvprintw(STATROW, STATCOL + 4, "users Load");
- mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt");
+ mvprintw(GENSTATROW, GENSTATCOL, " Csw Traps SysCal Intr Soft Fault");
mvprintw(GRAPHROW, GRAPHCOL,
" . %% Sy . %% Us . %% Ni . %% In . %% Id");
@@ -335,8 +335,8 @@
mvprintw(PAGEROW, PAGECOL + 8, "PAGING SWAPPING ");
mvprintw(PAGEROW + 1, PAGECOL, " in out in out ");
- mvprintw(PAGEROW + 2, PAGECOL + 2, "ops");
- mvprintw(PAGEROW + 3, PAGECOL, "pages");
+ mvprintw(PAGEROW + 2, PAGECOL, " ops ");
+ mvprintw(PAGEROW + 3, PAGECOL, "pages ");
}
void
@@ -350,10 +350,12 @@
/* Left hand column */
- mvprintw(MEMROW, MEMCOL, " memory totals (in kB)");
- mvprintw(MEMROW + 1, MEMCOL, " real virtual free");
- mvprintw(MEMROW + 2, MEMCOL, "Active");
- mvprintw(MEMROW + 3, MEMCOL, "All");
+ mvprintw(MEMROW + 0, MEMCOL, "Anon %% zero ");
+ mvprintw(MEMROW + 1, MEMCOL, "Exec %% wired ");
+ mvprintw(MEMROW + 2, MEMCOL, "File %% inact ");
+ mvprintw(MEMROW + 3, MEMCOL, "Meta %% bufs ");
+ mvprintw(MEMROW + 4, MEMCOL, " (kB) real swaponly free");
+ mvprintw(MEMROW + 5, MEMCOL, "Active ");
mvprintw(NAMEIROW, NAMEICOL, "Namei Sys-cache Proc-cache");
mvprintw(NAMEIROW + 1, NAMEICOL,
@@ -403,7 +405,7 @@
mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "fmin");
mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "ftarg");
mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "itarg");
- mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "wired");
+ mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "flnan");
mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "pdfre");
if (LINES - 1 > VMSTATROW + 16)
@@ -455,6 +457,11 @@
PUTRATE(us, us1, uvmexp->softs, GENSTATROW + 1, GENSTATCOL + 27, 5);
PUTRATE(us, us1, uvmexp->faults, GENSTATROW + 1, GENSTATCOL + 33, 6);
+ /*
+ * XXX it sure would be nice if this did what top(1) does and showed
+ * the utilization of each CPU on a separate line, though perhaps IFF
+ * the screen is tall enough
+ */
/* Last CPU state not calculated yet. */
for (f2 = 0.0, psiz = 0, c = 0; c < CPUSTATES; c++) {
i = cpuorder[c];
@@ -486,6 +493,11 @@
static int relabel = 0;
static int last_disks = 0;
static char pigs[] = "pigs";
+ static u_long bufmem;
+ struct buf_sysctl *buffers;
+ int mib[6];
+ size_t size;
+ int extraslop = 0;
if (relabel) {
labelvmstat();
@@ -517,15 +529,74 @@
/* Memory totals */
#define pgtokb(pg) ((pg) * (s.uvmexp.pagesize / 1024))
- putint(pgtokb(s.uvmexp.active), MEMROW + 2, MEMCOL + 6, 8);
- putint(pgtokb(s.uvmexp.active + s.uvmexp.swpginuse), /* XXX */
- MEMROW + 2, MEMCOL + 15, 8);
- putint(pgtokb(s.uvmexp.npages - s.uvmexp.free), MEMROW + 3, MEMCOL + 6, 8);
- putint(pgtokb(s.uvmexp.npages - s.uvmexp.free + s.uvmexp.swpginuse),
- MEMROW + 3, MEMCOL + 15, 8);
- putint(pgtokb(s.uvmexp.free), MEMROW + 2, MEMCOL + 24, 8);
- putint(pgtokb(s.uvmexp.free + s.uvmexp.swpages - s.uvmexp.swpginuse),
- MEMROW + 3, MEMCOL + 24, 8);
+
+ putint(pgtokb(s.uvmexp.anonpages), MEMROW + 0, MEMCOL + 7, 10);
+ putint((s.uvmexp.anonpages * 100 + 0.5) / s.uvmexp.npages, MEMROW + 0, MEMCOL + 17, 4);
+
+ putint(pgtokb(s.uvmexp.zeropages), MEMROW + 0, MEMCOL + 30, 8);
+
+ putint(pgtokb(s.uvmexp.execpages), MEMROW + 1, MEMCOL + 7, 10);
+ putint((s.uvmexp.execpages * 100 + 0.5) / s.uvmexp.npages, MEMROW + 1, MEMCOL + 17, 4);
+
+ putint(pgtokb(s.uvmexp.wired), MEMROW + 1, MEMCOL + 30, 8);
+
+ putint(pgtokb(s.uvmexp.filepages), MEMROW + 2, MEMCOL + 7, 10);
+ putint((s.uvmexp.filepages * 100 + 0.5) / s.uvmexp.npages, MEMROW + 2, MEMCOL + 17, 4);
+
+ putint(pgtokb(s.uvmexp.inactive), MEMROW + 2, MEMCOL + 30, 8);
+
+ /* Get total size of metadata buffers */
+ size = sizeof(bufmem);
+ if (sysctlbyname("vm.bufmem", &bufmem, &size, NULL, 0) < 0) {
+ error("can't get buffers size: %s\n", strerror(errno));
+ return;
+ }
+
+ /* Get number of metadata buffers */
+ size = 0;
+ buffers = NULL;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BUF;
+ mib[2] = KERN_BUF_ALL;
+ mib[3] = KERN_BUF_ALL;
+ mib[4] = (int)sizeof(struct buf_sysctl);
+ mib[5] = INT_MAX; /* we want them all */
+again:
+ if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
+ error("can't get buffers size: %s\n", strerror(errno));
+ return;
+ }
+ if (size == 0) {
+ error("buffers size is zero: %s\n", strerror(errno));
+ return;
+ }
+ size += extraslop * sizeof(struct buf_sysctl);
+ buffers = malloc(size);
+ if (buffers == NULL) {
+ error("can't allocate buffers: %s\n", strerror(errno));
+ return;
+ }
+ if (sysctl(mib, 6, buffers, &size, NULL, 0) < 0) {
+ free(buffers);
+ if (extraslop == 0) {
+ extraslop = 100;
+ goto again;
+ }
+ error("can't get buffers: %s\n", strerror(errno));
+ return;
+ }
+ free(buffers); /* XXX there must be a better way! */
+ nbuf = size / sizeof(struct buf_sysctl);
+
+ putint((int) (bufmem / 1024), MEMROW + 3, MEMCOL + 5, 12);
+ putint((int) ((bufmem * 100) + 0.5) / s.uvmexp.pagesize / s.uvmexp.npages,
+ MEMROW + 3, MEMCOL + 17, 4);
+ putint(nbuf, MEMROW + 3, MEMCOL + 30, 8);
+
+ putint(pgtokb(s.uvmexp.active), MEMROW + 5, MEMCOL + 7, 10);
+ putint(pgtokb(s.uvmexp.swpgonly), MEMROW + 5, MEMCOL + 18, 10);
+ putint(pgtokb(s.uvmexp.free), MEMROW + 5, MEMCOL + 28, 10);
+
#undef pgtokb
/* Namei cache */
@@ -641,7 +712,7 @@
putint(s.uvmexp.freemin, VMSTATROW + 11, VMSTATCOL, 9);
putint(s.uvmexp.freetarg, VMSTATROW + 12, VMSTATCOL, 9);
putint(s.uvmexp.inactarg, VMSTATROW + 13, VMSTATCOL, 9);
- putint(s.uvmexp.wired, VMSTATROW + 14, VMSTATCOL, 9);
+ putint(s.uvmexp.fltnoanon, VMSTATROW + 14, VMSTATCOL, 9);
PUTRATE(s, s1, uvmexp.pdfreed, VMSTATROW + 15, VMSTATCOL, 9);
if (LINES - 1 > VMSTATROW + 16)
PUTRATE(s, s1, uvmexp.pdscans, VMSTATROW + 16, VMSTATCOL, 9);
@@ -784,7 +855,7 @@
drvreadstats();
NREAD(X_NCHSTATS, &stats->nchstats, sizeof stats->nchstats);
if (nintr)
- NREAD(X_INTRCNT, stats->intrcnt, nintr * LONG);
+ NREAD(X_INTRCNT, stats->intrcnt, nintr * sizeof(long));
for (i = 0; i < nevcnt; i++)
KREAD(ie_head[i].ie_count, &stats->evcnt[i],
sizeof stats->evcnt[i]);
>Unformatted: