aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/pstat
diff options
context:
space:
mode:
authorMatthew Dillon <dillon@FreeBSD.org>1999-01-21 08:08:55 +0000
committerMatthew Dillon <dillon@FreeBSD.org>1999-01-21 08:08:55 +0000
commiteedc343625e28519e717a9867dff20efe5081a12 (patch)
tree153b95f14fdd9dc0328da9860c370551dcaedc6f /usr.sbin/pstat
parent391a151a771c79bdb9d9fe5f3b0d202b6ce5cd6c (diff)
downloadsrc-eedc343625e28519e717a9867dff20efe5081a12.tar.gz
src-eedc343625e28519e717a9867dff20efe5081a12.zip
Update pstat -s to handle both old and new swapper.
Add pstat -ss to dump new swapper's radix tree.
Notes
Notes: svn path=/head/; revision=42955
Diffstat (limited to 'usr.sbin/pstat')
-rw-r--r--usr.sbin/pstat/pstat.86
-rw-r--r--usr.sbin/pstat/pstat.c360
2 files changed, 290 insertions, 76 deletions
diff --git a/usr.sbin/pstat/pstat.8 b/usr.sbin/pstat/pstat.8
index 792bbb54795b..d4e5dc66d3e5 100644
--- a/usr.sbin/pstat/pstat.8
+++ b/usr.sbin/pstat/pstat.8
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)pstat.8 8.5 (Berkeley) 5/13/94
-.\" $Id: pstat.8,v 1.15 1997/10/09 07:22:05 charnier Exp $
+.\" $Id: pstat.8,v 1.16 1998/01/17 16:58:55 bde Exp $
.\"
.Dd May 13, 1994
.Dt PSTAT 8
@@ -131,6 +131,10 @@ reports the percentage of space used.
.Pp
If more than one partition is configured into the system, totals for all
of the statistics will be reported in the final line of the report.
+.Pp
+If you supply the option again, as in
+.Fl ss ,
+the system will display a breakdown of the swap bitmap/radix-tree.
.It Fl t
Print table for terminals
with these headings:
diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c
index 0cc433972c49..157068d2efba 100644
--- a/usr.sbin/pstat/pstat.c
+++ b/usr.sbin/pstat/pstat.c
@@ -42,7 +42,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95";
#endif
static const char rcsid[] =
- "$Id: pstat.c,v 1.36 1998/07/06 20:28:05 bde Exp $";
+ "$Id: pstat.c,v 1.37 1998/08/19 01:32:28 bde Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -68,6 +68,7 @@ static const char rcsid[] =
#include <sys/tty.h>
#include <sys/conf.h>
#include <sys/rlist.h>
+#include <sys/blist.h>
#include <sys/user.h>
#include <sys/sysctl.h>
@@ -85,76 +86,77 @@ static const char rcsid[] =
struct nlist nl[] = {
#define VM_SWAPLIST 0
{ "_swaplist" },/* list of free swap areas */
+#define NLMANDATORYBEG 1
#define VM_SWDEVT 1
{ "_swdevt" }, /* list of swap devices and sizes */
-#define VM_NSWAP 2
- { "_nswap" }, /* size of largest swap device */
-#define VM_NSWDEV 3
+#define VM_NSWDEV 2
{ "_nswdev" }, /* number of swap devices */
-#define VM_DMMAX 4
+#define VM_DMMAX 3
{ "_dmmax" }, /* maximum size of a swap block */
-#define V_MOUNTLIST 5
+#define V_MOUNTLIST 4
{ "_mountlist" }, /* address of head of mount list. */
-#define V_NUMV 6
+#define V_NUMV 5
{ "_numvnodes" },
-#define FNL_NFILE 7
+#define FNL_NFILE 6
{"_nfiles"},
-#define FNL_MAXFILE 8
+#define FNL_MAXFILE 7
{"_maxfiles"},
-#define NLMANDATORY FNL_MAXFILE /* names up to here are mandatory */
-#define SCONS NLMANDATORY + 1
+#define NLMANDATORYEND FNL_MAXFILE /* names up to here are mandatory */
+#define SCONS NLMANDATORYEND + 1
{ "_cons" },
-#define SPTY NLMANDATORY + 2
+#define SPTY NLMANDATORYEND + 2
{ "_pt_tty" },
-#define SNPTY NLMANDATORY + 3
+#define SNPTY NLMANDATORYEND + 3
{ "_npty" },
+#define VM_SWAPBLIST NLMANDATORYEND + 4
+ { "_swapblist" },
#ifdef hp300
-#define SDCA (SNPTY+1)
+#define SDCA (VM_SWAPBLIST+1)
{ "_dca_tty" },
-#define SNDCA (SNPTY+2)
+#define SNDCA (VM_SWAPBLIST+2)
{ "_ndca" },
-#define SDCM (SNPTY+3)
+#define SDCM (VM_SWAPBLIST+3)
{ "_dcm_tty" },
-#define SNDCM (SNPTY+4)
+#define SNDCM (VM_SWAPBLIST+4)
{ "_ndcm" },
-#define SDCL (SNPTY+5)
+#define SDCL (VM_SWAPBLIST+5)
{ "_dcl_tty" },
-#define SNDCL (SNPTY+6)
+#define SNDCL (VM_SWAPBLIST+6)
{ "_ndcl" },
-#define SITE (SNPTY+7)
+#define SITE (VM_SWAPBLIST+7)
{ "_ite_tty" },
-#define SNITE (SNPTY+8)
+#define SNITE (VM_SWAPBLIST+8)
{ "_nite" },
#endif
#ifdef mips
-#define SDC (SNPTY+1)
+#define SDC (VM_SWAPBLIST+1)
{ "_dc_tty" },
-#define SNDC (SNPTY+2)
+#define SNDC (VM_SWAPBLIST+2)
{ "_dc_cnt" },
#endif
#ifdef __FreeBSD__
-#define SCCONS (SNPTY+1)
+#define SCCONS (VM_SWAPBLIST+1)
{ "_sccons" },
-#define NSCCONS (SNPTY+2)
+#define NSCCONS (VM_SWAPBLIST+2)
{ "_nsccons" },
-#define SIO (SNPTY+3)
+#define SIO (VM_SWAPBLIST+3)
{ "_sio_tty" },
-#define NSIO (SNPTY+4)
+#define NSIO (VM_SWAPBLIST+4)
{ "_nsio_tty" },
-#define RC (SNPTY+5)
+#define RC (VM_SWAPBLIST+5)
{ "_rc_tty" },
-#define NRC (SNPTY+6)
+#define NRC (VM_SWAPBLIST+6)
{ "_nrc_tty" },
-#define CY (SNPTY+7)
+#define CY (VM_SWAPBLIST+7)
{ "_cy_tty" },
-#define NCY (SNPTY+8)
+#define NCY (VM_SWAPBLIST+8)
{ "_ncy_tty" },
-#define SI (SNPTY+9)
+#define SI (VM_SWAPBLIST+9)
{ "_si_tty" },
-#define NSI (SNPTY+10)
+#define NSI (VM_SWAPBLIST+10)
{ "_si_Nports" },
#endif
{ "" }
@@ -162,6 +164,7 @@ struct nlist nl[] = {
int usenumflag;
int totalflag;
+int swapflag;
char *nlistf = NULL;
char *memf = NULL;
kvm_t *kd;
@@ -212,6 +215,12 @@ struct {
#define KGET2(addr, p, s, msg) \
if (kvm_read(kd, (u_long)(addr), p, s) != s) \
warnx("cannot read %s: %s", msg, kvm_geterr(kd))
+#define KGETN(idx, var) \
+ KGET1N(idx, &var, sizeof(var), SVAR(var))
+#define KGET1N(idx, p, s, msg) \
+ KGET2N(nl[idx].n_value, p, s, msg)
+#define KGET2N(addr, p, s, msg) \
+ ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0)
#define KGETRET(addr, p, s, msg) \
if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
@@ -248,7 +257,7 @@ main(argc, argv)
char *argv[];
{
int ch, i, quit, ret;
- int fileflag, swapflag, ttyflag, vnodeflag;
+ int fileflag, ttyflag, vnodeflag;
char buf[_POSIX2_LINE_MAX],*opts;
fileflag = swapflag = ttyflag = vnodeflag = 0;
@@ -286,7 +295,7 @@ main(argc, argv)
usenumflag = 1;
break;
case 's':
- swapflag = 1;
+ ++swapflag;
break;
case 'T':
totalflag = 1;
@@ -320,7 +329,7 @@ main(argc, argv)
if ((ret = kvm_nlist(kd, nl)) != 0) {
if (ret == -1)
errx(1, "kvm_nlist: %s", kvm_geterr(kd));
- for (i = quit = 0; i <= NLMANDATORY; i++)
+ for (i = NLMANDATORYBEG, quit = 0; i <= NLMANDATORYEND; i++)
if (!nl[i].n_value) {
quit = 1;
warnx("undefined symbol: %s", nl[i].n_name);
@@ -1026,26 +1035,190 @@ getfiles(abuf, alen)
}
/*
+ * scanradix() - used by swapmode() to scan the swap device's new style
+ * radix tree
+ */
+
+#define TABME tab, tab, ""
+
+int
+scanradix(
+ blmeta_t *scan,
+ daddr_t blk,
+ daddr_t radix,
+ daddr_t skip,
+ daddr_t count,
+ int dmmax,
+ int nswdev,
+ long *perdev,
+ int tab
+) {
+ blmeta_t meta;
+
+ KGET2(scan, &meta, sizeof(meta), "blmeta_t");
+
+ /*
+ * Terminator
+ */
+ if (meta.bm_bighint == (daddr_t)-1) {
+ if (swapflag > 1) {
+ printf("%*.*s(0x%06x,%d) Terminator\n",
+ TABME,
+ blk,
+ radix
+ );
+ }
+ return(-1);
+ }
+
+ if (radix == BLIST_BMAP_RADIX) {
+ /*
+ * Leaf bitmap
+ */
+ int i;
+
+ if (swapflag > 1) {
+ printf("%*.*s(0x%06x,%d) Bitmap %08x big=%d\n",
+ TABME,
+ blk,
+ radix,
+ (int)meta.u.bmu_bitmap,
+ meta.bm_bighint
+ );
+ }
+
+ /*
+ * If not all allocated, count.
+ */
+ if (meta.u.bmu_bitmap != 0) {
+ for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) {
+ /*
+ * A 0 bit means allocated
+ */
+ if ((meta.u.bmu_bitmap & (1 << i))) {
+ int t = 0;
+
+ if (nswdev)
+ t = (blk + i) / dmmax % nswdev;
+ ++perdev[t];
+ }
+ }
+ }
+ } else if (meta.u.bmu_avail == radix) {
+ /*
+ * Meta node if all free
+ */
+ if (swapflag > 1) {
+ printf("%*.*s(0x%06x,%d) Submap ALL-FREE {\n",
+ TABME,
+ blk,
+ radix,
+ (int)meta.u.bmu_avail,
+ meta.bm_bighint
+ );
+ }
+ /*
+ * Note: both dmmax and radix are powers of 2. However, dmmax
+ * may be larger then radix so use a smaller increment if
+ * necessary.
+ */
+ {
+ int t;
+ int tinc = dmmax;
+
+ while (tinc > radix)
+ tinc >>= 1;
+
+ for (t = blk; t < blk + radix; t += tinc) {
+ if (nswdev)
+ perdev[0] += tinc;
+ else
+ perdev[t / dmmax % nswdev] += tinc;
+ }
+ }
+ } else if (meta.u.bmu_avail == 0) {
+ /*
+ * Meta node if all used
+ */
+ if (swapflag > 1) {
+ printf("%*.*s(0x%06x,%d) Submap ALL-ALLOCATED\n",
+ TABME,
+ blk,
+ radix,
+ (int)meta.u.bmu_avail,
+ meta.bm_bighint
+ );
+ }
+ } else {
+ /*
+ * Meta node if not all free
+ */
+ int i;
+ int next_skip;
+
+ radix >>= BLIST_META_RADIX_SHIFT;
+ next_skip = skip >> BLIST_META_RADIX_SHIFT;
+
+ if (swapflag > 1) {
+ printf("%*.*s(0x%06x,%d) Submap avail=%d big=%d {\n",
+ TABME,
+ blk,
+ radix,
+ (int)meta.u.bmu_avail,
+ meta.bm_bighint
+ );
+ }
+
+ for (i = 1; i <= skip; i += next_skip) {
+ int r;
+ daddr_t vcount = (count > radix) ? radix : count;
+
+ r = scanradix(
+ &scan[i],
+ blk,
+ radix,
+ next_skip - 1,
+ vcount,
+ dmmax,
+ nswdev,
+ perdev,
+ tab + 4
+ );
+ if (r < 0)
+ break;
+ blk += radix;
+ }
+ if (swapflag > 1) {
+ printf("%*.*s}\n", TABME);
+ }
+ }
+ return(0);
+}
+
+
+/*
* swapmode is based on a program called swapinfo written
* by Kevin Lahey <kml@rokkaku.atl.ga.us>.
*/
void
-swapmode()
+swapmode(void)
{
char *header, *p;
- int hlen, nswap, nswdev, dmmax;
- int i, div, avail, nfree, npfree, used;
+ int hlen, nswdev, dmmax;
+ int i, div, mul, avail, nfree, npfree, used;
struct swdevt *sw;
long blocksize, *perdev;
struct rlist head;
struct rlisthdr swaplist;
- struct rlist *swapptr;
+ struct blist *swapblist = NULL;
u_long ptr;
- KGET(VM_NSWAP, nswap);
KGET(VM_NSWDEV, nswdev);
- KGET(VM_DMMAX, dmmax);
- KGET1(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist");
+ KGET(VM_DMMAX, dmmax); /* PAGE_BSIZE'd or PAGE_SIZE'd depending */
+ if (!KGET1N(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist")) {
+ KGET1(VM_SWAPBLIST, &swapblist, sizeof swapblist, "swapblist");
+ }
+
if ((sw = malloc(nswdev * sizeof(*sw))) == NULL ||
(perdev = malloc(nswdev * sizeof(*perdev))) == NULL)
errx(1, "malloc");
@@ -1055,39 +1228,63 @@ swapmode()
/* Count up swap space. */
nfree = 0;
memset(perdev, 0, nswdev * sizeof(*perdev));
- swapptr = swaplist.rlh_list;
- while (swapptr) {
- int top, bottom, next_block;
- KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
+ if (swapblist) {
+ /*
+ * New swap radix tree (ugh!)
+ */
+ struct blist blcopy = { 0 };
+ KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist");
+ if (swapflag > 1) {
+ printf("radix tree: %d/%d/%d blocks, %dK wired\n",
+ blcopy.bl_free,
+ blcopy.bl_blocks,
+ blcopy.bl_radix,
+ (blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/
+ 1024
+ );
+ }
+ scanradix(blcopy.bl_root, 0, blcopy.bl_radix, blcopy.bl_skip, blcopy.bl_rootblks, dmmax, nswdev, perdev, 0);
+ } else {
+ /*
+ * Old swap
+ */
+ struct rlist *swapptr;
- top = head.rl_end;
- bottom = head.rl_start;
+ swapptr = swaplist.rlh_list;
+ while (swapptr) {
+ int top, bottom, next_block;
- nfree += top - bottom + 1;
+ KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
- /*
- * Swap space is split up among the configured disks.
- *
- * For interleaved swap devices, the first dmmax blocks
- * of swap space some from the first disk, the next dmmax
- * blocks from the next, and so on up to nswap blocks.
- *
- * The list of free space joins adjacent free blocks,
- * ignoring device boundries. If we want to keep track
- * of this information per device, we'll just have to
- * extract it ourselves.
- */
- while (top / dmmax != bottom / dmmax) {
- next_block = ((bottom + dmmax) / dmmax);
+ top = head.rl_end;
+ bottom = head.rl_start;
+
+ nfree += top - bottom + 1;
+
+ /*
+ * Swap space is split up among the configured disks.
+ *
+ * For interleaved swap devices, the first dmmax blocks
+ * of swap space some from the first disk, the next
+ * dmmax blocks from the next, and so.
+ *
+ * The list of free space joins adjacent free blocks,
+ * ignoring device boundries. If we want to keep track
+ * of this information per device, we'll just have to
+ * extract it ourselves.
+ */
+ while (top / dmmax != bottom / dmmax) {
+ next_block = ((bottom + dmmax) / dmmax);
+ perdev[(bottom / dmmax) % nswdev] +=
+ next_block * dmmax - bottom;
+ bottom = next_block * dmmax;
+ }
perdev[(bottom / dmmax) % nswdev] +=
- next_block * dmmax - bottom;
- bottom = next_block * dmmax;
- }
- perdev[(bottom / dmmax) % nswdev] +=
- top - bottom + 1;
+ top - bottom + 1;
- swapptr = head.rl_next;
+ swapptr = head.rl_next;
+ }
}
header = getbsize(&hlen, &blocksize);
@@ -1095,7 +1292,20 @@ swapmode()
(void)printf("%-11s %*s %8s %8s %8s %s\n",
"Device", hlen, header,
"Used", "Avail", "Capacity", "Type");
- div = blocksize / 512;
+
+ mul = 1;
+ if (swapblist) {
+ if ((div = blocksize / PAGE_SIZE) == 0) {
+ mul = PAGE_SIZE / blocksize;
+ div = 1;
+ }
+ } else {
+ if ((div = blocksize / DEV_BSIZE) == 0) {
+ mul = DEV_BSIZE / blocksize;
+ div = 1;
+ }
+ }
+
avail = npfree = 0;
for (i = 0; i < nswdev; i++) {
int xsize, xfree;
@@ -1112,10 +1322,10 @@ swapmode()
p = devname(sw[i].sw_dev, S_IFBLK);
(void)printf("/dev/%-6s %*d ",
p == NULL ? "??" : p,
- hlen, sw[i].sw_nblks / div);
+ hlen, sw[i].sw_nblks * mul / div);
} else
(void)printf("[NFS swap] %*d ",
- hlen, sw[i].sw_nblks / div);
+ hlen, sw[i].sw_nblks * mul / div);
/* The first dmmax is never allocated to avoid trashing of
* disklabels
@@ -1128,7 +1338,7 @@ swapmode()
if (totalflag)
continue;
(void)printf("%8d %8d %5.0f%% %s\n",
- used / div, xfree / div,
+ used * mul / div, xfree * mul / div,
(double)used / (double)xsize * 100.0,
(sw[i].sw_flags & SW_SEQUENTIAL) ?
"Sequential" : "Interleaved");
@@ -1147,7 +1357,7 @@ swapmode()
}
if (npfree > 1) {
(void)printf("%-11s %*d %8d %8d %5.0f%%\n",
- "Total", hlen, avail / div, used / div, nfree / div,
+ "Total", hlen, avail * mul / div, used * mul / div, nfree * mul / div,
(double)used / (double)avail * 100.0);
}
}