diff options
author | des <des@FreeBSD.org> | 2003-12-07 17:46:14 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2003-12-07 17:46:14 +0000 |
commit | 0e8712116d44b45f10cfd5b1b09b736cffff4b76 (patch) | |
tree | 87a78529ecc30f07c2eacabf685aa500987561de /usr.bin/vmstat | |
parent | dc062489f5085bfb7ebe145ee208d2857bd5197e (diff) | |
download | FreeBSD-src-0e8712116d44b45f10cfd5b1b09b736cffff4b76.zip FreeBSD-src-0e8712116d44b45f10cfd5b1b09b736cffff4b76.tar.gz |
Finish the transition from libkvm to sysctl that I started a while ago.
The use of libkvm for post-mortem analysis is still supported (though it
could use more testing). We can now remove vmstat's setgid bit.
While I'm here, hack the interrupt listing code to not display interrupts
that haven't occurred unless the -a option was given on the command line,
and document this change.
Diffstat (limited to 'usr.bin/vmstat')
-rw-r--r-- | usr.bin/vmstat/Makefile | 2 | ||||
-rw-r--r-- | usr.bin/vmstat/vmstat.8 | 9 | ||||
-rw-r--r-- | usr.bin/vmstat/vmstat.c | 356 |
3 files changed, 249 insertions, 118 deletions
diff --git a/usr.bin/vmstat/Makefile b/usr.bin/vmstat/Makefile index 9dd3768..bc0546e 100644 --- a/usr.bin/vmstat/Makefile +++ b/usr.bin/vmstat/Makefile @@ -3,8 +3,6 @@ PROG= vmstat MAN= vmstat.8 -BINGRP= kmem -BINMODE=2555 DPADD= ${LIBKVM} ${LIBDEVSTAT} LDADD= -lkvm -ldevstat diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8 index a950d75..5362a04 100644 --- a/usr.bin/vmstat/vmstat.8 +++ b/usr.bin/vmstat/vmstat.8 @@ -41,7 +41,7 @@ .Sh SYNOPSIS .Nm .\" .Op Fl fimst -.Op Fl fimsz +.Op Fl afimsz .Op Fl c Ar count .Op Fl M Ar core .Op Fl N Ar system @@ -62,6 +62,13 @@ disk, trap and cpu activity. .Pp The options are as follows: .Bl -tag -width indent +.It Fl a +When used with +.Fl i , +include statistics about interrupts that have never been generated. +If specified twice, also show interrupts that are not connected to any +device; if specified thrice, also list stray entries for each +interrupt. .It Fl c Repeat the display .Ar count diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index 2fc8504..c84f904 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -114,24 +114,25 @@ static struct nlist namelist[] = { { "" }, }; -struct statinfo cur, last; -int num_devices, maxshowdevs; -long generation; -struct device_selection *dev_select; -int num_selected; -struct devstat_match *matches; -int num_matches = 0; -int num_devices_specified, num_selections; -long select_generation; -char **specified_devices; -devstat_select_mode select_mode; - -struct vmmeter sum, osum; - -int winlines = 20; -int nflag = 0; - -kvm_t *kd; +static struct statinfo cur, last; +static int num_devices, maxshowdevs; +static long generation; +static struct device_selection *dev_select; +static int num_selected; +static struct devstat_match *matches; +static int num_matches = 0; +static int num_devices_specified, num_selections; +static long select_generation; +static char **specified_devices; +static devstat_select_mode select_mode; + +static struct vmmeter sum, osum; + +static int winlines = 20; +static int aflag; +static int nflag; + +static kvm_t *kd; #define FORKSTAT 0x01 #define INTRSTAT 0x02 @@ -158,12 +159,10 @@ static void usage(void); static long pct(long, long); static long getuptime(void); -char **getdrivedata(char **); +static char **getdrivedata(char **); int -main(argc, argv) - int argc; - char **argv; +main(int argc, char *argv[]) { int c, todo; u_int interval; @@ -174,8 +173,11 @@ main(argc, argv) memf = nlistf = NULL; interval = reps = todo = 0; maxshowdevs = 2; - while ((c = getopt(argc, argv, "c:fiM:mN:n:p:stw:z")) != -1) { + while ((c = getopt(argc, argv, "ac:fiM:mN:n:p:stw:z")) != -1) { switch (c) { + case 'a': + aflag++; + break; case 'c': reps = atoi(optarg); break; @@ -232,24 +234,18 @@ main(argc, argv) if (todo == 0) todo = VMSTAT; - /* - * Discard setgid privileges if not the running kernel so that bad - * guys can't print interesting stuff from kernel memory. - */ - if (nlistf != NULL || memf != NULL) - setgid(getgid()); - - kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); - if (kd == 0) - errx(1, "kvm_openfiles: %s", errbuf); - setgid(getgid()); + if (memf != NULL) { + kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); + if (kd == NULL) + errx(1, "kvm_openfiles: %s", errbuf); + } - if ((c = kvm_nlist(kd, namelist)) != 0) { + if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) { if (c > 0) { warnx("undefined symbols:"); for (c = 0; - c < (int)(sizeof(namelist)/sizeof(namelist[0])); - c++) + c < (int)(sizeof(namelist)/sizeof(namelist[0])); + c++) if (namelist[c].n_type == 0) (void)fprintf(stderr, " %s", namelist[c].n_name); @@ -313,9 +309,20 @@ main(argc, argv) exit(0); } -char ** -getdrivedata(argv) - char **argv; +static int +mysysctl(const char *name, void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + int error; + + error = sysctlbyname(name, oldp, oldlenp, newp, newlen); + if (error != 0 && errno != ENOMEM) + err(1, "sysctl(%s)", name); + return (error); +} + +static char ** +getdrivedata(char **argv) { if ((num_devices = devstat_getnumdevs(NULL)) < 0) errx(1, "%s", devstat_errbuf); @@ -379,15 +386,25 @@ getdrivedata(argv) return(argv); } -long -getuptime() +static long +getuptime(void) { static struct timeval boottime; static time_t now; time_t uptime; - if (boottime.tv_sec == 0) - kread(X_BOOTTIME, &boottime, sizeof(boottime)); + if (boottime.tv_sec == 0) { + if (kd != NULL) { + kread(X_BOOTTIME, &boottime, sizeof(boottime)); + } else { + size_t size; + + size = sizeof(boottime); + mysysctl("kern.boottime", &boottime, &size, NULL, 0); + if (size != sizeof(boottime)) + errx(1, "kern.boottime size mismatch"); + } + } (void)time(&now); uptime = now - boottime.tv_sec; if (uptime <= 0 || uptime > 60*60*24*365*10) @@ -395,32 +412,126 @@ getuptime() return(uptime); } -int hz, hdrcnt; +static void +fill_vmmeter(struct vmmeter *vmmp) +{ + if (kd != NULL) { + kread(X_SUM, vmmp, sizeof(*vmmp)); + } else { + size_t size = sizeof(unsigned int); +#define GET_VM_STATS(cat, name) \ + mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size, NULL, 0) + /* sys */ + GET_VM_STATS(sys, v_swtch); + GET_VM_STATS(sys, v_trap); + GET_VM_STATS(sys, v_syscall); + GET_VM_STATS(sys, v_intr); + GET_VM_STATS(sys, v_soft); + + /* vm */ + GET_VM_STATS(vm, v_vm_faults); + GET_VM_STATS(vm, v_cow_faults); + GET_VM_STATS(vm, v_cow_optim); + GET_VM_STATS(vm, v_zfod); + GET_VM_STATS(vm, v_ozfod); + GET_VM_STATS(vm, v_swapin); + GET_VM_STATS(vm, v_swapout); + GET_VM_STATS(vm, v_swappgsin); + GET_VM_STATS(vm, v_swappgsout); + GET_VM_STATS(vm, v_vnodein); + GET_VM_STATS(vm, v_vnodeout); + GET_VM_STATS(vm, v_vnodepgsin); + GET_VM_STATS(vm, v_vnodepgsout); + GET_VM_STATS(vm, v_intrans); + GET_VM_STATS(vm, v_reactivated); + GET_VM_STATS(vm, v_pdwakeups); + GET_VM_STATS(vm, v_pdpages); + GET_VM_STATS(vm, v_dfree); + GET_VM_STATS(vm, v_pfree); + GET_VM_STATS(vm, v_tfree); + GET_VM_STATS(vm, v_page_size); + GET_VM_STATS(vm, v_page_count); + GET_VM_STATS(vm, v_free_reserved); + GET_VM_STATS(vm, v_free_target); + GET_VM_STATS(vm, v_free_min); + GET_VM_STATS(vm, v_free_count); + GET_VM_STATS(vm, v_wire_count); + GET_VM_STATS(vm, v_active_count); + GET_VM_STATS(vm, v_inactive_target); + GET_VM_STATS(vm, v_inactive_count); + GET_VM_STATS(vm, v_cache_count); + GET_VM_STATS(vm, v_cache_min); + GET_VM_STATS(vm, v_cache_max); + GET_VM_STATS(vm, v_pageout_free_min); + GET_VM_STATS(vm, v_interrupt_free_min); + /*GET_VM_STATS(vm, v_free_severe);*/ + GET_VM_STATS(vm, v_forks); + GET_VM_STATS(vm, v_vforks); + GET_VM_STATS(vm, v_rforks); + GET_VM_STATS(vm, v_kthreads); + GET_VM_STATS(vm, v_forkpages); + GET_VM_STATS(vm, v_vforkpages); + GET_VM_STATS(vm, v_rforkpages); + GET_VM_STATS(vm, v_kthreadpages); +#undef GET_VM_STATS + } +} -void -dovmstat(interval, reps) - u_int interval; - int reps; +static void +fill_vmtotal(struct vmtotal *vmtp) +{ + if (kd != NULL) { + /* XXX fill vmtp */ + errx(1, "not implemented"); + } else { + size_t size = sizeof(*vmtp); + mysysctl("vm.vmtotal", vmtp, &size, NULL, 0); + if (size != sizeof(*vmtp)) + errx(1, "vm.total size mismatch"); + } +} + +static int hz, hdrcnt; + +static void +dovmstat(u_int interval, int reps) { struct vmtotal total; time_t uptime, halfuptime; struct devinfo *tmp_dinfo; - int mib[2]; size_t size; uptime = getuptime(); halfuptime = uptime / 2; (void)signal(SIGCONT, needhdr); - if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) - kread(X_STATHZ, &hz, sizeof(hz)); - if (!hz) - kread(X_HZ, &hz, sizeof(hz)); + if (kd != NULL) { + if (namelist[X_STATHZ].n_type != 0 && + namelist[X_STATHZ].n_value != 0) + kread(X_STATHZ, &hz, sizeof(hz)); + if (!hz) + kread(X_HZ, &hz, sizeof(hz)); + } else { + struct clockinfo clockrate; + + size = sizeof(clockrate); + mysysctl("kern.clockrate", &clockrate, &size, NULL, 0); + if (size != sizeof(clockrate)) + errx(1, "clockrate size mismatch"); + hz = clockrate.hz; + } for (hdrcnt = 1;;) { if (!--hdrcnt) printhdr(); - kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time)); + if (kd != NULL) { + kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time)); + } else { + size = sizeof(cur.cp_time); + mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0); + if (size != sizeof(cur.cp_time)) + errx(1, "cp_time size mismatch"); + } tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; @@ -466,15 +577,8 @@ dovmstat(interval, reps) break; } - kread(X_SUM, &sum, sizeof(sum)); - size = sizeof(total); - mib[0] = CTL_VM; - mib[1] = VM_TOTAL; - if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { - (void)printf("Can't get kerninfo: %s\n", - strerror(errno)); - bzero(&total, sizeof(total)); - } + fill_vmmeter(&sum); + fill_vmtotal(&total); (void)printf("%2d %1d %1d", total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); #define vmstat_pgtok(a) ((a) * sum.v_page_size >> 10) @@ -519,8 +623,8 @@ dovmstat(interval, reps) } } -void -printhdr() +static void +printhdr(void) { int i, num_shown; @@ -545,17 +649,16 @@ printhdr() /* * Force a header to be prepended to the next output. */ -void -needhdr(dummy) - int dummy __unused; +static void +needhdr(int dummy __unused) { hdrcnt = 1; } #ifdef notyet -void -dotimes() +static void +dotimes(void) { u_int pgintime, rectime; @@ -573,9 +676,8 @@ dotimes() } #endif -long -pct(top, bot) - long top, bot; +static long +pct(long top, long bot) { long ans; @@ -587,13 +689,13 @@ pct(top, bot) #define PCT(top, bot) pct((long)(top), (long)(bot)) -void -dosum() +static void +dosum(void) { struct nchstats lnchstats; long nchtotal; - kread(X_SUM, &sum, sizeof(sum)); + fill_vmmeter(&sum); (void)printf("%9u cpu context switches\n", sum.v_swtch); (void)printf("%9u device interrupts\n", sum.v_intr); (void)printf("%9u software interrupts\n", sum.v_soft); @@ -633,7 +735,14 @@ dosum() (void)printf("%9u pages wired down\n", sum.v_wire_count); (void)printf("%9u pages free\n", sum.v_free_count); (void)printf("%9u bytes per page\n", sum.v_page_size); - kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); + if (kd != NULL) { + kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); + } else { + size_t size = sizeof(lnchstats); + mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0); + if (size != sizeof(lnchstats)) + errx(1, "vfs.cache.nchstats size mismatch"); + } nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits + lnchstats.ncs_badhits + lnchstats.ncs_falsehits + lnchstats.ncs_miss + lnchstats.ncs_long; @@ -649,11 +758,10 @@ dosum() PCT(lnchstats.ncs_long, nchtotal)); } -void -doforkst() +static void +doforkst(void) { - - kread(X_SUM, &sum, sizeof(sum)); + fill_vmmeter(&sum); (void)printf("%d forks, %d pages, average %.2f\n", sum.v_forks, sum.v_forkpages, sum.v_forks == 0 ? 0.0 : @@ -669,13 +777,13 @@ doforkst() } static void -devstats() +devstats(void) { int dn, state; long double transfers_per_second; long double busy_seconds; long tmp; - + for (state = 0; state < CPUSTATES; ++state) { tmp = cur.cp_time[state]; cur.cp_time[state] -= last.cp_time[state]; @@ -703,8 +811,8 @@ devstats() } } -void -cpustats() +static void +cpustats(void) { int state; double lpct, total; @@ -723,8 +831,8 @@ cpustats() (void)printf("%2.0f", cur.cp_time[CP_IDLE] * lpct); } -void -dointr() +static void +dointr(void) { u_long *intrcnt, uptime; u_int64_t inttotal; @@ -734,15 +842,32 @@ dointr() char *intrname, *tintrname; uptime = getuptime(); - nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value; - inamlen = - namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; - intrcnt = malloc((size_t)nintr); - intrname = malloc((size_t)inamlen); - if (intrcnt == NULL || intrname == NULL) - errx(1, "malloc"); - kread(X_INTRCNT, intrcnt, (size_t)nintr); - kread(X_INTRNAMES, intrname, (size_t)inamlen); + if (kd != NULL) { + nintr = namelist[X_EINTRCNT].n_value - + namelist[X_INTRCNT].n_value; + inamlen = namelist[X_EINTRNAMES].n_value - + namelist[X_INTRNAMES].n_value; + if ((intrcnt = malloc((size_t)nintr)) == NULL || + (intrname = malloc((size_t)inamlen)) == NULL) + err(1, "malloc()"); + kread(X_INTRCNT, intrcnt, (size_t)nintr); + kread(X_INTRNAMES, intrname, (size_t)inamlen); + } else { + for (intrcnt = NULL, nintr = 1024; ; nintr *= 2) { + if ((intrcnt = reallocf(intrcnt, nintr)) == NULL) + err(1, "reallocf()"); + if (mysysctl("hw.intrcnt", + intrcnt, &nintr, NULL, 0) == 0) + break; + } + for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) { + if ((intrname = reallocf(intrname, inamlen)) == NULL) + err(1, "reallocf()"); + if (mysysctl("hw.intrnames", + intrname, &inamlen, NULL, 0) == 0) + break; + } + } nintr /= sizeof(u_long); tintrname = intrname; istrnamlen = strlen("interrupt"); @@ -756,7 +881,11 @@ dointr() "rate"); inttotal = 0; while (--nintr >= 0) { - if (*intrcnt) + const char *p; + if (intrname[0] != '\0' && + (aflag > 0 || *intrcnt != 0) && + (aflag > 1 || ((p = strchr(intrname, ' ')) && p[1] != ' ')) && + (aflag > 2 || strncmp(intrname, "stray ", 6) != 0)) (void)printf("%-*s %20lu %10lu\n", istrnamlen, intrname, *intrcnt, *intrcnt / uptime); intrname += strlen(intrname) + 1; @@ -766,33 +895,33 @@ dointr() inttotal / (u_int64_t) uptime); } -void +static void domem(void) { + if (kd != NULL) + errx(1, "not implemented"); dosysctl("kern.malloc"); } -void +static void dozmem(void) { + if (kd != NULL) + errx(1, "not implemented"); dosysctl("vm.zone"); } -void +static void dosysctl(char *name) { char *buf; size_t bufsize; - buf = NULL; - bufsize = 1024; - for (;;) { + for (buf = NULL, bufsize = 1024; ; bufsize *= 2) { if ((buf = realloc(buf, bufsize)) == NULL) err(1, "realloc()"); - if (sysctlbyname(name, buf, &bufsize, 0, NULL) == 0) + if (mysysctl(name, buf, &bufsize, 0, NULL) == 0) break; - if (errno != ENOMEM) - err(1, "sysctlbyname()"); bufsize *= 2; } buf[bufsize] = '\0'; /* play it safe */ @@ -803,11 +932,8 @@ dosysctl(char *name) /* * kread reads something from the kernel, given its nlist index. */ -void -kread(nlx, addr, size) - int nlx; - void *addr; - size_t size; +static void +kread(int nlx, void *addr, size_t size) { char *sym; @@ -825,11 +951,11 @@ kread(nlx, addr, size) } } -void -usage() +static void +usage(void) { (void)fprintf(stderr, "%s%s", - "usage: vmstat [-imsz] [-c count] [-M core] [-N system] [-w wait]\n", + "usage: vmstat [-aimsz] [-c count] [-M core] [-N system] [-w wait]\n", " [-n devs] [disks]\n"); exit(1); } |