vmstat.c revision 121626
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1986, 1991, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 3487690Smarkm#include <sys/cdefs.h> 3587690Smarkm 3687690Smarkm__FBSDID("$FreeBSD: head/usr.bin/vmstat/vmstat.c 121626 2003-10-28 05:02:03Z jmg $"); 3787690Smarkm 381590Srgrimes#ifndef lint 3928693Scharnierstatic const char copyright[] = 401590Srgrimes"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\ 411590Srgrimes The Regents of the University of California. All rights reserved.\n"; 4287690Smarkm#endif 431590Srgrimes 441590Srgrimes#ifndef lint 4587690Smarkmstatic const char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; 4628693Scharnier#endif 471590Srgrimes 481590Srgrimes#include <sys/param.h> 491590Srgrimes#include <sys/time.h> 501590Srgrimes#include <sys/proc.h> 5112811Sbde#include <sys/uio.h> 521590Srgrimes#include <sys/namei.h> 531590Srgrimes#include <sys/malloc.h> 541590Srgrimes#include <sys/signal.h> 551590Srgrimes#include <sys/fcntl.h> 561590Srgrimes#include <sys/ioctl.h> 57111008Sphk#include <sys/resource.h> 581590Srgrimes#include <sys/sysctl.h> 5912804Speter#include <sys/vmmeter.h> 6012811Sbde 6112811Sbde#include <vm/vm_param.h> 6212811Sbde 6328693Scharnier#include <ctype.h> 6487690Smarkm#include <devstat.h> 6528693Scharnier#include <err.h> 6628693Scharnier#include <errno.h> 6728693Scharnier#include <kvm.h> 6828693Scharnier#include <limits.h> 691590Srgrimes#include <nlist.h> 7028693Scharnier#include <paths.h> 711590Srgrimes#include <stdio.h> 721590Srgrimes#include <stdlib.h> 731590Srgrimes#include <string.h> 7430180Sdima#include <sysexits.h> 7528693Scharnier#include <time.h> 7628693Scharnier#include <unistd.h> 771590Srgrimes 7887690Smarkmstatic char da[] = "da"; 7987690Smarkm 8087690Smarkmstatic struct nlist namelist[] = { 811590Srgrimes#define X_CPTIME 0 821590Srgrimes { "_cp_time" }, 8339230Sgibbs#define X_SUM 1 841590Srgrimes { "_cnt" }, 8539230Sgibbs#define X_BOOTTIME 2 861590Srgrimes { "_boottime" }, 8739230Sgibbs#define X_HZ 3 881590Srgrimes { "_hz" }, 8939230Sgibbs#define X_STATHZ 4 901590Srgrimes { "_stathz" }, 9139230Sgibbs#define X_NCHSTATS 5 921590Srgrimes { "_nchstats" }, 9339230Sgibbs#define X_INTRNAMES 6 941590Srgrimes { "_intrnames" }, 9539230Sgibbs#define X_EINTRNAMES 7 961590Srgrimes { "_eintrnames" }, 9739230Sgibbs#define X_INTRCNT 8 981590Srgrimes { "_intrcnt" }, 9939230Sgibbs#define X_EINTRCNT 9 1001590Srgrimes { "_eintrcnt" }, 10130180Sdima#ifdef notyet 10294729Sjeff#define X_DEFICIT 10 1031590Srgrimes { "_deficit" }, 104113460Stjr#define X_REC 11 1051590Srgrimes { "_rectime" }, 106113460Stjr#define X_PGIN 12 1071590Srgrimes { "_pgintime" }, 108113460Stjr#define X_XSTATS 13 1091590Srgrimes { "_xstats" }, 110113460Stjr#define X_END 14 11192653Sjeff#else 11294729Sjeff#define X_END 10 1131590Srgrimes#endif 1141590Srgrimes { "" }, 1151590Srgrimes}; 1161590Srgrimes 11739230Sgibbsstruct statinfo cur, last; 11839498Skenint num_devices, maxshowdevs; 11939498Skenlong generation; 12039230Sgibbsstruct device_selection *dev_select; 12139230Sgibbsint num_selected; 12239230Sgibbsstruct devstat_match *matches; 12339230Sgibbsint num_matches = 0; 12439498Skenint num_devices_specified, num_selections; 12539498Skenlong select_generation; 12639230Sgibbschar **specified_devices; 12739230Sgibbsdevstat_select_mode select_mode; 1281590Srgrimes 1291590Srgrimesstruct vmmeter sum, osum; 1301590Srgrimes 1311590Srgrimesint winlines = 20; 13239372Sdillonint nflag = 0; 1331590Srgrimes 1341590Srgrimeskvm_t *kd; 1351590Srgrimes 1361590Srgrimes#define FORKSTAT 0x01 1371590Srgrimes#define INTRSTAT 0x02 1381590Srgrimes#define MEMSTAT 0x04 1391590Srgrimes#define SUMSTAT 0x08 1401590Srgrimes#define TIMESTAT 0x10 1411590Srgrimes#define VMSTAT 0x20 14243962Sdillon#define ZMEMSTAT 0x40 1431590Srgrimes 14492922Simpstatic void cpustats(void); 14592922Simpstatic void devstats(void); 14694729Sjeffstatic void dosysctl(char *); 14792922Simpstatic void domem(void); 14892922Simpstatic void dointr(void); 14992922Simpstatic void dosum(void); 150113460Stjrstatic void doforkst(void); 15192922Simpstatic void dovmstat(u_int, int); 15292922Simpstatic void dozmem(void); 15392922Simpstatic void kread(int, void *, size_t); 15492922Simpstatic void needhdr(int); 15592922Simpstatic void printhdr(void); 15692922Simpstatic void usage(void); 1571590Srgrimes 15892922Simpstatic long pct(long, long); 15992922Simpstatic long getuptime(void); 16087690Smarkm 16192922Simpchar **getdrivedata(char **); 16287690Smarkm 16328693Scharnierint 1641590Srgrimesmain(argc, argv) 16587690Smarkm int argc; 16687690Smarkm char **argv; 1671590Srgrimes{ 16887690Smarkm int c, todo; 1691590Srgrimes u_int interval; 1701590Srgrimes int reps; 1711590Srgrimes char *memf, *nlistf; 17278474Sschweikh char errbuf[_POSIX2_LINE_MAX]; 1731590Srgrimes 1741590Srgrimes memf = nlistf = NULL; 1751590Srgrimes interval = reps = todo = 0; 17643822Sken maxshowdevs = 2; 17744067Sbde while ((c = getopt(argc, argv, "c:fiM:mN:n:p:stw:z")) != -1) { 1781590Srgrimes switch (c) { 1791590Srgrimes case 'c': 1801590Srgrimes reps = atoi(optarg); 1811590Srgrimes break; 1821590Srgrimes case 'f': 183113460Stjr todo |= FORKSTAT; 1841590Srgrimes break; 1851590Srgrimes case 'i': 1861590Srgrimes todo |= INTRSTAT; 1871590Srgrimes break; 1881590Srgrimes case 'M': 1891590Srgrimes memf = optarg; 1901590Srgrimes break; 1911590Srgrimes case 'm': 1921590Srgrimes todo |= MEMSTAT; 1931590Srgrimes break; 1941590Srgrimes case 'N': 1951590Srgrimes nlistf = optarg; 1961590Srgrimes break; 19739230Sgibbs case 'n': 19839372Sdillon nflag = 1; 19939230Sgibbs maxshowdevs = atoi(optarg); 20039230Sgibbs if (maxshowdevs < 0) 20139230Sgibbs errx(1, "number of devices %d is < 0", 20239230Sgibbs maxshowdevs); 20339230Sgibbs break; 20439230Sgibbs case 'p': 205112284Sphk if (devstat_buildmatch(optarg, &matches, &num_matches) != 0) 20639230Sgibbs errx(1, "%s", devstat_errbuf); 20739230Sgibbs break; 2081590Srgrimes case 's': 2091590Srgrimes todo |= SUMSTAT; 2101590Srgrimes break; 2111590Srgrimes case 't': 21230180Sdima#ifdef notyet 2131590Srgrimes todo |= TIMESTAT; 21430180Sdima#else 21530180Sdima errx(EX_USAGE, "sorry, -t is not (re)implemented yet"); 21630180Sdima#endif 2171590Srgrimes break; 2181590Srgrimes case 'w': 2191590Srgrimes interval = atoi(optarg); 2201590Srgrimes break; 22144067Sbde case 'z': 22244067Sbde todo |= ZMEMSTAT; 22344067Sbde break; 2241590Srgrimes case '?': 2251590Srgrimes default: 2261590Srgrimes usage(); 2271590Srgrimes } 2281590Srgrimes } 2291590Srgrimes argc -= optind; 2301590Srgrimes argv += optind; 2311590Srgrimes 2321590Srgrimes if (todo == 0) 2331590Srgrimes todo = VMSTAT; 2341590Srgrimes 2351590Srgrimes /* 2361590Srgrimes * Discard setgid privileges if not the running kernel so that bad 2371590Srgrimes * guys can't print interesting stuff from kernel memory. 2381590Srgrimes */ 2391590Srgrimes if (nlistf != NULL || memf != NULL) 2401590Srgrimes setgid(getgid()); 2411590Srgrimes 24228693Scharnier kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 24328693Scharnier if (kd == 0) 24428693Scharnier errx(1, "kvm_openfiles: %s", errbuf); 24582664Sru setgid(getgid()); 2461590Srgrimes 2471590Srgrimes if ((c = kvm_nlist(kd, namelist)) != 0) { 2481590Srgrimes if (c > 0) { 24928693Scharnier warnx("undefined symbols:"); 2501590Srgrimes for (c = 0; 25187690Smarkm c < (int)(sizeof(namelist)/sizeof(namelist[0])); 25287690Smarkm c++) 2531590Srgrimes if (namelist[c].n_type == 0) 25481537Sken (void)fprintf(stderr, " %s", 2551590Srgrimes namelist[c].n_name); 2561590Srgrimes (void)fputc('\n', stderr); 2571590Srgrimes } else 25828693Scharnier warnx("kvm_nlist: %s", kvm_geterr(kd)); 2591590Srgrimes exit(1); 2601590Srgrimes } 2611590Srgrimes 2621590Srgrimes if (todo & VMSTAT) { 2631590Srgrimes struct winsize winsize; 2641590Srgrimes 26543819Sken /* 26643819Sken * Make sure that the userland devstat version matches the 26743819Sken * kernel devstat version. If not, exit and print a 26843819Sken * message informing the user of his mistake. 26943819Sken */ 270112284Sphk if (devstat_checkversion(NULL) < 0) 27143819Sken errx(1, "%s", devstat_errbuf); 27243819Sken 27343819Sken 2741590Srgrimes argv = getdrivedata(argv); 2751590Srgrimes winsize.ws_row = 0; 2761590Srgrimes (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize); 2771590Srgrimes if (winsize.ws_row > 0) 2781590Srgrimes winlines = winsize.ws_row; 2791590Srgrimes 2801590Srgrimes } 2811590Srgrimes 2821590Srgrimes#define BACKWARD_COMPATIBILITY 2831590Srgrimes#ifdef BACKWARD_COMPATIBILITY 2841590Srgrimes if (*argv) { 2851590Srgrimes interval = atoi(*argv); 2861590Srgrimes if (*++argv) 2871590Srgrimes reps = atoi(*argv); 2881590Srgrimes } 2891590Srgrimes#endif 2901590Srgrimes 2911590Srgrimes if (interval) { 2921590Srgrimes if (!reps) 2931590Srgrimes reps = -1; 2941590Srgrimes } else if (reps) 2951590Srgrimes interval = 1; 2961590Srgrimes 2971590Srgrimes if (todo & FORKSTAT) 2981590Srgrimes doforkst(); 2991590Srgrimes if (todo & MEMSTAT) 3001590Srgrimes domem(); 30143962Sdillon if (todo & ZMEMSTAT) 30243962Sdillon dozmem(); 3031590Srgrimes if (todo & SUMSTAT) 3041590Srgrimes dosum(); 30530180Sdima#ifdef notyet 3061590Srgrimes if (todo & TIMESTAT) 3071590Srgrimes dotimes(); 3081590Srgrimes#endif 3091590Srgrimes if (todo & INTRSTAT) 3101590Srgrimes dointr(); 3111590Srgrimes if (todo & VMSTAT) 3121590Srgrimes dovmstat(interval, reps); 3131590Srgrimes exit(0); 3141590Srgrimes} 3151590Srgrimes 3161590Srgrimeschar ** 3171590Srgrimesgetdrivedata(argv) 3181590Srgrimes char **argv; 3191590Srgrimes{ 320112284Sphk if ((num_devices = devstat_getnumdevs(NULL)) < 0) 32139230Sgibbs errx(1, "%s", devstat_errbuf); 3221590Srgrimes 32339230Sgibbs cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 32439230Sgibbs last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 32539230Sgibbs bzero(cur.dinfo, sizeof(struct devinfo)); 32639230Sgibbs bzero(last.dinfo, sizeof(struct devinfo)); 32739230Sgibbs 328112284Sphk if (devstat_getdevs(NULL, &cur) == -1) 32939230Sgibbs errx(1, "%s", devstat_errbuf); 33039230Sgibbs 33139230Sgibbs num_devices = cur.dinfo->numdevs; 33239230Sgibbs generation = cur.dinfo->generation; 33339230Sgibbs 33439230Sgibbs specified_devices = (char **)malloc(sizeof(char *)); 33539230Sgibbs for (num_devices_specified = 0; *argv; ++argv) { 3361590Srgrimes if (isdigit(**argv)) 3371590Srgrimes break; 33839230Sgibbs num_devices_specified++; 33939230Sgibbs specified_devices = (char **)realloc(specified_devices, 34039230Sgibbs sizeof(char *) * 34139230Sgibbs num_devices_specified); 34239230Sgibbs specified_devices[num_devices_specified - 1] = *argv; 3431590Srgrimes } 34439230Sgibbs dev_select = NULL; 34539230Sgibbs 34639372Sdillon if (nflag == 0 && maxshowdevs < num_devices_specified) 34739372Sdillon maxshowdevs = num_devices_specified; 34839372Sdillon 34939230Sgibbs /* 35039230Sgibbs * People are generally only interested in disk statistics when 35139230Sgibbs * they're running vmstat. So, that's what we're going to give 35239230Sgibbs * them if they don't specify anything by default. We'll also give 35339230Sgibbs * them any other random devices in the system so that we get to 35439230Sgibbs * maxshowdevs devices, if that many devices exist. If the user 35539230Sgibbs * specifies devices on the command line, either through a pattern 35639230Sgibbs * match or by naming them explicitly, we will give the user only 35739230Sgibbs * those devices. 35839230Sgibbs */ 35939230Sgibbs if ((num_devices_specified == 0) && (num_matches == 0)) { 360112284Sphk if (devstat_buildmatch(da, &matches, &num_matches) != 0) 36139230Sgibbs errx(1, "%s", devstat_errbuf); 36239230Sgibbs 36339230Sgibbs select_mode = DS_SELECT_ADD; 36439230Sgibbs } else 36539230Sgibbs select_mode = DS_SELECT_ONLY; 36639230Sgibbs 36739230Sgibbs /* 36839230Sgibbs * At this point, selectdevs will almost surely indicate that the 36939230Sgibbs * device list has changed, so we don't look for return values of 0 37039230Sgibbs * or 1. If we get back -1, though, there is an error. 37139230Sgibbs */ 372112284Sphk if (devstat_selectdevs(&dev_select, &num_selected, &num_selections, 37339230Sgibbs &select_generation, generation, cur.dinfo->devices, 37439230Sgibbs num_devices, matches, num_matches, specified_devices, 37539230Sgibbs num_devices_specified, select_mode, 37639230Sgibbs maxshowdevs, 0) == -1) 37739230Sgibbs errx(1, "%s", devstat_errbuf); 37839230Sgibbs 3791590Srgrimes return(argv); 3801590Srgrimes} 3811590Srgrimes 3821590Srgrimeslong 3831590Srgrimesgetuptime() 3841590Srgrimes{ 385101590Stmm static struct timeval boottime; 386101590Stmm static time_t now; 3871590Srgrimes time_t uptime; 3881590Srgrimes 389101590Stmm if (boottime.tv_sec == 0) 3901590Srgrimes kread(X_BOOTTIME, &boottime, sizeof(boottime)); 3911590Srgrimes (void)time(&now); 392101590Stmm uptime = now - boottime.tv_sec; 39328693Scharnier if (uptime <= 0 || uptime > 60*60*24*365*10) 39428693Scharnier errx(1, "time makes no sense; namelist must be wrong"); 3951590Srgrimes return(uptime); 3961590Srgrimes} 3971590Srgrimes 3981590Srgrimesint hz, hdrcnt; 3991590Srgrimes 4001590Srgrimesvoid 4011590Srgrimesdovmstat(interval, reps) 4021590Srgrimes u_int interval; 4031590Srgrimes int reps; 4041590Srgrimes{ 4051590Srgrimes struct vmtotal total; 4061590Srgrimes time_t uptime, halfuptime; 40739230Sgibbs struct devinfo *tmp_dinfo; 40880551Stmm int mib[2]; 40980551Stmm size_t size; 4101590Srgrimes 4111590Srgrimes uptime = getuptime(); 4121590Srgrimes halfuptime = uptime / 2; 4131590Srgrimes (void)signal(SIGCONT, needhdr); 4141590Srgrimes 4151590Srgrimes if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) 4161590Srgrimes kread(X_STATHZ, &hz, sizeof(hz)); 4171590Srgrimes if (!hz) 4181590Srgrimes kread(X_HZ, &hz, sizeof(hz)); 4191590Srgrimes 4201590Srgrimes for (hdrcnt = 1;;) { 4211590Srgrimes if (!--hdrcnt) 4221590Srgrimes printhdr(); 42339230Sgibbs kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time)); 42439230Sgibbs 42539230Sgibbs tmp_dinfo = last.dinfo; 42639230Sgibbs last.dinfo = cur.dinfo; 42739230Sgibbs cur.dinfo = tmp_dinfo; 428112288Sphk last.snap_time = cur.snap_time; 42939230Sgibbs 43039230Sgibbs /* 43139230Sgibbs * Here what we want to do is refresh our device stats. 43239230Sgibbs * getdevs() returns 1 when the device list has changed. 43339230Sgibbs * If the device list has changed, we want to go through 43439230Sgibbs * the selection process again, in case a device that we 43539230Sgibbs * were previously displaying has gone away. 43639230Sgibbs */ 437112284Sphk switch (devstat_getdevs(NULL, &cur)) { 43839230Sgibbs case -1: 43939230Sgibbs errx(1, "%s", devstat_errbuf); 44039230Sgibbs break; 44139230Sgibbs case 1: { 44239230Sgibbs int retval; 44339230Sgibbs 44439230Sgibbs num_devices = cur.dinfo->numdevs; 44539230Sgibbs generation = cur.dinfo->generation; 44639230Sgibbs 447112284Sphk retval = devstat_selectdevs(&dev_select, &num_selected, 44839230Sgibbs &num_selections, &select_generation, 44939230Sgibbs generation, cur.dinfo->devices, 45039230Sgibbs num_devices, matches, num_matches, 45139230Sgibbs specified_devices, 45239230Sgibbs num_devices_specified, select_mode, 45339230Sgibbs maxshowdevs, 0); 45439230Sgibbs switch (retval) { 45539230Sgibbs case -1: 45639230Sgibbs errx(1, "%s", devstat_errbuf); 45739230Sgibbs break; 45839230Sgibbs case 1: 45939230Sgibbs printhdr(); 46039230Sgibbs break; 46139230Sgibbs default: 46239230Sgibbs break; 46339230Sgibbs } 46439230Sgibbs } 46539230Sgibbs default: 46639230Sgibbs break; 46739230Sgibbs } 46839230Sgibbs 4691590Srgrimes kread(X_SUM, &sum, sizeof(sum)); 4701590Srgrimes size = sizeof(total); 4711590Srgrimes mib[0] = CTL_VM; 472109097Sdillon mib[1] = VM_TOTAL; 4731590Srgrimes if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { 47481537Sken (void)printf("Can't get kerninfo: %s\n", 47581537Sken strerror(errno)); 4761590Srgrimes bzero(&total, sizeof(total)); 4771590Srgrimes } 47878672Sschweikh (void)printf("%2d %1d %1d", 4791590Srgrimes total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); 48072887Salfred#define vmstat_pgtok(a) ((a) * sum.v_page_size >> 10) 4811590Srgrimes#define rate(x) (((x) + halfuptime) / uptime) /* round */ 48281537Sken (void)printf(" %7ld %6ld ", (long)vmstat_pgtok(total.t_avm), 48381537Sken (long)vmstat_pgtok(total.t_free)); 48437453Sbde (void)printf("%4lu ", 48537453Sbde (u_long)rate(sum.v_vm_faults - osum.v_vm_faults)); 4861590Srgrimes (void)printf("%3lu ", 48737453Sbde (u_long)rate(sum.v_reactivated - osum.v_reactivated)); 48837453Sbde (void)printf("%3lu ", 48937453Sbde (u_long)rate(sum.v_swapin + sum.v_vnodein - 4903659Sdg (osum.v_swapin + osum.v_vnodein))); 49137453Sbde (void)printf("%3lu ", 49237453Sbde (u_long)rate(sum.v_swapout + sum.v_vnodeout - 4933693Sdg (osum.v_swapout + osum.v_vnodeout))); 49437453Sbde (void)printf("%3lu ", 49537453Sbde (u_long)rate(sum.v_tfree - osum.v_tfree)); 49637453Sbde (void)printf("%3lu ", 49737453Sbde (u_long)rate(sum.v_pdpages - osum.v_pdpages)); 49839230Sgibbs devstats(); 4991590Srgrimes (void)printf("%4lu %4lu %3lu ", 50037453Sbde (u_long)rate(sum.v_intr - osum.v_intr), 50137453Sbde (u_long)rate(sum.v_syscall - osum.v_syscall), 50237453Sbde (u_long)rate(sum.v_swtch - osum.v_swtch)); 5031590Srgrimes cpustats(); 5041590Srgrimes (void)printf("\n"); 5051590Srgrimes (void)fflush(stdout); 5061590Srgrimes if (reps >= 0 && --reps <= 0) 5071590Srgrimes break; 5081590Srgrimes osum = sum; 5091590Srgrimes uptime = interval; 5101590Srgrimes /* 5111590Srgrimes * We round upward to avoid losing low-frequency events 5121590Srgrimes * (i.e., >= 1 per interval but < 1 per second). 5131590Srgrimes */ 5143659Sdg if (interval != 1) 5153659Sdg halfuptime = (uptime + 1) / 2; 5163659Sdg else 5173659Sdg halfuptime = 0; 5181590Srgrimes (void)sleep(interval); 5191590Srgrimes } 5201590Srgrimes} 5211590Srgrimes 52228693Scharniervoid 5231590Srgrimesprinthdr() 5241590Srgrimes{ 52543822Sken int i, num_shown; 5261590Srgrimes 52743822Sken num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs; 52878672Sschweikh (void)printf(" procs memory page%*s", 19, ""); 52943822Sken if (num_shown > 1) 53043822Sken (void)printf(" disks %*s", num_shown * 4 - 7, ""); 53143822Sken else if (num_shown == 1) 53243822Sken (void)printf("disk"); 53343822Sken (void)printf(" faults cpu\n"); 53478672Sschweikh (void)printf(" r b w avm fre flt re pi po fr sr "); 53539230Sgibbs for (i = 0; i < num_devices; i++) 53639230Sgibbs if ((dev_select[i].selected) 53739230Sgibbs && (dev_select[i].selected <= maxshowdevs)) 53839230Sgibbs (void)printf("%c%c%d ", dev_select[i].device_name[0], 53939230Sgibbs dev_select[i].device_name[1], 54039230Sgibbs dev_select[i].unit_number); 5411590Srgrimes (void)printf(" in sy cs us sy id\n"); 5421590Srgrimes hdrcnt = winlines - 2; 5431590Srgrimes} 5441590Srgrimes 5451590Srgrimes/* 5461590Srgrimes * Force a header to be prepended to the next output. 5471590Srgrimes */ 5481590Srgrimesvoid 54987690Smarkmneedhdr(dummy) 55087690Smarkm int dummy __unused; 5511590Srgrimes{ 5521590Srgrimes 5531590Srgrimes hdrcnt = 1; 5541590Srgrimes} 5551590Srgrimes 55630180Sdima#ifdef notyet 5571590Srgrimesvoid 5581590Srgrimesdotimes() 5591590Srgrimes{ 5601590Srgrimes u_int pgintime, rectime; 5611590Srgrimes 5621590Srgrimes kread(X_REC, &rectime, sizeof(rectime)); 5631590Srgrimes kread(X_PGIN, &pgintime, sizeof(pgintime)); 5641590Srgrimes kread(X_SUM, &sum, sizeof(sum)); 5651590Srgrimes (void)printf("%u reclaims, %u total time (usec)\n", 5661590Srgrimes sum.v_pgrec, rectime); 5671590Srgrimes (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); 5681590Srgrimes (void)printf("\n"); 5691590Srgrimes (void)printf("%u page ins, %u total time (msec)\n", 5701590Srgrimes sum.v_pgin, pgintime / 10); 5711590Srgrimes (void)printf("average: %8.1f msec / page in\n", 5721590Srgrimes pgintime / (sum.v_pgin * 10.0)); 5731590Srgrimes} 5741590Srgrimes#endif 5751590Srgrimes 57628693Scharnierlong 5771590Srgrimespct(top, bot) 5781590Srgrimes long top, bot; 5791590Srgrimes{ 5801590Srgrimes long ans; 5811590Srgrimes 5821590Srgrimes if (bot == 0) 5831590Srgrimes return(0); 5841590Srgrimes ans = (quad_t)top * 100 / bot; 5851590Srgrimes return (ans); 5861590Srgrimes} 5871590Srgrimes 5881590Srgrimes#define PCT(top, bot) pct((long)(top), (long)(bot)) 5891590Srgrimes 5901590Srgrimesvoid 5911590Srgrimesdosum() 5921590Srgrimes{ 59387690Smarkm struct nchstats lnchstats; 5941590Srgrimes long nchtotal; 5951590Srgrimes 5961590Srgrimes kread(X_SUM, &sum, sizeof(sum)); 5971590Srgrimes (void)printf("%9u cpu context switches\n", sum.v_swtch); 5981590Srgrimes (void)printf("%9u device interrupts\n", sum.v_intr); 5991590Srgrimes (void)printf("%9u software interrupts\n", sum.v_soft); 6001590Srgrimes (void)printf("%9u traps\n", sum.v_trap); 6011590Srgrimes (void)printf("%9u system calls\n", sum.v_syscall); 60271429Sume (void)printf("%9u kernel threads created\n", sum.v_kthreads); 60371429Sume (void)printf("%9u fork() calls\n", sum.v_forks); 60471429Sume (void)printf("%9u vfork() calls\n", sum.v_vforks); 60571429Sume (void)printf("%9u rfork() calls\n", sum.v_rforks); 6063659Sdg (void)printf("%9u swap pager pageins\n", sum.v_swapin); 6073693Sdg (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin); 6083659Sdg (void)printf("%9u swap pager pageouts\n", sum.v_swapout); 6093659Sdg (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout); 6103659Sdg (void)printf("%9u vnode pager pageins\n", sum.v_vnodein); 6113693Sdg (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin); 6123659Sdg (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout); 6133659Sdg (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout); 6143693Sdg (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups); 6153693Sdg (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages); 6161590Srgrimes (void)printf("%9u pages reactivated\n", sum.v_reactivated); 6177351Sdg (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); 61834214Sdyson (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim); 6197351Sdg (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod); 62034214Sdyson (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod); 6211590Srgrimes (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); 6221590Srgrimes (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); 62371429Sume (void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages); 62471429Sume (void)printf("%9u pages affected by fork()\n", sum.v_forkpages); 62571429Sume (void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages); 62671429Sume (void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages); 6273693Sdg (void)printf("%9u pages freed\n", sum.v_tfree); 6281590Srgrimes (void)printf("%9u pages freed by daemon\n", sum.v_dfree); 6291590Srgrimes (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); 6301590Srgrimes (void)printf("%9u pages active\n", sum.v_active_count); 6311590Srgrimes (void)printf("%9u pages inactive\n", sum.v_inactive_count); 6325463Sdg (void)printf("%9u pages in VM cache\n", sum.v_cache_count); 6333693Sdg (void)printf("%9u pages wired down\n", sum.v_wire_count); 6343693Sdg (void)printf("%9u pages free\n", sum.v_free_count); 6351590Srgrimes (void)printf("%9u bytes per page\n", sum.v_page_size); 63687690Smarkm kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); 63787690Smarkm nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits + 63887690Smarkm lnchstats.ncs_badhits + lnchstats.ncs_falsehits + 63987690Smarkm lnchstats.ncs_miss + lnchstats.ncs_long; 6401590Srgrimes (void)printf("%9ld total name lookups\n", nchtotal); 6411590Srgrimes (void)printf( 64228693Scharnier "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n", 64387690Smarkm "", PCT(lnchstats.ncs_goodhits, nchtotal), 64487690Smarkm PCT(lnchstats.ncs_neghits, nchtotal), 64587690Smarkm PCT(lnchstats.ncs_pass2, nchtotal)); 64628693Scharnier (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "", 64787690Smarkm PCT(lnchstats.ncs_badhits, nchtotal), 64887690Smarkm PCT(lnchstats.ncs_falsehits, nchtotal), 64987690Smarkm PCT(lnchstats.ncs_long, nchtotal)); 6501590Srgrimes} 6511590Srgrimes 6521590Srgrimesvoid 6531590Srgrimesdoforkst() 6541590Srgrimes{ 6551590Srgrimes 656113460Stjr kread(X_SUM, &sum, sizeof(sum)); 6571590Srgrimes (void)printf("%d forks, %d pages, average %.2f\n", 658113460Stjr sum.v_forks, sum.v_forkpages, 659113460Stjr sum.v_forks == 0 ? 0.0 : 660113460Stjr (double)sum.v_forkpages / sum.v_forks); 6611590Srgrimes (void)printf("%d vforks, %d pages, average %.2f\n", 662113460Stjr sum.v_vforks, sum.v_vforkpages, 663113460Stjr sum.v_vforks == 0 ? 0.0 : 664113460Stjr (double)sum.v_vforkpages / sum.v_vforks); 665113460Stjr (void)printf("%d rforks, %d pages, average %.2f\n", 666113460Stjr sum.v_rforks, sum.v_rforkpages, 667113460Stjr sum.v_rforks == 0 ? 0.0 : 668113460Stjr (double)sum.v_rforkpages / sum.v_rforks); 6691590Srgrimes} 6701590Srgrimes 67139230Sgibbsstatic void 67239230Sgibbsdevstats() 6731590Srgrimes{ 67487690Smarkm int dn, state; 67539230Sgibbs long double transfers_per_second; 67639230Sgibbs long double busy_seconds; 6771590Srgrimes long tmp; 67839230Sgibbs 6791590Srgrimes for (state = 0; state < CPUSTATES; ++state) { 68039230Sgibbs tmp = cur.cp_time[state]; 68139230Sgibbs cur.cp_time[state] -= last.cp_time[state]; 68239230Sgibbs last.cp_time[state] = tmp; 6831590Srgrimes } 68439230Sgibbs 685112288Sphk busy_seconds = cur.snap_time - last.snap_time; 68639230Sgibbs 68739230Sgibbs for (dn = 0; dn < num_devices; dn++) { 68839230Sgibbs int di; 68939230Sgibbs 69039230Sgibbs if ((dev_select[dn].selected == 0) 69139230Sgibbs || (dev_select[dn].selected > maxshowdevs)) 6921590Srgrimes continue; 69339230Sgibbs 69439230Sgibbs di = dev_select[dn].position; 69539230Sgibbs 69681537Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 69781537Sken &last.dinfo->devices[di], busy_seconds, 69881537Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 69981537Sken DSM_NONE) != 0) 70039230Sgibbs errx(1, "%s", devstat_errbuf); 70139230Sgibbs 70281537Sken (void)printf("%3.0Lf ", transfers_per_second); 7031590Srgrimes } 7041590Srgrimes} 7051590Srgrimes 7061590Srgrimesvoid 7071590Srgrimescpustats() 7081590Srgrimes{ 70987690Smarkm int state; 71087690Smarkm double lpct, total; 7111590Srgrimes 7121590Srgrimes total = 0; 7131590Srgrimes for (state = 0; state < CPUSTATES; ++state) 71439230Sgibbs total += cur.cp_time[state]; 7151590Srgrimes if (total) 71687690Smarkm lpct = 100.0 / total; 7171590Srgrimes else 71887690Smarkm lpct = 0.0; 71939230Sgibbs (void)printf("%2.0f ", (cur.cp_time[CP_USER] + 72087690Smarkm cur.cp_time[CP_NICE]) * lpct); 72139230Sgibbs (void)printf("%2.0f ", (cur.cp_time[CP_SYS] + 72287690Smarkm cur.cp_time[CP_INTR]) * lpct); 72387690Smarkm (void)printf("%2.0f", cur.cp_time[CP_IDLE] * lpct); 7241590Srgrimes} 7251590Srgrimes 7261590Srgrimesvoid 7271590Srgrimesdointr() 7281590Srgrimes{ 72987690Smarkm u_long *intrcnt, uptime; 73087690Smarkm u_int64_t inttotal; 73187690Smarkm int nintr, inamlen; 732121626Sjmg int i, istrnamlen; 733121626Sjmg size_t clen; 734121626Sjmg char *intrname, *tintrname; 7351590Srgrimes 7361590Srgrimes uptime = getuptime(); 7371590Srgrimes nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value; 7381590Srgrimes inamlen = 7391590Srgrimes namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; 7401590Srgrimes intrcnt = malloc((size_t)nintr); 7411590Srgrimes intrname = malloc((size_t)inamlen); 74228693Scharnier if (intrcnt == NULL || intrname == NULL) 74328693Scharnier errx(1, "malloc"); 7441590Srgrimes kread(X_INTRCNT, intrcnt, (size_t)nintr); 7451590Srgrimes kread(X_INTRNAMES, intrname, (size_t)inamlen); 746121626Sjmg tintrname = intrname; 747121626Sjmg istrnamlen = 14; 748121626Sjmg for (i = 0; i < nintr; i++) { 749121626Sjmg clen = strlen(tintrname); 750121626Sjmg if (clen > istrnamlen) 751121626Sjmg istrnamlen = clen; 752121626Sjmg tintrname += clen + 1; 753121626Sjmg } 754121626Sjmg (void)printf("%-*s %20s %10s\n", istrnamlen, "interrupt", "total", 755121626Sjmg "rate"); 7561590Srgrimes inttotal = 0; 7571590Srgrimes nintr /= sizeof(long); 7581590Srgrimes while (--nintr >= 0) { 7591590Srgrimes if (*intrcnt) 760121626Sjmg (void)printf("%-*s %20lu %10lu\n", istrnamlen, intrname, 7611590Srgrimes *intrcnt, *intrcnt / uptime); 7621590Srgrimes intrname += strlen(intrname) + 1; 7631590Srgrimes inttotal += *intrcnt++; 7641590Srgrimes } 765121626Sjmg (void)printf("%-*s %20llu %10llu\n", istrnamlen, "Total", inttotal, 76649107Sn_hibma inttotal / (u_int64_t) uptime); 7671590Srgrimes} 7681590Srgrimes 76994729Sjeffvoid 77094729Sjeffdomem(void) 77194729Sjeff{ 77294729Sjeff dosysctl("kern.malloc"); 77394729Sjeff} 77446852Simp 7751590Srgrimesvoid 77694729Sjeffdozmem(void) 7771590Srgrimes{ 77894729Sjeff dosysctl("vm.zone"); 7791590Srgrimes} 7801590Srgrimes 78143962Sdillonvoid 78294729Sjeffdosysctl(char *name) 78343962Sdillon{ 78471404Sdes char *buf; 78571404Sdes size_t bufsize; 78643962Sdillon 78771404Sdes buf = NULL; 78871404Sdes bufsize = 1024; 78971404Sdes for (;;) { 79071404Sdes if ((buf = realloc(buf, bufsize)) == NULL) 79171404Sdes err(1, "realloc()"); 79294729Sjeff if (sysctlbyname(name, buf, &bufsize, 0, NULL) == 0) 79343962Sdillon break; 79471404Sdes if (errno != ENOMEM) 79571404Sdes err(1, "sysctl()"); 79671404Sdes bufsize *= 2; 79743962Sdillon } 79871404Sdes buf[bufsize] = '\0'; /* play it safe */ 79971404Sdes (void)printf("%s\n\n", buf); 80071404Sdes free(buf); 80143962Sdillon} 80243962Sdillon 8031590Srgrimes/* 8041590Srgrimes * kread reads something from the kernel, given its nlist index. 8051590Srgrimes */ 8061590Srgrimesvoid 8071590Srgrimeskread(nlx, addr, size) 8081590Srgrimes int nlx; 8091590Srgrimes void *addr; 8101590Srgrimes size_t size; 8111590Srgrimes{ 8121590Srgrimes char *sym; 8131590Srgrimes 81440690Sjdp if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { 8151590Srgrimes sym = namelist[nlx].n_name; 8161590Srgrimes if (*sym == '_') 8171590Srgrimes ++sym; 81828693Scharnier errx(1, "symbol %s not defined", sym); 8191590Srgrimes } 82087690Smarkm if (kvm_read(kd, namelist[nlx].n_value, addr, size) != (int)size) { 8211590Srgrimes sym = namelist[nlx].n_name; 8221590Srgrimes if (*sym == '_') 8231590Srgrimes ++sym; 82428693Scharnier errx(1, "%s: %s", sym, kvm_geterr(kd)); 8251590Srgrimes } 8261590Srgrimes} 8271590Srgrimes 8281590Srgrimesvoid 8291590Srgrimesusage() 8301590Srgrimes{ 83172887Salfred (void)fprintf(stderr, "%s%s", 83272887Salfred "usage: vmstat [-imsz] [-c count] [-M core] [-N system] [-w wait]\n", 83372887Salfred " [-n devs] [disks]\n"); 8341590Srgrimes exit(1); 8351590Srgrimes} 836