version 1.47, 2001/01/04 17:40:26 |
version 1.48, 2001/03/21 23:51:47 |
|
|
#endif |
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
|
#define __POOL_EXPOSE |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/time.h> |
#include <sys/time.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
|
|
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
#include <sys/device.h> |
#include <sys/device.h> |
|
#include <sys/pool.h> |
#include <vm/vm.h> |
#include <vm/vm.h> |
#include <time.h> |
#include <time.h> |
#include <nlist.h> |
#include <nlist.h> |
|
|
{ "_allevents" }, |
{ "_allevents" }, |
#define X_FORKSTAT 13 |
#define X_FORKSTAT 13 |
{ "_forkstat" }, |
{ "_forkstat" }, |
#define X_NSELCOLL 14 |
#define X_POOLHEAD 14 |
{ "_nselcoll" }, |
{ "_pool_head" }, |
#define X_END 15 |
#define X_END 15 |
#if defined(__pc532__) |
#if defined(__pc532__) |
#define X_IVT (X_END) |
#define X_IVT (X_END) |
|
|
void dkstats __P((void)); |
void dkstats __P((void)); |
void dointr __P((void)); |
void dointr __P((void)); |
void domem __P((void)); |
void domem __P((void)); |
|
void dopool __P((void)); |
void dosum __P((void)); |
void dosum __P((void)); |
void dovmstat __P((u_int, int)); |
void dovmstat __P((u_int, int)); |
void kread __P((int, void *, size_t)); |
void kread __P((int, void *, size_t)); |
|
|
/* Namelist and memory file names. */ |
/* Namelist and memory file names. */ |
char *nlistf, *memf; |
char *nlistf, *memf; |
|
|
extern char *__progname; |
|
|
|
int |
int |
main(argc, argv) |
main(argc, argv) |
register int argc; |
register int argc; |
|
|
} |
} |
|
|
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); |
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); |
if (kd == 0) |
if (kd == 0) { |
errx(1, "kvm_openfiles: %s", errbuf); |
(void)fprintf(stderr, |
|
"vmstat: kvm_openfiles: %s\n", errbuf); |
|
exit(1); |
|
} |
|
|
if ((c = kvm_nlist(kd, namelist)) != 0) { |
if ((c = kvm_nlist(kd, namelist)) != 0) { |
|
|
|
|
|
|
if (c > 0) { |
if (c > 0) { |
(void)fprintf(stderr, |
(void)fprintf(stderr, |
"%s: undefined symbols:", __progname); |
"vmstat: undefined symbols:"); |
for (c = 0; |
for (c = 0; |
c < sizeof(namelist)/sizeof(namelist[0]); c++) |
c < sizeof(namelist)/sizeof(namelist[0]); c++) |
if (namelist[c].n_type == 0) |
if (namelist[c].n_type == 0) |
fprintf(stderr, " %s", |
fprintf(stderr, " %s", |
namelist[c].n_name); |
namelist[c].n_name); |
(void)fputc('\n', stderr); |
(void)fputc('\n', stderr); |
exit(1); |
|
} else |
} else |
errx(1, "kvm_nlist: %s", kvm_geterr(kd)); |
(void)fprintf(stderr, "vmstat: kvm_nlist: %s\n", |
|
kvm_geterr(kd)); |
|
exit(1); |
} |
} |
|
|
if (todo & VMSTAT) { |
if (todo & VMSTAT) { |
|
|
|
|
if (todo & FORKSTAT) |
if (todo & FORKSTAT) |
doforkst(); |
doforkst(); |
if (todo & MEMSTAT) |
if (todo & MEMSTAT) { |
domem(); |
domem(); |
|
dopool(); |
|
} |
if (todo & SUMSTAT) |
if (todo & SUMSTAT) |
dosum(); |
dosum(); |
if (todo & TIMESTAT) |
if (todo & TIMESTAT) |
|
|
static time_t now; |
static time_t now; |
static struct timeval boottime; |
static struct timeval boottime; |
time_t uptime; |
time_t uptime; |
int mib[2]; |
|
size_t size; |
|
|
|
if (boottime.tv_sec == 0) { |
if (boottime.tv_sec == 0) |
if (nlist == NULL && memf == NULL) { |
kread(X_BOOTTIME, &boottime, sizeof(boottime)); |
kread(X_BOOTTIME, &boottime, sizeof(boottime)); |
|
} else { |
|
size = sizeof(boottime); |
|
mib[0] = CTL_KERN; |
|
mib[1] = KERN_BOOTTIME; |
|
if (sysctl(mib, 2, &boottime, &size, NULL, 0) < 0) { |
|
printf("Can't get kerninfo: %s\n", |
|
strerror(errno)); |
|
bzero(&boottime, sizeof(boottime)); |
|
} |
|
} |
|
} |
|
(void)time(&now); |
(void)time(&now); |
uptime = now - boottime.tv_sec; |
uptime = now - boottime.tv_sec; |
if (uptime <= 0 || uptime > 60*60*24*365*10) |
if (uptime <= 0 || uptime > 60*60*24*365*10) { |
errx(1, "time makes no sense; namelist must be wrong"); |
(void)fprintf(stderr, |
|
"vmstat: time makes no sense; namelist must be wrong.\n"); |
|
exit(1); |
|
} |
return(uptime); |
return(uptime); |
} |
} |
|
|
|
|
time_t uptime, halfuptime; |
time_t uptime, halfuptime; |
void needhdr(); |
void needhdr(); |
int mib[2]; |
int mib[2]; |
struct clockinfo clkinfo; |
|
size_t size; |
size_t size; |
|
|
uptime = getuptime(); |
uptime = getuptime(); |
halfuptime = uptime / 2; |
halfuptime = uptime / 2; |
(void)signal(SIGCONT, needhdr); |
(void)signal(SIGCONT, needhdr); |
|
|
mib[0] = CTL_KERN; |
if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) |
mib[1] = KERN_CLOCKRATE; |
kread(X_STATHZ, &hz, sizeof(hz)); |
size = sizeof(clkinfo); |
if (!hz) |
if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) { |
kread(X_HZ, &hz, sizeof(hz)); |
printf("Can't get kerninfo: %s\n", strerror(errno)); |
|
return; |
|
} |
|
hz = clkinfo.stathz; |
|
|
|
for (hdrcnt = 1;;) { |
for (hdrcnt = 1;;) { |
if (!--hdrcnt) |
if (!--hdrcnt) |
|
|
{ |
{ |
struct nchstats nchstats; |
struct nchstats nchstats; |
long nchtotal; |
long nchtotal; |
int nselcoll; |
|
|
|
#ifdef UVM |
#ifdef UVM |
kread(X_UVMEXP, &uvmexp, sizeof(uvmexp)); |
kread(X_UVMEXP, &uvmexp, sizeof(uvmexp)); |
|
|
(void)printf("%11u pages being paged out\n", uvmexp.paging); |
(void)printf("%11u pages being paged out\n", uvmexp.paging); |
(void)printf("%11u pages wired\n", uvmexp.wired); |
(void)printf("%11u pages wired\n", uvmexp.wired); |
(void)printf("%11u pages reserved for pagedaemon\n", |
(void)printf("%11u pages reserved for pagedaemon\n", |
uvmexp.reserve_pagedaemon); |
uvmexp.reserve_pagedaemon); |
(void)printf("%11u pages reserved for kernel\n", |
(void)printf("%11u pages reserved for kernel\n", |
uvmexp.reserve_kernel); |
uvmexp.reserve_kernel); |
|
|
/* swap */ |
/* swap */ |
(void)printf("%11u swap pages\n", uvmexp.swpages); |
(void)printf("%11u swap pages\n", uvmexp.swpages); |
|
|
(void)printf("%11u swap outs\n", uvmexp.swapouts); |
(void)printf("%11u swap outs\n", uvmexp.swapouts); |
(void)printf("%11u forks\n", uvmexp.forks); |
(void)printf("%11u forks\n", uvmexp.forks); |
(void)printf("%11u forks where vmspace is shared\n", |
(void)printf("%11u forks where vmspace is shared\n", |
uvmexp.forks_sharevm); |
uvmexp.forks_sharevm); |
|
|
/* daemon counters */ |
/* daemon counters */ |
(void)printf("%11u number of times the pagedeamon woke up\n", |
(void)printf("%11u number of times the pagedeamon woke up\n", |
uvmexp.pdwoke); |
uvmexp.pdwoke); |
(void)printf("%11u revolutions of the clock hand\n", uvmexp.pdrevs); |
(void)printf("%11u revolutions of the clock hand\n", uvmexp.pdrevs); |
(void)printf("%11u pages freed by pagedaemon\n", uvmexp.pdfreed); |
(void)printf("%11u pages freed by pagedaemon\n", uvmexp.pdfreed); |
(void)printf("%11u pages scanned by pagedaemon\n", uvmexp.pdscans); |
(void)printf("%11u pages scanned by pagedaemon\n", uvmexp.pdscans); |
|
|
PCT(nchstats.ncs_badhits, nchtotal), |
PCT(nchstats.ncs_badhits, nchtotal), |
PCT(nchstats.ncs_falsehits, nchtotal), |
PCT(nchstats.ncs_falsehits, nchtotal), |
PCT(nchstats.ncs_long, nchtotal)); |
PCT(nchstats.ncs_long, nchtotal)); |
kread(X_NSELCOLL, &nselcoll, sizeof(nselcoll)); |
|
(void)printf("%11d select collisions\n", nselcoll); |
|
} |
} |
|
|
void |
void |
|
|
for (j = 0; j < 16; j++, ivp++) { |
for (j = 0; j < 16; j++, ivp++) { |
if (ivp->iv_vec && ivp->iv_use && ivp->iv_cnt) { |
if (ivp->iv_vec && ivp->iv_use && ivp->iv_cnt) { |
if (kvm_read(kd, (u_long)ivp->iv_use, iname, 63) != 63) { |
if (kvm_read(kd, (u_long)ivp->iv_use, iname, 63) != 63) { |
errx(1, "iv_use: %s", kvm_geterr(kd)); |
(void)fprintf(stderr, "vmstat: iv_use: %s\n", |
kvm_geterr(kd)); |
kvm_geterr(kd)); |
exit(1); |
exit(1); |
} |
} |
|
|
dointr() |
dointr() |
{ |
{ |
struct intrhand *intrhand[16], *ihp, ih; |
struct intrhand *intrhand[16], *ihp, ih; |
u_long inttotal; |
long inttotal; |
time_t uptime; |
time_t uptime; |
u_long intrstray[16]; |
int intrstray[16]; |
char iname[17], fname[31]; |
char iname[17], fname[31]; |
int i; |
int i; |
|
|
|
|
if (kvm_read(kd, (u_long)ih.ih_what, iname, 16) != 16) |
if (kvm_read(kd, (u_long)ih.ih_what, iname, 16) != 16) |
errx(1, "vmstat: ih_what: %s", kvm_geterr(kd)); |
errx(1, "vmstat: ih_what: %s", kvm_geterr(kd)); |
snprintf(fname, sizeof fname, "irq%d/%s", i, iname); |
snprintf(fname, sizeof fname, "irq%d/%s", i, iname); |
printf("%-16.16s %10lu %8lu\n", fname, ih.ih_count, |
printf("%-16.16s %10ld %8ld\n", fname, ih.ih_count, |
ih.ih_count / uptime); |
ih.ih_count / uptime); |
inttotal += ih.ih_count; |
inttotal += ih.ih_count; |
ihp = ih.ih_next; |
ihp = ih.ih_next; |
|
|
} |
} |
for (i = 0; i < 16; i++) |
for (i = 0; i < 16; i++) |
if (intrstray[i]) { |
if (intrstray[i]) { |
printf("Stray irq %-2d %10lu %8lu\n", |
printf("Stray irq %-2d %10d %8d\n", |
i, intrstray[i], intrstray[i] / uptime); |
i, intrstray[i], intrstray[i] / uptime); |
inttotal += intrstray[i]; |
inttotal += intrstray[i]; |
} |
} |
printf("Total %10lu %8lu\n", inttotal, inttotal / uptime); |
printf("Total %10ld %8ld\n", inttotal, inttotal / uptime); |
} |
} |
#else |
#else |
void |
void |
|
|
namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; |
namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; |
intrcnt = malloc((size_t)nintr); |
intrcnt = malloc((size_t)nintr); |
intrname = malloc((size_t)inamlen); |
intrname = malloc((size_t)inamlen); |
if (intrcnt == NULL || intrname == NULL) |
if (intrcnt == NULL || intrname == NULL) { |
err(1, "malloc"); |
(void)fprintf(stderr, "vmstat: %s.\n", strerror(errno)); |
|
exit(1); |
|
} |
kread(X_INTRCNT, intrcnt, (size_t)nintr); |
kread(X_INTRCNT, intrcnt, (size_t)nintr); |
kread(X_INTRNAMES, intrname, (size_t)inamlen); |
kread(X_INTRNAMES, intrname, (size_t)inamlen); |
(void)printf("interrupt total rate\n"); |
(void)printf("interrupt total rate\n"); |
|
|
evptr = allevents.tqh_first; |
evptr = allevents.tqh_first; |
while (evptr) { |
while (evptr) { |
if (kvm_read(kd, (long)evptr, (void *)&evcnt, |
if (kvm_read(kd, (long)evptr, (void *)&evcnt, |
sizeof evcnt) != sizeof evcnt) |
sizeof evcnt) != sizeof evcnt) { |
errx(1, "event chain trashed: %s", kvm_geterr(kd)); |
(void)fprintf(stderr, "vmstat: event chain trashed: %s\n", |
|
kvm_geterr(kd)); |
|
exit(1); |
|
} |
if (strcmp(evcnt.ev_name, "intr") == 0) { |
if (strcmp(evcnt.ev_name, "intr") == 0) { |
if (kvm_read(kd, (long)evcnt.ev_dev, (void *)&dev, |
if (kvm_read(kd, (long)evcnt.ev_dev, (void *)&dev, |
sizeof dev) != sizeof dev) |
sizeof dev) != sizeof dev) { |
errx(1, "event chain trashed: %s", kvm_geterr(kd)); |
(void)fprintf(stderr, "vmstat: event chain trashed: %s\n", |
|
kvm_geterr(kd)); |
|
exit(1); |
|
} |
if (evcnt.ev_count) |
if (evcnt.ev_count) |
(void)printf("%-14s %12d %8ld\n", dev.dv_xname, |
(void)printf("%-14s %12d %8ld\n", dev.dv_xname, |
evcnt.ev_count, (long)(evcnt.ev_count / uptime)); |
evcnt.ev_count, (long)(evcnt.ev_count / uptime)); |
|
|
register struct kmemstats *ks; |
register struct kmemstats *ks; |
register int i, j; |
register int i, j; |
int len, size, first; |
int len, size, first; |
u_long totuse = 0, totfree = 0; |
long totuse = 0, totfree = 0, totreq = 0; |
quad_t totreq = 0; |
|
char *name; |
char *name; |
struct kmemstats kmemstats[M_LAST]; |
struct kmemstats kmemstats[M_LAST]; |
struct kmembuckets buckets[MINBUCKET + 16]; |
struct kmembuckets buckets[MINBUCKET + 16]; |
int mib[4]; |
|
size_t siz; |
|
char buf[BUFSIZ], *bufp, *ap; |
|
|
|
if (memf == NULL && nlistf == NULL) { |
kread(X_KMEMBUCKETS, buckets, sizeof(buckets)); |
mib[0] = CTL_KERN; |
|
mib[1] = KERN_MALLOCSTATS; |
|
mib[2] = KERN_MALLOC_BUCKETS; |
|
siz = sizeof(buf); |
|
if (sysctl(mib, 3, buf, &siz, NULL, 0) < 0) { |
|
printf("Could not acquire information on kernel memory bucket sizes.\n"); |
|
return; |
|
} |
|
|
|
bufp = buf; |
|
mib[2] = KERN_MALLOC_BUCKET; |
|
siz = sizeof(struct kmembuckets); |
|
i = 0; |
|
while ((ap = strsep(&bufp, ",")) != NULL) { |
|
mib[3] = atoi(ap); |
|
|
|
if (sysctl(mib, 4, &buckets[MINBUCKET + i], &siz, |
|
NULL, 0) < 0) { |
|
printf("Failed to read statistics for bucket %d.\n", mib[3]); |
|
return; |
|
} |
|
i++; |
|
} |
|
} else { |
|
kread(X_KMEMBUCKETS, buckets, sizeof(buckets)); |
|
} |
|
|
|
for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; |
for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; |
i++, kp++) { |
i++, kp++) { |
if (kp->kb_calls == 0) |
if (kp->kb_calls == 0) |
|
|
if (first) { |
if (first) { |
(void)printf("Memory statistics by bucket size\n"); |
(void)printf("Memory statistics by bucket size\n"); |
(void)printf( |
(void)printf( |
" Size In Use Free Requests HighWater Couldfree\n"); |
" Size In Use Free Requests HighWater Couldfree\n"); |
first = 0; |
first = 0; |
} |
} |
size = 1 << i; |
size = 1 << i; |
(void)printf("%8d %8qu %6qu %18qu %7qu %10qu\n", size, |
(void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size, |
kp->kb_total - kp->kb_totalfree, |
kp->kb_total - kp->kb_totalfree, |
kp->kb_totalfree, kp->kb_calls, |
kp->kb_totalfree, kp->kb_calls, |
kp->kb_highwat, kp->kb_couldfree); |
kp->kb_highwat, kp->kb_couldfree); |
|
|
totreq += ks->ks_calls; |
totreq += ks->ks_calls; |
} |
} |
(void)printf("\nMemory Totals: In Use Free Requests\n"); |
(void)printf("\nMemory Totals: In Use Free Requests\n"); |
(void)printf(" %7luK %6luK %8qu\n", |
(void)printf(" %7ldK %6ldK %8ld\n", |
(totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); |
(totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); |
} |
} |
|
|
|
void |
|
dopool(void) |
|
{ |
|
int first, ovflw; |
|
long addr; |
|
long total = 0, inuse = 0; |
|
TAILQ_HEAD(,pool) pool_head; |
|
struct pool pool, *pp = &pool; |
|
|
|
kread(X_POOLHEAD, &pool_head, sizeof(pool_head)); |
|
addr = (long)TAILQ_FIRST(&pool_head); |
|
|
|
for (first = 1; addr != 0; ) { |
|
char name[32], maxp[32]; |
|
if (kvm_read(kd, addr, (void *)pp, sizeof *pp) != sizeof *pp) { |
|
(void)fprintf(stderr, |
|
"vmstat: pool chain trashed: %s\n", |
|
kvm_geterr(kd)); |
|
exit(1); |
|
} |
|
if (kvm_read(kd, (long)pp->pr_wchan, name, sizeof name) < 0) { |
|
(void)fprintf(stderr, |
|
"vmstat: pool name trashed: %s\n", |
|
kvm_geterr(kd)); |
|
exit(1); |
|
} |
|
name[31] = '\0'; |
|
|
|
if (first) { |
|
(void)printf("Memory resource pool statistics\n"); |
|
(void)printf( |
|
"%-11s%5s%9s%5s%9s%6s%6s%6s%6s%6s%6s%5s\n", |
|
"Name", |
|
"Size", |
|
"Requests", |
|
"Fail", |
|
"Releases", |
|
"Pgreq", |
|
"Pgrel", |
|
"Npage", |
|
"Hiwat", |
|
"Minpg", |
|
"Maxpg", |
|
"Idle"); |
|
first = 0; |
|
} |
|
if (pp->pr_maxpages == UINT_MAX) |
|
sprintf(maxp, "inf"); |
|
else |
|
sprintf(maxp, "%u", pp->pr_maxpages); |
/* |
/* |
|
* Print single word. `ovflow' is number of characters didn't fit |
|
* on the last word. `fmt' is a format string to print this word. |
|
* It must contain asterisk for field width. `width' is a width |
|
* occupied by this word. `fixed' is a number of constant chars in |
|
* `fmt'. `val' is a value to be printed using format string `fmt'. |
|
*/ |
|
#define PRWORD(ovflw, fmt, width, fixed, val) do { \ |
|
(ovflw) += printf((fmt), \ |
|
(width) - (fixed) - (ovflw) > 0 ? \ |
|
(width) - (fixed) - (ovflw) : 0, \ |
|
(val)) - (width); \ |
|
if ((ovflw) < 0) \ |
|
(ovflw) = 0; \ |
|
} while (/* CONSTCOND */0) |
|
ovflw = 0; |
|
PRWORD(ovflw, "%-*s", 11, 0, name); |
|
PRWORD(ovflw, " %*u", 5, 1, pp->pr_size); |
|
PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget); |
|
PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail); |
|
PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nput); |
|
PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagealloc); |
|
PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagefree); |
|
PRWORD(ovflw, " %*d", 6, 1, pp->pr_npages); |
|
PRWORD(ovflw, " %*d", 6, 1, pp->pr_hiwat); |
|
PRWORD(ovflw, " %*d", 6, 1, pp->pr_minpages); |
|
PRWORD(ovflw, " %*s", 6, 1, maxp); |
|
PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle); |
|
|
|
inuse += (pp->pr_nget - pp->pr_nput) * pp->pr_size; |
|
total += pp->pr_npages * pp->pr_pagesz; |
|
addr = (long)TAILQ_NEXT(pp, pr_poollist); |
|
} |
|
|
|
inuse /= 1024; |
|
total /= 1024; |
|
printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n", |
|
inuse, total, (double)(100 * inuse) / total); |
|
} |
|
|
|
/* |
* kread reads something from the kernel, given its nlist index. |
* kread reads something from the kernel, given its nlist index. |
*/ |
*/ |
void |
void |
|
|
sym = namelist[nlx].n_name; |
sym = namelist[nlx].n_name; |
if (*sym == '_') |
if (*sym == '_') |
++sym; |
++sym; |
errx(1, "symbol %s not defined", sym); |
(void)fprintf(stderr, |
|
"vmstat: symbol %s not defined\n", sym); |
|
exit(1); |
} |
} |
if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { |
if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { |
sym = namelist[nlx].n_name; |
sym = namelist[nlx].n_name; |
if (*sym == '_') |
if (*sym == '_') |
++sym; |
++sym; |
errx(1, "%s: %s", sym, kvm_geterr(kd)); |
(void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd)); |
|
exit(1); |
} |
} |
} |
} |
|
|
void |
void |
usage() |
usage() |
{ |
{ |
(void)fprintf(stderr, "usage: %s [-fimst] [-c count] [-M core] " |
(void)fprintf(stderr, |
"[-N system] [-w wait] [disks]\n", __progname); |
"usage: vmstat [-fimst] [-c count] [-M core] \ |
|
[-N system] [-w wait] [disks]\n"); |
exit(1); |
exit(1); |
} |
} |
|
|