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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3128693Scharnierstatic const char copyright[] = 321590Srgrimes"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\ 331590Srgrimes The Regents of the University of California. All rights reserved.\n"; 34123441Sbde#endif /* not lint */ 351590Srgrimes 36123441Sbde#if 0 371590Srgrimes#ifndef lint 38123441Sbdestatic char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; 39123441Sbde#endif /* not lint */ 4028693Scharnier#endif 411590Srgrimes 42123441Sbde#include <sys/cdefs.h> 43123441Sbde__FBSDID("$FreeBSD$"); 44123441Sbde 451590Srgrimes#include <sys/param.h> 461590Srgrimes#include <sys/proc.h> 4712811Sbde#include <sys/uio.h> 481590Srgrimes#include <sys/namei.h> 491590Srgrimes#include <sys/malloc.h> 501590Srgrimes#include <sys/signal.h> 511590Srgrimes#include <sys/fcntl.h> 521590Srgrimes#include <sys/ioctl.h> 53111008Sphk#include <sys/resource.h> 541590Srgrimes#include <sys/sysctl.h> 55208389Ssbruno#include <sys/time.h> 5612804Speter#include <sys/vmmeter.h> 57198620Sjhb#include <sys/pcpu.h> 5812811Sbde 5912811Sbde#include <vm/vm_param.h> 6012811Sbde 6128693Scharnier#include <ctype.h> 6287690Smarkm#include <devstat.h> 6328693Scharnier#include <err.h> 6428693Scharnier#include <errno.h> 65228654Sdim#include <inttypes.h> 6628693Scharnier#include <kvm.h> 6728693Scharnier#include <limits.h> 68148413Srwatson#include <memstat.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> 77174573Speter#include <libutil.h> 781590Srgrimes 7987690Smarkmstatic char da[] = "da"; 8087690Smarkm 8187690Smarkmstatic struct nlist namelist[] = { 82181881Sjhb#define X_SUM 0 831590Srgrimes { "_cnt" }, 84233298Spluknet#define X_HZ 1 851590Srgrimes { "_hz" }, 86233298Spluknet#define X_STATHZ 2 871590Srgrimes { "_stathz" }, 88233298Spluknet#define X_NCHSTATS 3 891590Srgrimes { "_nchstats" }, 90233298Spluknet#define X_INTRNAMES 4 911590Srgrimes { "_intrnames" }, 92233298Spluknet#define X_SINTRNAMES 5 93224187Sattilio { "_sintrnames" }, 94233298Spluknet#define X_INTRCNT 6 951590Srgrimes { "_intrcnt" }, 96233298Spluknet#define X_SINTRCNT 7 97224187Sattilio { "_sintrcnt" }, 9830180Sdima#ifdef notyet 99131300Sgreen#define X_DEFICIT XXX 1001590Srgrimes { "_deficit" }, 101131300Sgreen#define X_REC XXX 1021590Srgrimes { "_rectime" }, 103131300Sgreen#define X_PGIN XXX 1041590Srgrimes { "_pgintime" }, 105131300Sgreen#define X_XSTATS XXX 1061590Srgrimes { "_xstats" }, 107131300Sgreen#define X_END XXX 10892653Sjeff#else 109233298Spluknet#define X_END 8 1101590Srgrimes#endif 1111590Srgrimes { "" }, 1121590Srgrimes}; 1131590Srgrimes 114123250Sdesstatic struct statinfo cur, last; 115123250Sdesstatic int num_devices, maxshowdevs; 116123250Sdesstatic long generation; 117123250Sdesstatic struct device_selection *dev_select; 118123250Sdesstatic int num_selected; 119123250Sdesstatic struct devstat_match *matches; 120123250Sdesstatic int num_matches = 0; 121123250Sdesstatic int num_devices_specified, num_selections; 122123250Sdesstatic long select_generation; 123123250Sdesstatic char **specified_devices; 124123250Sdesstatic devstat_select_mode select_mode; 1251590Srgrimes 126123250Sdesstatic struct vmmeter sum, osum; 1271590Srgrimes 128184645Skeramida#define VMSTAT_DEFAULT_LINES 20 /* Default number of `winlines'. */ 129184645Skeramidavolatile sig_atomic_t wresized; /* Tty resized, when non-zero. */ 130184645Skeramidastatic int winlines = VMSTAT_DEFAULT_LINES; /* Current number of tty rows. */ 131184645Skeramida 132123250Sdesstatic int aflag; 133123250Sdesstatic int nflag; 134174573Speterstatic int Pflag; 135174573Speterstatic int hflag; 1361590Srgrimes 137123250Sdesstatic kvm_t *kd; 1381590Srgrimes 1391590Srgrimes#define FORKSTAT 0x01 1401590Srgrimes#define INTRSTAT 0x02 1411590Srgrimes#define MEMSTAT 0x04 1421590Srgrimes#define SUMSTAT 0x08 1431590Srgrimes#define TIMESTAT 0x10 1441590Srgrimes#define VMSTAT 0x20 14543962Sdillon#define ZMEMSTAT 0x40 1461590Srgrimes 14792922Simpstatic void cpustats(void); 148174573Speterstatic void pcpustats(int, u_long, int); 14992922Simpstatic void devstats(void); 150122300Sjmgstatic void doforkst(void); 15192922Simpstatic void dointr(void); 15292922Simpstatic void dosum(void); 153123407Sdesstatic void dovmstat(unsigned int, int); 154148790Srwatsonstatic void domemstat_malloc(void); 155148630Srwatsonstatic void domemstat_zone(void); 15692922Simpstatic void kread(int, void *, size_t); 157131300Sgreenstatic void kreado(int, void *, size_t, size_t); 158131300Sgreenstatic char *kgetstr(const char *); 15992922Simpstatic void needhdr(int); 160184645Skeramidastatic void needresize(int); 161184645Skeramidastatic void doresize(void); 162174573Speterstatic void printhdr(int, u_long); 16392922Simpstatic void usage(void); 1641590Srgrimes 16592922Simpstatic long pct(long, long); 16692922Simpstatic long getuptime(void); 16787690Smarkm 168123250Sdesstatic char **getdrivedata(char **); 16987690Smarkm 17028693Scharnierint 171123250Sdesmain(int argc, char *argv[]) 1721590Srgrimes{ 17387690Smarkm int c, todo; 174123407Sdes unsigned int interval; 175208389Ssbruno float f; 1761590Srgrimes int reps; 1771590Srgrimes char *memf, *nlistf; 17878474Sschweikh char errbuf[_POSIX2_LINE_MAX]; 1791590Srgrimes 1801590Srgrimes memf = nlistf = NULL; 1811590Srgrimes interval = reps = todo = 0; 18243822Sken maxshowdevs = 2; 183174573Speter hflag = isatty(1); 184174573Speter while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:Pp:stw:z")) != -1) { 1851590Srgrimes switch (c) { 186123250Sdes case 'a': 187123250Sdes aflag++; 188123250Sdes break; 1891590Srgrimes case 'c': 1901590Srgrimes reps = atoi(optarg); 1911590Srgrimes break; 192174573Speter case 'P': 193174573Speter Pflag++; 194174573Speter break; 1951590Srgrimes case 'f': 196113460Stjr todo |= FORKSTAT; 1971590Srgrimes break; 198174573Speter case 'h': 199174573Speter hflag = 1; 200174573Speter break; 201174573Speter case 'H': 202174573Speter hflag = 0; 203174573Speter break; 2041590Srgrimes case 'i': 2051590Srgrimes todo |= INTRSTAT; 2061590Srgrimes break; 2071590Srgrimes case 'M': 2081590Srgrimes memf = optarg; 2091590Srgrimes break; 2101590Srgrimes case 'm': 2111590Srgrimes todo |= MEMSTAT; 2121590Srgrimes break; 2131590Srgrimes case 'N': 2141590Srgrimes nlistf = optarg; 2151590Srgrimes break; 21639230Sgibbs case 'n': 21739372Sdillon nflag = 1; 21839230Sgibbs maxshowdevs = atoi(optarg); 21939230Sgibbs if (maxshowdevs < 0) 22039230Sgibbs errx(1, "number of devices %d is < 0", 22139230Sgibbs maxshowdevs); 22239230Sgibbs break; 22339230Sgibbs case 'p': 224112284Sphk if (devstat_buildmatch(optarg, &matches, &num_matches) != 0) 22539230Sgibbs errx(1, "%s", devstat_errbuf); 22639230Sgibbs break; 2271590Srgrimes case 's': 2281590Srgrimes todo |= SUMSTAT; 2291590Srgrimes break; 2301590Srgrimes case 't': 23130180Sdima#ifdef notyet 2321590Srgrimes todo |= TIMESTAT; 23330180Sdima#else 23430180Sdima errx(EX_USAGE, "sorry, -t is not (re)implemented yet"); 23530180Sdima#endif 2361590Srgrimes break; 2371590Srgrimes case 'w': 238208389Ssbruno /* Convert to milliseconds. */ 239208389Ssbruno f = atof(optarg); 240208389Ssbruno interval = f * 1000; 2411590Srgrimes break; 24244067Sbde case 'z': 24344067Sbde todo |= ZMEMSTAT; 24444067Sbde break; 2451590Srgrimes case '?': 2461590Srgrimes default: 2471590Srgrimes usage(); 2481590Srgrimes } 2491590Srgrimes } 2501590Srgrimes argc -= optind; 2511590Srgrimes argv += optind; 2521590Srgrimes 2531590Srgrimes if (todo == 0) 2541590Srgrimes todo = VMSTAT; 2551590Srgrimes 256123250Sdes if (memf != NULL) { 257123250Sdes kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 258123250Sdes if (kd == NULL) 259123250Sdes errx(1, "kvm_openfiles: %s", errbuf); 260123250Sdes } 2611590Srgrimes 262123250Sdes if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) { 2631590Srgrimes if (c > 0) { 26428693Scharnier warnx("undefined symbols:"); 2651590Srgrimes for (c = 0; 266123250Sdes c < (int)(sizeof(namelist)/sizeof(namelist[0])); 267123250Sdes c++) 2681590Srgrimes if (namelist[c].n_type == 0) 26981537Sken (void)fprintf(stderr, " %s", 2701590Srgrimes namelist[c].n_name); 2711590Srgrimes (void)fputc('\n', stderr); 2721590Srgrimes } else 27328693Scharnier warnx("kvm_nlist: %s", kvm_geterr(kd)); 2741590Srgrimes exit(1); 2751590Srgrimes } 276174573Speter if (kd && Pflag) 277174573Speter errx(1, "Cannot use -P with crash dumps"); 2781590Srgrimes 2791590Srgrimes if (todo & VMSTAT) { 28043819Sken /* 28143819Sken * Make sure that the userland devstat version matches the 28243819Sken * kernel devstat version. If not, exit and print a 28343819Sken * message informing the user of his mistake. 28443819Sken */ 285112284Sphk if (devstat_checkversion(NULL) < 0) 28643819Sken errx(1, "%s", devstat_errbuf); 28743819Sken 28843819Sken 2891590Srgrimes argv = getdrivedata(argv); 2901590Srgrimes } 2911590Srgrimes 2921590Srgrimes#define BACKWARD_COMPATIBILITY 2931590Srgrimes#ifdef BACKWARD_COMPATIBILITY 2941590Srgrimes if (*argv) { 295208389Ssbruno f = atof(*argv); 296208389Ssbruno interval = f * 1000; 2971590Srgrimes if (*++argv) 2981590Srgrimes reps = atoi(*argv); 2991590Srgrimes } 3001590Srgrimes#endif 3011590Srgrimes 3021590Srgrimes if (interval) { 3031590Srgrimes if (!reps) 3041590Srgrimes reps = -1; 3051590Srgrimes } else if (reps) 306208389Ssbruno interval = 1 * 1000; 3071590Srgrimes 3081590Srgrimes if (todo & FORKSTAT) 3091590Srgrimes doforkst(); 3101590Srgrimes if (todo & MEMSTAT) 311148790Srwatson domemstat_malloc(); 31243962Sdillon if (todo & ZMEMSTAT) 313148630Srwatson domemstat_zone(); 3141590Srgrimes if (todo & SUMSTAT) 3151590Srgrimes dosum(); 31630180Sdima#ifdef notyet 3171590Srgrimes if (todo & TIMESTAT) 3181590Srgrimes dotimes(); 3191590Srgrimes#endif 3201590Srgrimes if (todo & INTRSTAT) 3211590Srgrimes dointr(); 3221590Srgrimes if (todo & VMSTAT) 3231590Srgrimes dovmstat(interval, reps); 3241590Srgrimes exit(0); 3251590Srgrimes} 3261590Srgrimes 327123250Sdesstatic int 328123250Sdesmysysctl(const char *name, void *oldp, size_t *oldlenp, 329123250Sdes void *newp, size_t newlen) 3301590Srgrimes{ 331123250Sdes int error; 332123250Sdes 333123250Sdes error = sysctlbyname(name, oldp, oldlenp, newp, newlen); 334123250Sdes if (error != 0 && errno != ENOMEM) 335123250Sdes err(1, "sysctl(%s)", name); 336123250Sdes return (error); 337123250Sdes} 338123250Sdes 339123250Sdesstatic char ** 340123250Sdesgetdrivedata(char **argv) 341123250Sdes{ 342112284Sphk if ((num_devices = devstat_getnumdevs(NULL)) < 0) 34339230Sgibbs errx(1, "%s", devstat_errbuf); 3441590Srgrimes 345188888Sdelphij cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); 346188888Sdelphij last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); 34739230Sgibbs 348112284Sphk if (devstat_getdevs(NULL, &cur) == -1) 34939230Sgibbs errx(1, "%s", devstat_errbuf); 35039230Sgibbs 35139230Sgibbs num_devices = cur.dinfo->numdevs; 35239230Sgibbs generation = cur.dinfo->generation; 35339230Sgibbs 35439230Sgibbs specified_devices = (char **)malloc(sizeof(char *)); 35539230Sgibbs for (num_devices_specified = 0; *argv; ++argv) { 3561590Srgrimes if (isdigit(**argv)) 3571590Srgrimes break; 35839230Sgibbs num_devices_specified++; 35939230Sgibbs specified_devices = (char **)realloc(specified_devices, 36039230Sgibbs sizeof(char *) * 36139230Sgibbs num_devices_specified); 36239230Sgibbs specified_devices[num_devices_specified - 1] = *argv; 3631590Srgrimes } 36439230Sgibbs dev_select = NULL; 36539230Sgibbs 36639372Sdillon if (nflag == 0 && maxshowdevs < num_devices_specified) 36739372Sdillon maxshowdevs = num_devices_specified; 36839372Sdillon 36939230Sgibbs /* 37039230Sgibbs * People are generally only interested in disk statistics when 37139230Sgibbs * they're running vmstat. So, that's what we're going to give 37239230Sgibbs * them if they don't specify anything by default. We'll also give 37339230Sgibbs * them any other random devices in the system so that we get to 37439230Sgibbs * maxshowdevs devices, if that many devices exist. If the user 37539230Sgibbs * specifies devices on the command line, either through a pattern 37639230Sgibbs * match or by naming them explicitly, we will give the user only 37739230Sgibbs * those devices. 37839230Sgibbs */ 37939230Sgibbs if ((num_devices_specified == 0) && (num_matches == 0)) { 380112284Sphk if (devstat_buildmatch(da, &matches, &num_matches) != 0) 38139230Sgibbs errx(1, "%s", devstat_errbuf); 38239230Sgibbs 38339230Sgibbs select_mode = DS_SELECT_ADD; 38439230Sgibbs } else 38539230Sgibbs select_mode = DS_SELECT_ONLY; 38639230Sgibbs 38739230Sgibbs /* 38839230Sgibbs * At this point, selectdevs will almost surely indicate that the 38939230Sgibbs * device list has changed, so we don't look for return values of 0 39039230Sgibbs * or 1. If we get back -1, though, there is an error. 39139230Sgibbs */ 392112284Sphk if (devstat_selectdevs(&dev_select, &num_selected, &num_selections, 39339230Sgibbs &select_generation, generation, cur.dinfo->devices, 39439230Sgibbs num_devices, matches, num_matches, specified_devices, 39539230Sgibbs num_devices_specified, select_mode, 39639230Sgibbs maxshowdevs, 0) == -1) 39739230Sgibbs errx(1, "%s", devstat_errbuf); 39839230Sgibbs 3991590Srgrimes return(argv); 4001590Srgrimes} 4011590Srgrimes 402123250Sdesstatic long 403123250Sdesgetuptime(void) 4041590Srgrimes{ 405151417Sandre struct timespec sp; 4061590Srgrimes 407151417Sandre (void)clock_gettime(CLOCK_MONOTONIC, &sp); 408151417Sandre 409219708Semaste return(sp.tv_sec); 4101590Srgrimes} 4111590Srgrimes 412123250Sdesstatic void 413198620Sjhbfill_pcpu(struct pcpu ***pcpup, int* maxcpup) 414198620Sjhb{ 415198620Sjhb struct pcpu **pcpu; 416198620Sjhb 417215569Skevlo int maxcpu, i; 418198620Sjhb 419198620Sjhb *pcpup = NULL; 420198620Sjhb 421198620Sjhb if (kd == NULL) 422198620Sjhb return; 423198620Sjhb 424198620Sjhb maxcpu = kvm_getmaxcpu(kd); 425198620Sjhb if (maxcpu < 0) 426198620Sjhb errx(1, "kvm_getmaxcpu: %s", kvm_geterr(kd)); 427198620Sjhb 428198620Sjhb pcpu = calloc(maxcpu, sizeof(struct pcpu *)); 429198620Sjhb if (pcpu == NULL) 430198620Sjhb err(1, "calloc"); 431198620Sjhb 432198620Sjhb for (i = 0; i < maxcpu; i++) { 433198620Sjhb pcpu[i] = kvm_getpcpu(kd, i); 434198620Sjhb if (pcpu[i] == (struct pcpu *)-1) 435198620Sjhb errx(1, "kvm_getpcpu: %s", kvm_geterr(kd)); 436198620Sjhb } 437198620Sjhb 438198620Sjhb *maxcpup = maxcpu; 439198620Sjhb *pcpup = pcpu; 440198620Sjhb} 441198620Sjhb 442198620Sjhbstatic void 443198620Sjhbfree_pcpu(struct pcpu **pcpu, int maxcpu) 444198620Sjhb{ 445198620Sjhb int i; 446198620Sjhb 447198620Sjhb for (i = 0; i < maxcpu; i++) 448198620Sjhb free(pcpu[i]); 449198620Sjhb free(pcpu); 450198620Sjhb} 451198620Sjhb 452198620Sjhbstatic void 453123250Sdesfill_vmmeter(struct vmmeter *vmmp) 454123250Sdes{ 455198620Sjhb struct pcpu **pcpu; 456198620Sjhb int maxcpu, i; 457198620Sjhb 458123250Sdes if (kd != NULL) { 459123250Sdes kread(X_SUM, vmmp, sizeof(*vmmp)); 460198620Sjhb fill_pcpu(&pcpu, &maxcpu); 461198620Sjhb for (i = 0; i < maxcpu; i++) { 462198620Sjhb if (pcpu[i] == NULL) 463198620Sjhb continue; 464198620Sjhb#define ADD_FROM_PCPU(i, name) \ 465198620Sjhb vmmp->name += pcpu[i]->pc_cnt.name 466198620Sjhb ADD_FROM_PCPU(i, v_swtch); 467198620Sjhb ADD_FROM_PCPU(i, v_trap); 468198620Sjhb ADD_FROM_PCPU(i, v_syscall); 469198620Sjhb ADD_FROM_PCPU(i, v_intr); 470198620Sjhb ADD_FROM_PCPU(i, v_soft); 471198620Sjhb ADD_FROM_PCPU(i, v_vm_faults); 472246034Szont ADD_FROM_PCPU(i, v_io_faults); 473198620Sjhb ADD_FROM_PCPU(i, v_cow_faults); 474198620Sjhb ADD_FROM_PCPU(i, v_cow_optim); 475198620Sjhb ADD_FROM_PCPU(i, v_zfod); 476198620Sjhb ADD_FROM_PCPU(i, v_ozfod); 477198620Sjhb ADD_FROM_PCPU(i, v_swapin); 478198620Sjhb ADD_FROM_PCPU(i, v_swapout); 479198620Sjhb ADD_FROM_PCPU(i, v_swappgsin); 480198620Sjhb ADD_FROM_PCPU(i, v_swappgsout); 481198620Sjhb ADD_FROM_PCPU(i, v_vnodein); 482198620Sjhb ADD_FROM_PCPU(i, v_vnodeout); 483198620Sjhb ADD_FROM_PCPU(i, v_vnodepgsin); 484198620Sjhb ADD_FROM_PCPU(i, v_vnodepgsout); 485198620Sjhb ADD_FROM_PCPU(i, v_intrans); 486198620Sjhb ADD_FROM_PCPU(i, v_tfree); 487198620Sjhb ADD_FROM_PCPU(i, v_forks); 488198620Sjhb ADD_FROM_PCPU(i, v_vforks); 489198620Sjhb ADD_FROM_PCPU(i, v_rforks); 490198620Sjhb ADD_FROM_PCPU(i, v_kthreads); 491198620Sjhb ADD_FROM_PCPU(i, v_forkpages); 492198620Sjhb ADD_FROM_PCPU(i, v_vforkpages); 493198620Sjhb ADD_FROM_PCPU(i, v_rforkpages); 494198620Sjhb ADD_FROM_PCPU(i, v_kthreadpages); 495198620Sjhb#undef ADD_FROM_PCPU 496198620Sjhb } 497198620Sjhb free_pcpu(pcpu, maxcpu); 498123250Sdes } else { 499123250Sdes size_t size = sizeof(unsigned int); 500123250Sdes#define GET_VM_STATS(cat, name) \ 501123250Sdes mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size, NULL, 0) 502123250Sdes /* sys */ 503123250Sdes GET_VM_STATS(sys, v_swtch); 504123250Sdes GET_VM_STATS(sys, v_trap); 505123250Sdes GET_VM_STATS(sys, v_syscall); 506123250Sdes GET_VM_STATS(sys, v_intr); 507123250Sdes GET_VM_STATS(sys, v_soft); 5081590Srgrimes 509123250Sdes /* vm */ 510123414Sdes GET_VM_STATS(vm, v_vm_faults); 511246034Szont GET_VM_STATS(vm, v_io_faults); 512123414Sdes GET_VM_STATS(vm, v_cow_faults); 513123414Sdes GET_VM_STATS(vm, v_cow_optim); 514123414Sdes GET_VM_STATS(vm, v_zfod); 515123414Sdes GET_VM_STATS(vm, v_ozfod); 516123414Sdes GET_VM_STATS(vm, v_swapin); 517123414Sdes GET_VM_STATS(vm, v_swapout); 518123414Sdes GET_VM_STATS(vm, v_swappgsin); 519123414Sdes GET_VM_STATS(vm, v_swappgsout); 520123414Sdes GET_VM_STATS(vm, v_vnodein); 521123414Sdes GET_VM_STATS(vm, v_vnodeout); 522123414Sdes GET_VM_STATS(vm, v_vnodepgsin); 523123414Sdes GET_VM_STATS(vm, v_vnodepgsout); 524123414Sdes GET_VM_STATS(vm, v_intrans); 525123414Sdes GET_VM_STATS(vm, v_reactivated); 526123414Sdes GET_VM_STATS(vm, v_pdwakeups); 527123414Sdes GET_VM_STATS(vm, v_pdpages); 528171633Salc GET_VM_STATS(vm, v_tcached); 529123414Sdes GET_VM_STATS(vm, v_dfree); 530123414Sdes GET_VM_STATS(vm, v_pfree); 531123414Sdes GET_VM_STATS(vm, v_tfree); 532123414Sdes GET_VM_STATS(vm, v_page_size); 533123414Sdes GET_VM_STATS(vm, v_page_count); 534123414Sdes GET_VM_STATS(vm, v_free_reserved); 535123414Sdes GET_VM_STATS(vm, v_free_target); 536123414Sdes GET_VM_STATS(vm, v_free_min); 537123414Sdes GET_VM_STATS(vm, v_free_count); 538123414Sdes GET_VM_STATS(vm, v_wire_count); 539123414Sdes GET_VM_STATS(vm, v_active_count); 540123414Sdes GET_VM_STATS(vm, v_inactive_target); 541123414Sdes GET_VM_STATS(vm, v_inactive_count); 542123414Sdes GET_VM_STATS(vm, v_cache_count); 543123414Sdes GET_VM_STATS(vm, v_cache_min); 544123414Sdes GET_VM_STATS(vm, v_cache_max); 545123414Sdes GET_VM_STATS(vm, v_pageout_free_min); 546123414Sdes GET_VM_STATS(vm, v_interrupt_free_min); 547123414Sdes /*GET_VM_STATS(vm, v_free_severe);*/ 548123250Sdes GET_VM_STATS(vm, v_forks); 549123250Sdes GET_VM_STATS(vm, v_vforks); 550123250Sdes GET_VM_STATS(vm, v_rforks); 551123250Sdes GET_VM_STATS(vm, v_kthreads); 552123250Sdes GET_VM_STATS(vm, v_forkpages); 553123250Sdes GET_VM_STATS(vm, v_vforkpages); 554123250Sdes GET_VM_STATS(vm, v_rforkpages); 555123250Sdes GET_VM_STATS(vm, v_kthreadpages); 556123250Sdes#undef GET_VM_STATS 557123250Sdes } 558123250Sdes} 559123250Sdes 560123250Sdesstatic void 561123250Sdesfill_vmtotal(struct vmtotal *vmtp) 5621590Srgrimes{ 563123250Sdes if (kd != NULL) { 564123250Sdes /* XXX fill vmtp */ 565123250Sdes errx(1, "not implemented"); 566123250Sdes } else { 567123250Sdes size_t size = sizeof(*vmtp); 568123250Sdes mysysctl("vm.vmtotal", vmtp, &size, NULL, 0); 569123250Sdes if (size != sizeof(*vmtp)) 570123250Sdes errx(1, "vm.total size mismatch"); 571123250Sdes } 572123250Sdes} 573123250Sdes 574174573Speter/* Determine how many cpu columns, and what index they are in kern.cp_times */ 575174573Speterstatic int 576174573Spetergetcpuinfo(u_long *maskp, int *maxidp) 577174573Speter{ 578174573Speter int maxcpu; 579174573Speter int maxid; 580174573Speter int ncpus; 581174573Speter int i, j; 582174573Speter int empty; 583174573Speter size_t size; 584174573Speter long *times; 585174573Speter u_long mask; 586174573Speter 587174573Speter if (kd != NULL) 588174573Speter errx(1, "not implemented"); 589174573Speter mask = 0; 590174573Speter ncpus = 0; 591174573Speter size = sizeof(maxcpu); 592174573Speter mysysctl("kern.smp.maxcpus", &maxcpu, &size, NULL, 0); 593174573Speter if (size != sizeof(maxcpu)) 594174573Speter errx(1, "sysctl kern.smp.maxcpus"); 595174573Speter size = sizeof(long) * maxcpu * CPUSTATES; 596174573Speter times = malloc(size); 597174573Speter if (times == NULL) 598174573Speter err(1, "malloc %zd bytes", size); 599174573Speter mysysctl("kern.cp_times", times, &size, NULL, 0); 600174573Speter maxid = (size / CPUSTATES / sizeof(long)) - 1; 601174573Speter for (i = 0; i <= maxid; i++) { 602174573Speter empty = 1; 603174573Speter for (j = 0; empty && j < CPUSTATES; j++) { 604174573Speter if (times[i * CPUSTATES + j] != 0) 605174573Speter empty = 0; 606174573Speter } 607174573Speter if (!empty) { 608174573Speter mask |= (1ul << i); 609174573Speter ncpus++; 610174573Speter } 611174573Speter } 612174573Speter if (maskp) 613174573Speter *maskp = mask; 614174573Speter if (maxidp) 615174573Speter *maxidp = maxid; 616174573Speter return (ncpus); 617174573Speter} 618174573Speter 619174573Speter 620174573Speterstatic void 621174573Speterprthuman(u_int64_t val, int size) 622174573Speter{ 623174573Speter char buf[10]; 624174573Speter int flags; 625174573Speter 626174573Speter if (size < 5 || size > 9) 627174573Speter errx(1, "doofus"); 628174573Speter flags = HN_B | HN_NOSPACE | HN_DECIMAL; 629174573Speter humanize_number(buf, size, val, "", HN_AUTOSCALE, flags); 630174573Speter printf("%*s", size, buf); 631174573Speter} 632174573Speter 633123250Sdesstatic int hz, hdrcnt; 634123250Sdes 635174573Speterstatic long *cur_cp_times; 636174573Speterstatic long *last_cp_times; 637174573Speterstatic size_t size_cp_times; 638174573Speter 639123250Sdesstatic void 640123407Sdesdovmstat(unsigned int interval, int reps) 641123250Sdes{ 6421590Srgrimes struct vmtotal total; 6431590Srgrimes time_t uptime, halfuptime; 64439230Sgibbs struct devinfo *tmp_dinfo; 64580551Stmm size_t size; 646174573Speter int ncpus, maxid; 647174573Speter u_long cpumask; 648208389Ssbruno int rate_adj; 6491590Srgrimes 6501590Srgrimes uptime = getuptime(); 6511590Srgrimes halfuptime = uptime / 2; 652208389Ssbruno rate_adj = 1; 653184645Skeramida 654184645Skeramida /* 655184645Skeramida * If the user stops the program (control-Z) and then resumes it, 656184645Skeramida * print out the header again. 657184645Skeramida */ 6581590Srgrimes (void)signal(SIGCONT, needhdr); 6591590Srgrimes 660184645Skeramida /* 661184645Skeramida * If our standard output is a tty, then install a SIGWINCH handler 662184645Skeramida * and set wresized so that our first iteration through the main 663184646Skeramida * vmstat loop will peek at the terminal's current rows to find out 664184645Skeramida * how many lines can fit in a screenful of output. 665184645Skeramida */ 666184645Skeramida if (isatty(fileno(stdout)) != 0) { 667184645Skeramida wresized = 1; 668184645Skeramida (void)signal(SIGWINCH, needresize); 669184645Skeramida } else { 670184645Skeramida wresized = 0; 671184645Skeramida winlines = VMSTAT_DEFAULT_LINES; 672184645Skeramida } 673184645Skeramida 674123250Sdes if (kd != NULL) { 675123250Sdes if (namelist[X_STATHZ].n_type != 0 && 676123250Sdes namelist[X_STATHZ].n_value != 0) 677123250Sdes kread(X_STATHZ, &hz, sizeof(hz)); 678123250Sdes if (!hz) 679123250Sdes kread(X_HZ, &hz, sizeof(hz)); 680123250Sdes } else { 681123250Sdes struct clockinfo clockrate; 6821590Srgrimes 683123250Sdes size = sizeof(clockrate); 684123250Sdes mysysctl("kern.clockrate", &clockrate, &size, NULL, 0); 685123250Sdes if (size != sizeof(clockrate)) 686123250Sdes errx(1, "clockrate size mismatch"); 687123250Sdes hz = clockrate.hz; 688123250Sdes } 689123250Sdes 690174573Speter if (Pflag) { 691174573Speter ncpus = getcpuinfo(&cpumask, &maxid); 692174573Speter size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES; 693188888Sdelphij cur_cp_times = calloc(1, size_cp_times); 694188888Sdelphij last_cp_times = calloc(1, size_cp_times); 695174573Speter } 6961590Srgrimes for (hdrcnt = 1;;) { 6971590Srgrimes if (!--hdrcnt) 698174573Speter printhdr(ncpus, cpumask); 699123250Sdes if (kd != NULL) { 700181881Sjhb if (kvm_getcptime(kd, cur.cp_time) < 0) 701181881Sjhb errx(1, "kvm_getcptime: %s", kvm_geterr(kd)); 702123250Sdes } else { 703123250Sdes size = sizeof(cur.cp_time); 704123250Sdes mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0); 705123250Sdes if (size != sizeof(cur.cp_time)) 706123250Sdes errx(1, "cp_time size mismatch"); 707123250Sdes } 708174573Speter if (Pflag) { 709174573Speter size = size_cp_times; 710174573Speter mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0); 711174573Speter if (size != size_cp_times) 712174573Speter errx(1, "cp_times mismatch"); 713174573Speter } 71439230Sgibbs 71539230Sgibbs tmp_dinfo = last.dinfo; 71639230Sgibbs last.dinfo = cur.dinfo; 71739230Sgibbs cur.dinfo = tmp_dinfo; 718112288Sphk last.snap_time = cur.snap_time; 71939230Sgibbs 72039230Sgibbs /* 72139230Sgibbs * Here what we want to do is refresh our device stats. 72239230Sgibbs * getdevs() returns 1 when the device list has changed. 72339230Sgibbs * If the device list has changed, we want to go through 72439230Sgibbs * the selection process again, in case a device that we 72539230Sgibbs * were previously displaying has gone away. 72639230Sgibbs */ 727112284Sphk switch (devstat_getdevs(NULL, &cur)) { 72839230Sgibbs case -1: 72939230Sgibbs errx(1, "%s", devstat_errbuf); 73039230Sgibbs break; 73139230Sgibbs case 1: { 73239230Sgibbs int retval; 73339230Sgibbs 73439230Sgibbs num_devices = cur.dinfo->numdevs; 73539230Sgibbs generation = cur.dinfo->generation; 73639230Sgibbs 737112284Sphk retval = devstat_selectdevs(&dev_select, &num_selected, 73839230Sgibbs &num_selections, &select_generation, 73939230Sgibbs generation, cur.dinfo->devices, 74039230Sgibbs num_devices, matches, num_matches, 74139230Sgibbs specified_devices, 74239230Sgibbs num_devices_specified, select_mode, 74339230Sgibbs maxshowdevs, 0); 74439230Sgibbs switch (retval) { 74539230Sgibbs case -1: 74639230Sgibbs errx(1, "%s", devstat_errbuf); 74739230Sgibbs break; 74839230Sgibbs case 1: 749174573Speter printhdr(ncpus, cpumask); 75039230Sgibbs break; 75139230Sgibbs default: 75239230Sgibbs break; 75339230Sgibbs } 75439230Sgibbs } 75539230Sgibbs default: 75639230Sgibbs break; 75739230Sgibbs } 75839230Sgibbs 759123250Sdes fill_vmmeter(&sum); 760123250Sdes fill_vmtotal(&total); 761164718Sru (void)printf("%2d %1d %1d", 7621590Srgrimes total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); 763164718Sru#define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10)) 764208389Ssbruno#define rate(x) (((x) * rate_adj + halfuptime) / uptime) /* round */ 765174573Speter if (hflag) { 766174573Speter printf(" "); 767174573Speter prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7); 768174573Speter printf(" "); 769174573Speter prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6); 770174573Speter printf(" "); 771174573Speter } else { 772174573Speter printf(" %7d ", vmstat_pgtok(total.t_avm)); 773174573Speter printf(" %6d ", vmstat_pgtok(total.t_free)); 774174573Speter } 775159200Sobrien (void)printf("%5lu ", 776123407Sdes (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); 7771590Srgrimes (void)printf("%3lu ", 778123407Sdes (unsigned long)rate(sum.v_reactivated - osum.v_reactivated)); 77937453Sbde (void)printf("%3lu ", 780123407Sdes (unsigned long)rate(sum.v_swapin + sum.v_vnodein - 7813659Sdg (osum.v_swapin + osum.v_vnodein))); 78237453Sbde (void)printf("%3lu ", 783123407Sdes (unsigned long)rate(sum.v_swapout + sum.v_vnodeout - 7843693Sdg (osum.v_swapout + osum.v_vnodeout))); 785159200Sobrien (void)printf("%5lu ", 786123407Sdes (unsigned long)rate(sum.v_tfree - osum.v_tfree)); 78737453Sbde (void)printf("%3lu ", 788123407Sdes (unsigned long)rate(sum.v_pdpages - osum.v_pdpages)); 78939230Sgibbs devstats(); 790174573Speter (void)printf("%4lu %4lu %4lu", 791123407Sdes (unsigned long)rate(sum.v_intr - osum.v_intr), 792123407Sdes (unsigned long)rate(sum.v_syscall - osum.v_syscall), 793123407Sdes (unsigned long)rate(sum.v_swtch - osum.v_swtch)); 794174573Speter if (Pflag) 795174573Speter pcpustats(ncpus, cpumask, maxid); 796174573Speter else 797174573Speter cpustats(); 7981590Srgrimes (void)printf("\n"); 7991590Srgrimes (void)fflush(stdout); 8001590Srgrimes if (reps >= 0 && --reps <= 0) 8011590Srgrimes break; 8021590Srgrimes osum = sum; 8031590Srgrimes uptime = interval; 804208389Ssbruno rate_adj = 1000; 8051590Srgrimes /* 8061590Srgrimes * We round upward to avoid losing low-frequency events 807208389Ssbruno * (i.e., >= 1 per interval but < 1 per millisecond). 8081590Srgrimes */ 8093659Sdg if (interval != 1) 8103659Sdg halfuptime = (uptime + 1) / 2; 8113659Sdg else 8123659Sdg halfuptime = 0; 813208389Ssbruno (void)usleep(interval * 1000); 8141590Srgrimes } 8151590Srgrimes} 8161590Srgrimes 817123250Sdesstatic void 818174573Speterprinthdr(int ncpus, u_long cpumask) 8191590Srgrimes{ 82043822Sken int i, num_shown; 8211590Srgrimes 82243822Sken num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs; 82378672Sschweikh (void)printf(" procs memory page%*s", 19, ""); 82443822Sken if (num_shown > 1) 82543822Sken (void)printf(" disks %*s", num_shown * 4 - 7, ""); 82643822Sken else if (num_shown == 1) 82743822Sken (void)printf("disk"); 828174573Speter (void)printf(" faults "); 829174573Speter if (Pflag) { 830174573Speter for (i = 0; i < ncpus; i++) { 831175465Speter if (cpumask & (1ul << i)) 832174573Speter printf("cpu%-2d ", i); 833174573Speter } 834174573Speter printf("\n"); 835174573Speter } else 836174573Speter printf("cpu\n"); 837159200Sobrien (void)printf(" r b w avm fre flt re pi po fr sr "); 83839230Sgibbs for (i = 0; i < num_devices; i++) 83939230Sgibbs if ((dev_select[i].selected) 84039230Sgibbs && (dev_select[i].selected <= maxshowdevs)) 84139230Sgibbs (void)printf("%c%c%d ", dev_select[i].device_name[0], 84239230Sgibbs dev_select[i].device_name[1], 84339230Sgibbs dev_select[i].unit_number); 844174573Speter (void)printf(" in sy cs"); 845174573Speter if (Pflag) { 846174573Speter for (i = 0; i < ncpus; i++) 847174573Speter printf(" us sy id"); 848174573Speter printf("\n"); 849174573Speter } else 850174573Speter printf(" us sy id\n"); 851184645Skeramida if (wresized != 0) 852184645Skeramida doresize(); 853184645Skeramida hdrcnt = winlines; 8541590Srgrimes} 8551590Srgrimes 8561590Srgrimes/* 8571590Srgrimes * Force a header to be prepended to the next output. 8581590Srgrimes */ 859123250Sdesstatic void 860123250Sdesneedhdr(int dummy __unused) 8611590Srgrimes{ 8621590Srgrimes 8631590Srgrimes hdrcnt = 1; 8641590Srgrimes} 8651590Srgrimes 866184645Skeramida/* 867184645Skeramida * When the terminal is resized, force an update of the maximum number of rows 868184645Skeramida * printed between each header repetition. Then force a new header to be 869184645Skeramida * prepended to the next output. 870184645Skeramida */ 871184645Skeramidavoid 872184645Skeramidaneedresize(int signo) 873184645Skeramida{ 874184645Skeramida 875184645Skeramida wresized = 1; 876184645Skeramida hdrcnt = 1; 877184645Skeramida} 878184645Skeramida 879184645Skeramida/* 880184645Skeramida * Update the global `winlines' count of terminal rows. 881184645Skeramida */ 882184645Skeramidavoid 883184645Skeramidadoresize(void) 884184645Skeramida{ 885184645Skeramida int status; 886184645Skeramida struct winsize w; 887184645Skeramida 888184645Skeramida for (;;) { 889184645Skeramida status = ioctl(fileno(stdout), TIOCGWINSZ, &w); 890184645Skeramida if (status == -1 && errno == EINTR) 891184645Skeramida continue; 892184645Skeramida else if (status == -1) 893184645Skeramida err(1, "ioctl"); 894184645Skeramida if (w.ws_row > 3) 895184645Skeramida winlines = w.ws_row - 3; 896184645Skeramida else 897184645Skeramida winlines = VMSTAT_DEFAULT_LINES; 898184645Skeramida break; 899184645Skeramida } 900184645Skeramida 901184645Skeramida /* 902184645Skeramida * Inhibit doresize() calls until we are rescheduled by SIGWINCH. 903184645Skeramida */ 904184645Skeramida wresized = 0; 905184645Skeramida} 906184645Skeramida 90730180Sdima#ifdef notyet 908123250Sdesstatic void 909123250Sdesdotimes(void) 9101590Srgrimes{ 911123407Sdes unsigned int pgintime, rectime; 9121590Srgrimes 9131590Srgrimes kread(X_REC, &rectime, sizeof(rectime)); 9141590Srgrimes kread(X_PGIN, &pgintime, sizeof(pgintime)); 9151590Srgrimes kread(X_SUM, &sum, sizeof(sum)); 9161590Srgrimes (void)printf("%u reclaims, %u total time (usec)\n", 9171590Srgrimes sum.v_pgrec, rectime); 9181590Srgrimes (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); 9191590Srgrimes (void)printf("\n"); 9201590Srgrimes (void)printf("%u page ins, %u total time (msec)\n", 9211590Srgrimes sum.v_pgin, pgintime / 10); 9221590Srgrimes (void)printf("average: %8.1f msec / page in\n", 9231590Srgrimes pgintime / (sum.v_pgin * 10.0)); 9241590Srgrimes} 9251590Srgrimes#endif 9261590Srgrimes 927123250Sdesstatic long 928123250Sdespct(long top, long bot) 9291590Srgrimes{ 9301590Srgrimes long ans; 9311590Srgrimes 9321590Srgrimes if (bot == 0) 9331590Srgrimes return(0); 9341590Srgrimes ans = (quad_t)top * 100 / bot; 9351590Srgrimes return (ans); 9361590Srgrimes} 9371590Srgrimes 9381590Srgrimes#define PCT(top, bot) pct((long)(top), (long)(bot)) 9391590Srgrimes 940123250Sdesstatic void 941123250Sdesdosum(void) 9421590Srgrimes{ 94387690Smarkm struct nchstats lnchstats; 9441590Srgrimes long nchtotal; 9451590Srgrimes 946123250Sdes fill_vmmeter(&sum); 9471590Srgrimes (void)printf("%9u cpu context switches\n", sum.v_swtch); 9481590Srgrimes (void)printf("%9u device interrupts\n", sum.v_intr); 9491590Srgrimes (void)printf("%9u software interrupts\n", sum.v_soft); 9501590Srgrimes (void)printf("%9u traps\n", sum.v_trap); 9511590Srgrimes (void)printf("%9u system calls\n", sum.v_syscall); 95271429Sume (void)printf("%9u kernel threads created\n", sum.v_kthreads); 95371429Sume (void)printf("%9u fork() calls\n", sum.v_forks); 95471429Sume (void)printf("%9u vfork() calls\n", sum.v_vforks); 95571429Sume (void)printf("%9u rfork() calls\n", sum.v_rforks); 9563659Sdg (void)printf("%9u swap pager pageins\n", sum.v_swapin); 9573693Sdg (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin); 9583659Sdg (void)printf("%9u swap pager pageouts\n", sum.v_swapout); 9593659Sdg (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout); 9603659Sdg (void)printf("%9u vnode pager pageins\n", sum.v_vnodein); 9613693Sdg (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin); 9623659Sdg (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout); 9633659Sdg (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout); 9643693Sdg (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups); 9653693Sdg (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages); 9661590Srgrimes (void)printf("%9u pages reactivated\n", sum.v_reactivated); 9677351Sdg (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); 96834214Sdyson (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim); 9697351Sdg (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod); 97034214Sdyson (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod); 9711590Srgrimes (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); 9721590Srgrimes (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); 973246034Szont (void)printf("%9u page faults requiring I/O\n", sum.v_io_faults); 97471429Sume (void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages); 97571429Sume (void)printf("%9u pages affected by fork()\n", sum.v_forkpages); 97671429Sume (void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages); 97771429Sume (void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages); 978171633Salc (void)printf("%9u pages cached\n", sum.v_tcached); 9793693Sdg (void)printf("%9u pages freed\n", sum.v_tfree); 9801590Srgrimes (void)printf("%9u pages freed by daemon\n", sum.v_dfree); 9811590Srgrimes (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); 9821590Srgrimes (void)printf("%9u pages active\n", sum.v_active_count); 9831590Srgrimes (void)printf("%9u pages inactive\n", sum.v_inactive_count); 9845463Sdg (void)printf("%9u pages in VM cache\n", sum.v_cache_count); 9853693Sdg (void)printf("%9u pages wired down\n", sum.v_wire_count); 9863693Sdg (void)printf("%9u pages free\n", sum.v_free_count); 9871590Srgrimes (void)printf("%9u bytes per page\n", sum.v_page_size); 988123250Sdes if (kd != NULL) { 989123250Sdes kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); 990123250Sdes } else { 991123250Sdes size_t size = sizeof(lnchstats); 992123250Sdes mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0); 993123250Sdes if (size != sizeof(lnchstats)) 994123250Sdes errx(1, "vfs.cache.nchstats size mismatch"); 995123250Sdes } 99687690Smarkm nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits + 99787690Smarkm lnchstats.ncs_badhits + lnchstats.ncs_falsehits + 99887690Smarkm lnchstats.ncs_miss + lnchstats.ncs_long; 9991590Srgrimes (void)printf("%9ld total name lookups\n", nchtotal); 10001590Srgrimes (void)printf( 100128693Scharnier "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n", 100287690Smarkm "", PCT(lnchstats.ncs_goodhits, nchtotal), 100387690Smarkm PCT(lnchstats.ncs_neghits, nchtotal), 100487690Smarkm PCT(lnchstats.ncs_pass2, nchtotal)); 100528693Scharnier (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "", 100687690Smarkm PCT(lnchstats.ncs_badhits, nchtotal), 100787690Smarkm PCT(lnchstats.ncs_falsehits, nchtotal), 100887690Smarkm PCT(lnchstats.ncs_long, nchtotal)); 10091590Srgrimes} 10101590Srgrimes 1011123250Sdesstatic void 1012123250Sdesdoforkst(void) 10131590Srgrimes{ 1014123250Sdes fill_vmmeter(&sum); 1015128573Stjr (void)printf("%u forks, %u pages, average %.2f\n", 1016113460Stjr sum.v_forks, sum.v_forkpages, 1017113460Stjr sum.v_forks == 0 ? 0.0 : 1018113460Stjr (double)sum.v_forkpages / sum.v_forks); 1019128573Stjr (void)printf("%u vforks, %u pages, average %.2f\n", 1020113460Stjr sum.v_vforks, sum.v_vforkpages, 1021113460Stjr sum.v_vforks == 0 ? 0.0 : 1022113460Stjr (double)sum.v_vforkpages / sum.v_vforks); 1023128573Stjr (void)printf("%u rforks, %u pages, average %.2f\n", 1024113460Stjr sum.v_rforks, sum.v_rforkpages, 1025113460Stjr sum.v_rforks == 0 ? 0.0 : 1026113460Stjr (double)sum.v_rforkpages / sum.v_rforks); 10271590Srgrimes} 10281590Srgrimes 102939230Sgibbsstatic void 1030123250Sdesdevstats(void) 10311590Srgrimes{ 103287690Smarkm int dn, state; 103339230Sgibbs long double transfers_per_second; 103439230Sgibbs long double busy_seconds; 10351590Srgrimes long tmp; 1036123250Sdes 10371590Srgrimes for (state = 0; state < CPUSTATES; ++state) { 103839230Sgibbs tmp = cur.cp_time[state]; 103939230Sgibbs cur.cp_time[state] -= last.cp_time[state]; 104039230Sgibbs last.cp_time[state] = tmp; 10411590Srgrimes } 104239230Sgibbs 1043112288Sphk busy_seconds = cur.snap_time - last.snap_time; 104439230Sgibbs 104539230Sgibbs for (dn = 0; dn < num_devices; dn++) { 104639230Sgibbs int di; 104739230Sgibbs 104839230Sgibbs if ((dev_select[dn].selected == 0) 104939230Sgibbs || (dev_select[dn].selected > maxshowdevs)) 10501590Srgrimes continue; 105139230Sgibbs 105239230Sgibbs di = dev_select[dn].position; 105339230Sgibbs 105481537Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 105581537Sken &last.dinfo->devices[di], busy_seconds, 105681537Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 105781537Sken DSM_NONE) != 0) 105839230Sgibbs errx(1, "%s", devstat_errbuf); 105939230Sgibbs 106081537Sken (void)printf("%3.0Lf ", transfers_per_second); 10611590Srgrimes } 10621590Srgrimes} 10631590Srgrimes 1064123250Sdesstatic void 1065174573Speterpercent(double pct, int *over) 1066174573Speter{ 1067174573Speter char buf[10]; 1068174573Speter int l; 1069174573Speter 1070174573Speter l = snprintf(buf, sizeof(buf), "%.0f", pct); 1071174573Speter if (l == 1 && *over) { 1072174573Speter printf("%s", buf); 1073174573Speter (*over)--; 1074174573Speter } else 1075174573Speter printf("%2s", buf); 1076174573Speter if (l > 2) 1077174573Speter (*over)++; 1078174573Speter} 1079174573Speter 1080174573Speterstatic void 1081123250Sdescpustats(void) 10821590Srgrimes{ 1083174573Speter int state, over; 108487690Smarkm double lpct, total; 10851590Srgrimes 10861590Srgrimes total = 0; 10871590Srgrimes for (state = 0; state < CPUSTATES; ++state) 108839230Sgibbs total += cur.cp_time[state]; 10891590Srgrimes if (total) 109087690Smarkm lpct = 100.0 / total; 10911590Srgrimes else 109287690Smarkm lpct = 0.0; 1093174573Speter over = 0; 1094174573Speter printf(" "); 1095174573Speter percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over); 1096174573Speter printf(" "); 1097174573Speter percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over); 1098174573Speter printf(" "); 1099174573Speter percent(cur.cp_time[CP_IDLE] * lpct, &over); 11001590Srgrimes} 11011590Srgrimes 1102123250Sdesstatic void 1103174573Speterpcpustats(int ncpus, u_long cpumask, int maxid) 1104174573Speter{ 1105174573Speter int state, i; 1106174573Speter double lpct, total; 1107174573Speter long tmp; 1108174573Speter int over; 1109174573Speter 1110174573Speter /* devstats does this for cp_time */ 1111174573Speter for (i = 0; i <= maxid; i++) { 1112175465Speter if ((cpumask & (1ul << i)) == 0) 1113174573Speter continue; 1114174573Speter for (state = 0; state < CPUSTATES; ++state) { 1115174573Speter tmp = cur_cp_times[i * CPUSTATES + state]; 1116174573Speter cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state]; 1117174573Speter last_cp_times[i * CPUSTATES + state] = tmp; 1118174573Speter } 1119174573Speter } 1120174573Speter 1121174573Speter over = 0; 1122174573Speter for (i = 0; i <= maxid; i++) { 1123175465Speter if ((cpumask & (1ul << i)) == 0) 1124174573Speter continue; 1125174573Speter total = 0; 1126174573Speter for (state = 0; state < CPUSTATES; ++state) 1127174573Speter total += cur_cp_times[i * CPUSTATES + state]; 1128174573Speter if (total) 1129174573Speter lpct = 100.0 / total; 1130174573Speter else 1131174573Speter lpct = 0.0; 1132174573Speter printf(" "); 1133174573Speter percent((cur_cp_times[i * CPUSTATES + CP_USER] + 1134174573Speter cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over); 1135174573Speter printf(" "); 1136174573Speter percent((cur_cp_times[i * CPUSTATES + CP_SYS] + 1137174573Speter cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over); 1138174573Speter printf(" "); 1139174573Speter percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over); 1140174573Speter } 1141174573Speter} 1142174573Speter 1143174573Speterstatic void 1144123250Sdesdointr(void) 11451590Srgrimes{ 1146123407Sdes unsigned long *intrcnt, uptime; 1147123409Sdes uint64_t inttotal; 1148123409Sdes size_t clen, inamlen, intrcntlen, istrnamlen; 1149123409Sdes unsigned int i, nintr; 1150121626Sjmg char *intrname, *tintrname; 11511590Srgrimes 11521590Srgrimes uptime = getuptime(); 1153123250Sdes if (kd != NULL) { 1154224198Spluknet kread(X_SINTRCNT, &intrcntlen, sizeof(intrcntlen)); 1155224198Spluknet kread(X_SINTRNAMES, &inamlen, sizeof(inamlen)); 1156123409Sdes if ((intrcnt = malloc(intrcntlen)) == NULL || 1157123290Smarcel (intrname = malloc(inamlen)) == NULL) 1158123250Sdes err(1, "malloc()"); 1159123409Sdes kread(X_INTRCNT, intrcnt, intrcntlen); 1160123290Smarcel kread(X_INTRNAMES, intrname, inamlen); 1161123250Sdes } else { 1162123438Sdes for (intrcnt = NULL, intrcntlen = 1024; ; intrcntlen *= 2) { 1163123438Sdes if ((intrcnt = reallocf(intrcnt, intrcntlen)) == NULL) 1164123438Sdes err(1, "reallocf()"); 1165123438Sdes if (mysysctl("hw.intrcnt", 1166123438Sdes intrcnt, &intrcntlen, NULL, 0) == 0) 1167123438Sdes break; 1168123438Sdes } 1169123250Sdes for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) { 1170123250Sdes if ((intrname = reallocf(intrname, inamlen)) == NULL) 1171123250Sdes err(1, "reallocf()"); 1172123250Sdes if (mysysctl("hw.intrnames", 1173123250Sdes intrname, &inamlen, NULL, 0) == 0) 1174123250Sdes break; 1175123250Sdes } 1176123250Sdes } 1177123409Sdes nintr = intrcntlen / sizeof(unsigned long); 1178121626Sjmg tintrname = intrname; 1179122365Sjmg istrnamlen = strlen("interrupt"); 1180121626Sjmg for (i = 0; i < nintr; i++) { 1181121626Sjmg clen = strlen(tintrname); 1182121626Sjmg if (clen > istrnamlen) 1183121626Sjmg istrnamlen = clen; 1184121626Sjmg tintrname += clen + 1; 1185121626Sjmg } 1186228654Sdim (void)printf("%-*s %20s %10s\n", (int)istrnamlen, "interrupt", "total", 1187121626Sjmg "rate"); 11881590Srgrimes inttotal = 0; 1189123290Smarcel for (i = 0; i < nintr; i++) { 1190123409Sdes if (intrname[0] != '\0' && (*intrcnt != 0 || aflag)) 1191228654Sdim (void)printf("%-*s %20lu %10lu\n", (int)istrnamlen, 1192228654Sdim intrname, *intrcnt, *intrcnt / uptime); 11931590Srgrimes intrname += strlen(intrname) + 1; 11941590Srgrimes inttotal += *intrcnt++; 11951590Srgrimes } 1196228654Sdim (void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen, 1197228654Sdim "Total", inttotal, inttotal / uptime); 11981590Srgrimes} 11991590Srgrimes 1200148413Srwatsonstatic void 1201148413Srwatsondomemstat_malloc(void) 1202148413Srwatson{ 1203148413Srwatson struct memory_type_list *mtlp; 1204148413Srwatson struct memory_type *mtp; 1205148790Srwatson int error, first, i; 1206148413Srwatson 1207148413Srwatson mtlp = memstat_mtl_alloc(); 1208148413Srwatson if (mtlp == NULL) { 1209148413Srwatson warn("memstat_mtl_alloc"); 1210148413Srwatson return; 1211148413Srwatson } 1212148790Srwatson if (kd == NULL) { 1213148790Srwatson if (memstat_sysctl_malloc(mtlp, 0) < 0) { 1214148790Srwatson warnx("memstat_sysctl_malloc: %s", 1215148790Srwatson memstat_strerror(memstat_mtl_geterror(mtlp))); 1216148790Srwatson return; 1217148790Srwatson } 1218148790Srwatson } else { 1219148790Srwatson if (memstat_kvm_malloc(mtlp, kd) < 0) { 1220148790Srwatson error = memstat_mtl_geterror(mtlp); 1221148790Srwatson if (error == MEMSTAT_ERROR_KVM) 1222148790Srwatson warnx("memstat_kvm_malloc: %s", 1223148790Srwatson kvm_geterr(kd)); 1224148790Srwatson else 1225148790Srwatson warnx("memstat_kvm_malloc: %s", 1226148790Srwatson memstat_strerror(error)); 1227148790Srwatson } 1228148413Srwatson } 1229148413Srwatson printf("%13s %5s %6s %7s %8s Size(s)\n", "Type", "InUse", "MemUse", 1230148413Srwatson "HighUse", "Requests"); 1231148413Srwatson for (mtp = memstat_mtl_first(mtlp); mtp != NULL; 1232148413Srwatson mtp = memstat_mtl_next(mtp)) { 1233148413Srwatson if (memstat_get_numallocs(mtp) == 0 && 1234148413Srwatson memstat_get_count(mtp) == 0) 1235148413Srwatson continue; 1236228654Sdim printf("%13s %5" PRIu64 " %5" PRIu64 "K %7s %8" PRIu64 " ", 1237148413Srwatson memstat_get_name(mtp), memstat_get_count(mtp), 1238228654Sdim (memstat_get_bytes(mtp) + 1023) / 1024, "-", 1239148413Srwatson memstat_get_numallocs(mtp)); 1240148413Srwatson first = 1; 1241148413Srwatson for (i = 0; i < 32; i++) { 1242148413Srwatson if (memstat_get_sizemask(mtp) & (1 << i)) { 1243148413Srwatson if (!first) 1244148413Srwatson printf(","); 1245148413Srwatson printf("%d", 1 << (i + 4)); 1246148413Srwatson first = 0; 1247148413Srwatson } 1248148413Srwatson } 1249148413Srwatson printf("\n"); 1250148413Srwatson } 1251148413Srwatson memstat_mtl_free(mtlp); 1252148413Srwatson} 1253148413Srwatson 1254148413Srwatsonstatic void 1255148413Srwatsondomemstat_zone(void) 1256148413Srwatson{ 1257148413Srwatson struct memory_type_list *mtlp; 1258148413Srwatson struct memory_type *mtp; 1259148413Srwatson char name[MEMTYPE_MAXNAME + 1]; 1260148630Srwatson int error; 1261148413Srwatson 1262148413Srwatson mtlp = memstat_mtl_alloc(); 1263148413Srwatson if (mtlp == NULL) { 1264148413Srwatson warn("memstat_mtl_alloc"); 1265148413Srwatson return; 1266148413Srwatson } 1267148630Srwatson if (kd == NULL) { 1268148630Srwatson if (memstat_sysctl_uma(mtlp, 0) < 0) { 1269148630Srwatson warnx("memstat_sysctl_uma: %s", 1270148630Srwatson memstat_strerror(memstat_mtl_geterror(mtlp))); 1271148630Srwatson return; 1272148630Srwatson } 1273148630Srwatson } else { 1274148630Srwatson if (memstat_kvm_uma(mtlp, kd) < 0) { 1275148630Srwatson error = memstat_mtl_geterror(mtlp); 1276148630Srwatson if (error == MEMSTAT_ERROR_KVM) 1277148630Srwatson warnx("memstat_kvm_uma: %s", 1278148630Srwatson kvm_geterr(kd)); 1279148630Srwatson else 1280148630Srwatson warnx("memstat_kvm_uma: %s", 1281148630Srwatson memstat_strerror(error)); 1282148630Srwatson } 1283148413Srwatson } 1284209215Ssbruno printf("%-20s %6s %6s %8s %8s %8s %4s %4s\n\n", "ITEM", "SIZE", 1285209215Ssbruno "LIMIT", "USED", "FREE", "REQ", "FAIL", "SLEEP"); 1286148413Srwatson for (mtp = memstat_mtl_first(mtlp); mtp != NULL; 1287148413Srwatson mtp = memstat_mtl_next(mtp)) { 1288148413Srwatson strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME); 1289148413Srwatson strcat(name, ":"); 1290228654Sdim printf("%-20s %6" PRIu64 ", %6" PRIu64 ",%8" PRIu64 ",%8" PRIu64 1291228654Sdim ",%8" PRIu64 ",%4" PRIu64 ",%4" PRIu64 "\n", name, 1292148413Srwatson memstat_get_size(mtp), memstat_get_countlimit(mtp), 1293148413Srwatson memstat_get_count(mtp), memstat_get_free(mtp), 1294209215Ssbruno memstat_get_numallocs(mtp), memstat_get_failures(mtp), 1295209215Ssbruno memstat_get_sleeps(mtp)); 1296148413Srwatson } 1297148413Srwatson memstat_mtl_free(mtlp); 1298148413Srwatson printf("\n"); 1299148413Srwatson} 1300148413Srwatson 1301148413Srwatson/* 13021590Srgrimes * kread reads something from the kernel, given its nlist index. 13031590Srgrimes */ 1304123250Sdesstatic void 1305131300Sgreenkreado(int nlx, void *addr, size_t size, size_t offset) 13061590Srgrimes{ 1307123825Sdwmalone const char *sym; 13081590Srgrimes 130940690Sjdp if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { 13101590Srgrimes sym = namelist[nlx].n_name; 13111590Srgrimes if (*sym == '_') 13121590Srgrimes ++sym; 131328693Scharnier errx(1, "symbol %s not defined", sym); 13141590Srgrimes } 1315131300Sgreen if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr, 1316131300Sgreen size) != size) { 13171590Srgrimes sym = namelist[nlx].n_name; 13181590Srgrimes if (*sym == '_') 13191590Srgrimes ++sym; 132028693Scharnier errx(1, "%s: %s", sym, kvm_geterr(kd)); 13211590Srgrimes } 13221590Srgrimes} 13231590Srgrimes 1324123250Sdesstatic void 1325131300Sgreenkread(int nlx, void *addr, size_t size) 1326131300Sgreen{ 1327131300Sgreen kreado(nlx, addr, size, 0); 1328131300Sgreen} 1329131300Sgreen 1330131300Sgreenstatic char * 1331131300Sgreenkgetstr(const char *strp) 1332131300Sgreen{ 1333131300Sgreen int n = 0, size = 1; 1334131300Sgreen char *ret = NULL; 1335131300Sgreen 1336131300Sgreen do { 1337131300Sgreen if (size == n + 1) { 1338131300Sgreen ret = realloc(ret, size); 1339131300Sgreen if (ret == NULL) 1340131300Sgreen err(1, "%s: realloc", __func__); 1341131300Sgreen size *= 2; 1342131300Sgreen } 1343131300Sgreen if (kvm_read(kd, (u_long)strp + n, &ret[n], 1) != 1) 1344131300Sgreen errx(1, "%s: %s", __func__, kvm_geterr(kd)); 1345131300Sgreen } while (ret[n++] != '\0'); 1346131300Sgreen return (ret); 1347131300Sgreen} 1348131300Sgreen 1349131300Sgreenstatic void 1350123250Sdesusage(void) 13511590Srgrimes{ 135272887Salfred (void)fprintf(stderr, "%s%s", 1353178063Sru "usage: vmstat [-afHhimPsz] [-c count] [-M core [-N system]] [-w wait]\n", 1354146466Sru " [-n devs] [-p type,if,pass] [disks]\n"); 13551590Srgrimes exit(1); 13561590Srgrimes} 1357