Extend "systat vm" output to provide better insight about buffercache and

document it.

From Greg A. Woods in PR bin/36542
This commit is contained in:
sevan 2018-12-26 01:47:37 +00:00
parent 41d71c6b2c
commit 5a5cdfa229
6 changed files with 214 additions and 67 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bufcache.c,v 1.28 2017/06/09 00:13:29 chs Exp $ */
/* $NetBSD: bufcache.c,v 1.29 2018/12/26 01:47:37 sevan Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: bufcache.c,v 1.28 2017/06/09 00:13:29 chs Exp $");
__RCSID("$NetBSD: bufcache.c,v 1.29 2018/12/26 01:47:37 sevan Exp $");
#endif /* not lint */
#include <sys/param.h>
@ -117,8 +117,8 @@ labelbufcache(void)
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);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: cmdtab.c,v 1.25 2016/08/02 15:56:09 scole Exp $ */
/* $NetBSD: cmdtab.c,v 1.26 2018/12/26 01:47:37 sevan Exp $ */
/*-
* Copyright (c) 1980, 1992, 1993
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
#endif
__RCSID("$NetBSD: cmdtab.c,v 1.25 2016/08/02 15:56:09 scole Exp $");
__RCSID("$NetBSD: cmdtab.c,v 1.26 2018/12/26 01:47:37 sevan Exp $");
#endif /* not lint */
#include "systat.h"
@ -52,6 +52,7 @@ struct command global_commands[] = {
{ "quit", global_quit, "exit systat"},
{ "start", global_interval, "restart updating display"},
{ "stop", global_stop, "stop updating display"},
{ "?", global_help, "show help"},
{ .c_name = NULL }
};
@ -114,7 +115,7 @@ struct command netstat_commands[] = {
{ "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 }

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.53 2017/11/22 02:52:42 snj Exp $ */
/* $NetBSD: main.c,v 1.54 2018/12/26 01:47:37 sevan Exp $ */
/*-
* Copyright (c) 1980, 1992, 1993
@ -36,7 +36,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\
#if 0
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
#endif
__RCSID("$NetBSD: main.c,v 1.53 2017/11/22 02:52:42 snj Exp $");
__RCSID("$NetBSD: main.c,v 1.54 2018/12/26 01:47:37 sevan Exp $");
#endif /* not lint */
#include <sys/param.h>
@ -66,7 +66,7 @@ char *nlistf = NULL;
sig_t sigtstpdfl;
double avenrun[3];
int col;
double naptime = 5;
double naptime = 1;
int verbose = 1; /* to report kvm read errs */
int hz, stathz, maxslp;
char c;
@ -173,10 +173,8 @@ main(int argc, char **argv)
(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)
@ -194,19 +192,24 @@ main(int argc, char **argv)
* 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);
}
@ -411,7 +414,6 @@ nlisterr(struct nlist name_list[])
move(CMDLINE, 0);
clrtoeol();
refresh();
sleep(5);
endwin();
exit(1);
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: systat.1,v 1.48 2017/07/03 21:34:21 wiz Exp $
.\" $NetBSD: systat.1,v 1.49 2018/12/26 01:47:37 sevan Exp $
.\"
.\" Copyright (c) 1985, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\"
.\" @(#)systat.1 8.2 (Berkeley) 12/30/93
.\"
.Dd November 16, 2016
.Dd December 26, 2018
.Dt SYSTAT 1
.Os
.Sh NAME
@ -454,7 +454,22 @@ etc.
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'), sleeping (`s').
@ -465,9 +480,9 @@ nice (shown as `-'), and idle time (shown as ` ').
.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
@ -509,16 +524,75 @@ the second row of the display shows the average
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

View File

@ -61,4 +61,3 @@ struct command {
#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))

View File

@ -1,4 +1,4 @@
/* $NetBSD: vmstat.c,v 1.82 2017/07/15 08:22:23 mlelstv Exp $ */
/* $NetBSD: vmstat.c,v 1.83 2018/12/26 01:47:37 sevan Exp $ */
/*-
* Copyright (c) 1983, 1989, 1992, 1993
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
#endif
__RCSID("$NetBSD: vmstat.c,v 1.82 2017/07/15 08:22:23 mlelstv Exp $");
__RCSID("$NetBSD: vmstat.c,v 1.83 2018/12/26 01:47:37 sevan Exp $");
#endif /* not lint */
/*
@ -87,6 +87,7 @@ static long *intrloc;
static char **intrname;
static int nextintsrow;
static int disk_horiz = 1;
static u_int nbuf;
WINDOW *
openvmstat(void)
@ -124,7 +125,7 @@ static struct nlist namelist[] = {
*/
#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
@ -139,11 +140,11 @@ static struct nlist namelist[] = {
#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 DISKCOLWIDTH 8
#define DISKCOLEND INTSCOL
typedef struct intr_evcnt intr_evcnt_t;
@ -318,7 +319,7 @@ labelvmstat_top(void)
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");
@ -328,8 +329,8 @@ labelvmstat_top(void)
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
@ -343,26 +344,28 @@ labelvmstat(void)
/* 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,
" Calls hits %% hits %%");
mvprintw(DISKROW, DISKCOL, "Disks:");
mvprintw(DISKROW, DISKCOL, "%*s", DISKCOLWIDTH, "Disks:");
if (disk_horiz) {
mvprintw(DISKROW + 1, DISKCOL + 1, "seeks");
mvprintw(DISKROW + 2, DISKCOL + 1, "xfers");
mvprintw(DISKROW + 3, DISKCOL + 1, "bytes");
mvprintw(DISKROW + 4, DISKCOL + 1, "%%busy");
} else {
mvprintw(DISKROW, DISKCOL + 1 + 1 * DISKCOLWIDTH, "seeks");
mvprintw(DISKROW, DISKCOL + 1 + 2 * DISKCOLWIDTH, "xfers");
mvprintw(DISKROW, DISKCOL + 1 + 3 * DISKCOLWIDTH, "bytes");
mvprintw(DISKROW, DISKCOL + 1 + 4 * DISKCOLWIDTH, "%%busy");
mvprintw(DISKROW, DISKCOL + 1 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "seeks");
mvprintw(DISKROW, DISKCOL + 2 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "xfers");
mvprintw(DISKROW, DISKCOL + 3 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "bytes");
mvprintw(DISKROW, DISKCOL + 4 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "%%busy");
}
/* Middle column */
@ -396,7 +399,7 @@ labelvmstat(void)
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)
@ -447,6 +450,11 @@ show_vmstat_top(vmtotal_t *Total, uvmexp_sysctl_t *uvm, uvmexp_sysctl_t *uvm1)
PUTRATE(us, us1, uvmexp->softs, GENSTATROW + 1, GENSTATCOL + 27, 6);
PUTRATE(us, us1, uvmexp->faults, GENSTATROW + 1, GENSTATCOL + 34, 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];
@ -476,6 +484,11 @@ showvmstat(void)
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();
@ -507,16 +520,74 @@ showvmstat(void)
/* Memory totals */
#define pgtokb(pg) ((pg) * (s.uvmexp.pagesize / 1024))
putint(pgtokb(s.uvmexp.active), MEMROW + 2, MEMCOL + 6, 9);
putint(pgtokb(s.uvmexp.active + s.uvmexp.swpginuse), /* XXX */
MEMROW + 2, MEMCOL + 16, 9);
putint(pgtokb(s.uvmexp.npages - s.uvmexp.free),
MEMROW + 3, MEMCOL + 6, 9);
putint(pgtokb(s.uvmexp.npages - s.uvmexp.free + s.uvmexp.swpginuse),
MEMROW + 3, MEMCOL + 16, 9);
putint(pgtokb(s.uvmexp.free), MEMROW + 2, MEMCOL + 26, 9);
putint(pgtokb(s.uvmexp.free + s.uvmexp.swpages - s.uvmexp.swpginuse),
MEMROW + 3, MEMCOL + 26, 9);
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 */
@ -633,7 +704,7 @@ showvmstat(void)
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);
@ -776,7 +847,7 @@ getinfo(struct Info *stats)
memset(&stats->nchstats, 0, 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]);