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; 653273188Shrs ncpus = 1; 654273188Shrs maxid = 0; 655184645Skeramida 656184645Skeramida /* 657184645Skeramida * If the user stops the program (control-Z) and then resumes it, 658184645Skeramida * print out the header again. 659184645Skeramida */ 6601590Srgrimes (void)signal(SIGCONT, needhdr); 6611590Srgrimes 662184645Skeramida /* 663184645Skeramida * If our standard output is a tty, then install a SIGWINCH handler 664184645Skeramida * and set wresized so that our first iteration through the main 665184646Skeramida * vmstat loop will peek at the terminal's current rows to find out 666184645Skeramida * how many lines can fit in a screenful of output. 667184645Skeramida */ 668184645Skeramida if (isatty(fileno(stdout)) != 0) { 669184645Skeramida wresized = 1; 670184645Skeramida (void)signal(SIGWINCH, needresize); 671184645Skeramida } else { 672184645Skeramida wresized = 0; 673184645Skeramida winlines = VMSTAT_DEFAULT_LINES; 674184645Skeramida } 675184645Skeramida 676123250Sdes if (kd != NULL) { 677123250Sdes if (namelist[X_STATHZ].n_type != 0 && 678123250Sdes namelist[X_STATHZ].n_value != 0) 679123250Sdes kread(X_STATHZ, &hz, sizeof(hz)); 680123250Sdes if (!hz) 681123250Sdes kread(X_HZ, &hz, sizeof(hz)); 682123250Sdes } else { 683123250Sdes struct clockinfo clockrate; 6841590Srgrimes 685123250Sdes size = sizeof(clockrate); 686123250Sdes mysysctl("kern.clockrate", &clockrate, &size, NULL, 0); 687123250Sdes if (size != sizeof(clockrate)) 688123250Sdes errx(1, "clockrate size mismatch"); 689123250Sdes hz = clockrate.hz; 690123250Sdes } 691123250Sdes 692174573Speter if (Pflag) { 693174573Speter ncpus = getcpuinfo(&cpumask, &maxid); 694174573Speter size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES; 695188888Sdelphij cur_cp_times = calloc(1, size_cp_times); 696188888Sdelphij last_cp_times = calloc(1, size_cp_times); 697174573Speter } 6981590Srgrimes for (hdrcnt = 1;;) { 6991590Srgrimes if (!--hdrcnt) 700273188Shrs printhdr(maxid, cpumask); 701123250Sdes if (kd != NULL) { 702181881Sjhb if (kvm_getcptime(kd, cur.cp_time) < 0) 703181881Sjhb errx(1, "kvm_getcptime: %s", kvm_geterr(kd)); 704123250Sdes } else { 705123250Sdes size = sizeof(cur.cp_time); 706123250Sdes mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0); 707123250Sdes if (size != sizeof(cur.cp_time)) 708123250Sdes errx(1, "cp_time size mismatch"); 709123250Sdes } 710174573Speter if (Pflag) { 711174573Speter size = size_cp_times; 712174573Speter mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0); 713174573Speter if (size != size_cp_times) 714174573Speter errx(1, "cp_times mismatch"); 715174573Speter } 71639230Sgibbs 71739230Sgibbs tmp_dinfo = last.dinfo; 71839230Sgibbs last.dinfo = cur.dinfo; 71939230Sgibbs cur.dinfo = tmp_dinfo; 720112288Sphk last.snap_time = cur.snap_time; 72139230Sgibbs 72239230Sgibbs /* 72339230Sgibbs * Here what we want to do is refresh our device stats. 72439230Sgibbs * getdevs() returns 1 when the device list has changed. 72539230Sgibbs * If the device list has changed, we want to go through 72639230Sgibbs * the selection process again, in case a device that we 72739230Sgibbs * were previously displaying has gone away. 72839230Sgibbs */ 729112284Sphk switch (devstat_getdevs(NULL, &cur)) { 73039230Sgibbs case -1: 73139230Sgibbs errx(1, "%s", devstat_errbuf); 73239230Sgibbs break; 73339230Sgibbs case 1: { 73439230Sgibbs int retval; 73539230Sgibbs 73639230Sgibbs num_devices = cur.dinfo->numdevs; 73739230Sgibbs generation = cur.dinfo->generation; 73839230Sgibbs 739112284Sphk retval = devstat_selectdevs(&dev_select, &num_selected, 74039230Sgibbs &num_selections, &select_generation, 74139230Sgibbs generation, cur.dinfo->devices, 74239230Sgibbs num_devices, matches, num_matches, 74339230Sgibbs specified_devices, 74439230Sgibbs num_devices_specified, select_mode, 74539230Sgibbs maxshowdevs, 0); 74639230Sgibbs switch (retval) { 74739230Sgibbs case -1: 74839230Sgibbs errx(1, "%s", devstat_errbuf); 74939230Sgibbs break; 75039230Sgibbs case 1: 751273188Shrs printhdr(maxid, cpumask); 75239230Sgibbs break; 75339230Sgibbs default: 75439230Sgibbs break; 75539230Sgibbs } 75639230Sgibbs } 75739230Sgibbs default: 75839230Sgibbs break; 75939230Sgibbs } 76039230Sgibbs 761123250Sdes fill_vmmeter(&sum); 762123250Sdes fill_vmtotal(&total); 763164718Sru (void)printf("%2d %1d %1d", 7641590Srgrimes total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); 765164718Sru#define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10)) 766208389Ssbruno#define rate(x) (((x) * rate_adj + halfuptime) / uptime) /* round */ 767174573Speter if (hflag) { 768174573Speter printf(" "); 769174573Speter prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7); 770174573Speter printf(" "); 771174573Speter prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6); 772174573Speter printf(" "); 773174573Speter } else { 774174573Speter printf(" %7d ", vmstat_pgtok(total.t_avm)); 775174573Speter printf(" %6d ", vmstat_pgtok(total.t_free)); 776174573Speter } 777159200Sobrien (void)printf("%5lu ", 778123407Sdes (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); 7791590Srgrimes (void)printf("%3lu ", 780123407Sdes (unsigned long)rate(sum.v_reactivated - osum.v_reactivated)); 78137453Sbde (void)printf("%3lu ", 782123407Sdes (unsigned long)rate(sum.v_swapin + sum.v_vnodein - 7833659Sdg (osum.v_swapin + osum.v_vnodein))); 78437453Sbde (void)printf("%3lu ", 785123407Sdes (unsigned long)rate(sum.v_swapout + sum.v_vnodeout - 7863693Sdg (osum.v_swapout + osum.v_vnodeout))); 787159200Sobrien (void)printf("%5lu ", 788123407Sdes (unsigned long)rate(sum.v_tfree - osum.v_tfree)); 78937453Sbde (void)printf("%3lu ", 790123407Sdes (unsigned long)rate(sum.v_pdpages - osum.v_pdpages)); 79139230Sgibbs devstats(); 792174573Speter (void)printf("%4lu %4lu %4lu", 793123407Sdes (unsigned long)rate(sum.v_intr - osum.v_intr), 794123407Sdes (unsigned long)rate(sum.v_syscall - osum.v_syscall), 795123407Sdes (unsigned long)rate(sum.v_swtch - osum.v_swtch)); 796174573Speter if (Pflag) 797174573Speter pcpustats(ncpus, cpumask, maxid); 798174573Speter else 799174573Speter cpustats(); 8001590Srgrimes (void)printf("\n"); 8011590Srgrimes (void)fflush(stdout); 8021590Srgrimes if (reps >= 0 && --reps <= 0) 8031590Srgrimes break; 8041590Srgrimes osum = sum; 8051590Srgrimes uptime = interval; 806208389Ssbruno rate_adj = 1000; 8071590Srgrimes /* 8081590Srgrimes * We round upward to avoid losing low-frequency events 809208389Ssbruno * (i.e., >= 1 per interval but < 1 per millisecond). 8101590Srgrimes */ 8113659Sdg if (interval != 1) 8123659Sdg halfuptime = (uptime + 1) / 2; 8133659Sdg else 8143659Sdg halfuptime = 0; 815208389Ssbruno (void)usleep(interval * 1000); 8161590Srgrimes } 8171590Srgrimes} 8181590Srgrimes 819123250Sdesstatic void 820273188Shrsprinthdr(int maxid, u_long cpumask) 8211590Srgrimes{ 82243822Sken int i, num_shown; 8231590Srgrimes 82443822Sken num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs; 82578672Sschweikh (void)printf(" procs memory page%*s", 19, ""); 82643822Sken if (num_shown > 1) 82743822Sken (void)printf(" disks %*s", num_shown * 4 - 7, ""); 82843822Sken else if (num_shown == 1) 82943822Sken (void)printf("disk"); 830174573Speter (void)printf(" faults "); 831174573Speter if (Pflag) { 832273188Shrs for (i = 0; i <= maxid; i++) { 833175465Speter if (cpumask & (1ul << i)) 834174573Speter printf("cpu%-2d ", i); 835174573Speter } 836174573Speter printf("\n"); 837174573Speter } else 838174573Speter printf("cpu\n"); 839159200Sobrien (void)printf(" r b w avm fre flt re pi po fr sr "); 84039230Sgibbs for (i = 0; i < num_devices; i++) 84139230Sgibbs if ((dev_select[i].selected) 84239230Sgibbs && (dev_select[i].selected <= maxshowdevs)) 84339230Sgibbs (void)printf("%c%c%d ", dev_select[i].device_name[0], 84439230Sgibbs dev_select[i].device_name[1], 84539230Sgibbs dev_select[i].unit_number); 846174573Speter (void)printf(" in sy cs"); 847174573Speter if (Pflag) { 848273188Shrs for (i = 0; i <= maxid; i++) { 849273188Shrs if (cpumask & (1ul << i)) 850273188Shrs printf(" us sy id"); 851273188Shrs } 852174573Speter printf("\n"); 853174573Speter } else 854174573Speter printf(" us sy id\n"); 855184645Skeramida if (wresized != 0) 856184645Skeramida doresize(); 857184645Skeramida hdrcnt = winlines; 8581590Srgrimes} 8591590Srgrimes 8601590Srgrimes/* 8611590Srgrimes * Force a header to be prepended to the next output. 8621590Srgrimes */ 863123250Sdesstatic void 864123250Sdesneedhdr(int dummy __unused) 8651590Srgrimes{ 8661590Srgrimes 8671590Srgrimes hdrcnt = 1; 8681590Srgrimes} 8691590Srgrimes 870184645Skeramida/* 871184645Skeramida * When the terminal is resized, force an update of the maximum number of rows 872184645Skeramida * printed between each header repetition. Then force a new header to be 873184645Skeramida * prepended to the next output. 874184645Skeramida */ 875184645Skeramidavoid 876184645Skeramidaneedresize(int signo) 877184645Skeramida{ 878184645Skeramida 879184645Skeramida wresized = 1; 880184645Skeramida hdrcnt = 1; 881184645Skeramida} 882184645Skeramida 883184645Skeramida/* 884184645Skeramida * Update the global `winlines' count of terminal rows. 885184645Skeramida */ 886184645Skeramidavoid 887184645Skeramidadoresize(void) 888184645Skeramida{ 889184645Skeramida int status; 890184645Skeramida struct winsize w; 891184645Skeramida 892184645Skeramida for (;;) { 893184645Skeramida status = ioctl(fileno(stdout), TIOCGWINSZ, &w); 894184645Skeramida if (status == -1 && errno == EINTR) 895184645Skeramida continue; 896184645Skeramida else if (status == -1) 897184645Skeramida err(1, "ioctl"); 898184645Skeramida if (w.ws_row > 3) 899184645Skeramida winlines = w.ws_row - 3; 900184645Skeramida else 901184645Skeramida winlines = VMSTAT_DEFAULT_LINES; 902184645Skeramida break; 903184645Skeramida } 904184645Skeramida 905184645Skeramida /* 906184645Skeramida * Inhibit doresize() calls until we are rescheduled by SIGWINCH. 907184645Skeramida */ 908184645Skeramida wresized = 0; 909184645Skeramida} 910184645Skeramida 91130180Sdima#ifdef notyet 912123250Sdesstatic void 913123250Sdesdotimes(void) 9141590Srgrimes{ 915123407Sdes unsigned int pgintime, rectime; 9161590Srgrimes 9171590Srgrimes kread(X_REC, &rectime, sizeof(rectime)); 9181590Srgrimes kread(X_PGIN, &pgintime, sizeof(pgintime)); 9191590Srgrimes kread(X_SUM, &sum, sizeof(sum)); 9201590Srgrimes (void)printf("%u reclaims, %u total time (usec)\n", 9211590Srgrimes sum.v_pgrec, rectime); 9221590Srgrimes (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); 9231590Srgrimes (void)printf("\n"); 9241590Srgrimes (void)printf("%u page ins, %u total time (msec)\n", 9251590Srgrimes sum.v_pgin, pgintime / 10); 9261590Srgrimes (void)printf("average: %8.1f msec / page in\n", 9271590Srgrimes pgintime / (sum.v_pgin * 10.0)); 9281590Srgrimes} 9291590Srgrimes#endif 9301590Srgrimes 931123250Sdesstatic long 932123250Sdespct(long top, long bot) 9331590Srgrimes{ 9341590Srgrimes long ans; 9351590Srgrimes 9361590Srgrimes if (bot == 0) 9371590Srgrimes return(0); 9381590Srgrimes ans = (quad_t)top * 100 / bot; 9391590Srgrimes return (ans); 9401590Srgrimes} 9411590Srgrimes 9421590Srgrimes#define PCT(top, bot) pct((long)(top), (long)(bot)) 9431590Srgrimes 944123250Sdesstatic void 945123250Sdesdosum(void) 9461590Srgrimes{ 94787690Smarkm struct nchstats lnchstats; 9481590Srgrimes long nchtotal; 9491590Srgrimes 950123250Sdes fill_vmmeter(&sum); 9511590Srgrimes (void)printf("%9u cpu context switches\n", sum.v_swtch); 9521590Srgrimes (void)printf("%9u device interrupts\n", sum.v_intr); 9531590Srgrimes (void)printf("%9u software interrupts\n", sum.v_soft); 9541590Srgrimes (void)printf("%9u traps\n", sum.v_trap); 9551590Srgrimes (void)printf("%9u system calls\n", sum.v_syscall); 95671429Sume (void)printf("%9u kernel threads created\n", sum.v_kthreads); 95771429Sume (void)printf("%9u fork() calls\n", sum.v_forks); 95871429Sume (void)printf("%9u vfork() calls\n", sum.v_vforks); 95971429Sume (void)printf("%9u rfork() calls\n", sum.v_rforks); 9603659Sdg (void)printf("%9u swap pager pageins\n", sum.v_swapin); 9613693Sdg (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin); 9623659Sdg (void)printf("%9u swap pager pageouts\n", sum.v_swapout); 9633659Sdg (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout); 9643659Sdg (void)printf("%9u vnode pager pageins\n", sum.v_vnodein); 9653693Sdg (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin); 9663659Sdg (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout); 9673659Sdg (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout); 9683693Sdg (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups); 9693693Sdg (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages); 9701590Srgrimes (void)printf("%9u pages reactivated\n", sum.v_reactivated); 9717351Sdg (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); 97234214Sdyson (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim); 9737351Sdg (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod); 97434214Sdyson (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod); 9751590Srgrimes (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); 9761590Srgrimes (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); 977246034Szont (void)printf("%9u page faults requiring I/O\n", sum.v_io_faults); 97871429Sume (void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages); 97971429Sume (void)printf("%9u pages affected by fork()\n", sum.v_forkpages); 98071429Sume (void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages); 98171429Sume (void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages); 982171633Salc (void)printf("%9u pages cached\n", sum.v_tcached); 9833693Sdg (void)printf("%9u pages freed\n", sum.v_tfree); 9841590Srgrimes (void)printf("%9u pages freed by daemon\n", sum.v_dfree); 9851590Srgrimes (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); 9861590Srgrimes (void)printf("%9u pages active\n", sum.v_active_count); 9871590Srgrimes (void)printf("%9u pages inactive\n", sum.v_inactive_count); 9885463Sdg (void)printf("%9u pages in VM cache\n", sum.v_cache_count); 9893693Sdg (void)printf("%9u pages wired down\n", sum.v_wire_count); 9903693Sdg (void)printf("%9u pages free\n", sum.v_free_count); 9911590Srgrimes (void)printf("%9u bytes per page\n", sum.v_page_size); 992123250Sdes if (kd != NULL) { 993123250Sdes kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); 994123250Sdes } else { 995123250Sdes size_t size = sizeof(lnchstats); 996123250Sdes mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0); 997123250Sdes if (size != sizeof(lnchstats)) 998123250Sdes errx(1, "vfs.cache.nchstats size mismatch"); 999123250Sdes } 100087690Smarkm nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits + 100187690Smarkm lnchstats.ncs_badhits + lnchstats.ncs_falsehits + 100287690Smarkm lnchstats.ncs_miss + lnchstats.ncs_long; 10031590Srgrimes (void)printf("%9ld total name lookups\n", nchtotal); 10041590Srgrimes (void)printf( 100528693Scharnier "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n", 100687690Smarkm "", PCT(lnchstats.ncs_goodhits, nchtotal), 100787690Smarkm PCT(lnchstats.ncs_neghits, nchtotal), 100887690Smarkm PCT(lnchstats.ncs_pass2, nchtotal)); 100928693Scharnier (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "", 101087690Smarkm PCT(lnchstats.ncs_badhits, nchtotal), 101187690Smarkm PCT(lnchstats.ncs_falsehits, nchtotal), 101287690Smarkm PCT(lnchstats.ncs_long, nchtotal)); 10131590Srgrimes} 10141590Srgrimes 1015123250Sdesstatic void 1016123250Sdesdoforkst(void) 10171590Srgrimes{ 1018123250Sdes fill_vmmeter(&sum); 1019128573Stjr (void)printf("%u forks, %u pages, average %.2f\n", 1020113460Stjr sum.v_forks, sum.v_forkpages, 1021113460Stjr sum.v_forks == 0 ? 0.0 : 1022113460Stjr (double)sum.v_forkpages / sum.v_forks); 1023128573Stjr (void)printf("%u vforks, %u pages, average %.2f\n", 1024113460Stjr sum.v_vforks, sum.v_vforkpages, 1025113460Stjr sum.v_vforks == 0 ? 0.0 : 1026113460Stjr (double)sum.v_vforkpages / sum.v_vforks); 1027128573Stjr (void)printf("%u rforks, %u pages, average %.2f\n", 1028113460Stjr sum.v_rforks, sum.v_rforkpages, 1029113460Stjr sum.v_rforks == 0 ? 0.0 : 1030113460Stjr (double)sum.v_rforkpages / sum.v_rforks); 10311590Srgrimes} 10321590Srgrimes 103339230Sgibbsstatic void 1034123250Sdesdevstats(void) 10351590Srgrimes{ 103687690Smarkm int dn, state; 103739230Sgibbs long double transfers_per_second; 103839230Sgibbs long double busy_seconds; 10391590Srgrimes long tmp; 1040123250Sdes 10411590Srgrimes for (state = 0; state < CPUSTATES; ++state) { 104239230Sgibbs tmp = cur.cp_time[state]; 104339230Sgibbs cur.cp_time[state] -= last.cp_time[state]; 104439230Sgibbs last.cp_time[state] = tmp; 10451590Srgrimes } 104639230Sgibbs 1047112288Sphk busy_seconds = cur.snap_time - last.snap_time; 104839230Sgibbs 104939230Sgibbs for (dn = 0; dn < num_devices; dn++) { 105039230Sgibbs int di; 105139230Sgibbs 105239230Sgibbs if ((dev_select[dn].selected == 0) 105339230Sgibbs || (dev_select[dn].selected > maxshowdevs)) 10541590Srgrimes continue; 105539230Sgibbs 105639230Sgibbs di = dev_select[dn].position; 105739230Sgibbs 105881537Sken if (devstat_compute_statistics(&cur.dinfo->devices[di], 105981537Sken &last.dinfo->devices[di], busy_seconds, 106081537Sken DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 106181537Sken DSM_NONE) != 0) 106239230Sgibbs errx(1, "%s", devstat_errbuf); 106339230Sgibbs 106481537Sken (void)printf("%3.0Lf ", transfers_per_second); 10651590Srgrimes } 10661590Srgrimes} 10671590Srgrimes 1068123250Sdesstatic void 1069174573Speterpercent(double pct, int *over) 1070174573Speter{ 1071174573Speter char buf[10]; 1072174573Speter int l; 1073174573Speter 1074174573Speter l = snprintf(buf, sizeof(buf), "%.0f", pct); 1075174573Speter if (l == 1 && *over) { 1076174573Speter printf("%s", buf); 1077174573Speter (*over)--; 1078174573Speter } else 1079174573Speter printf("%2s", buf); 1080174573Speter if (l > 2) 1081174573Speter (*over)++; 1082174573Speter} 1083174573Speter 1084174573Speterstatic void 1085123250Sdescpustats(void) 10861590Srgrimes{ 1087174573Speter int state, over; 108887690Smarkm double lpct, total; 10891590Srgrimes 10901590Srgrimes total = 0; 10911590Srgrimes for (state = 0; state < CPUSTATES; ++state) 109239230Sgibbs total += cur.cp_time[state]; 10931590Srgrimes if (total) 109487690Smarkm lpct = 100.0 / total; 10951590Srgrimes else 109687690Smarkm lpct = 0.0; 1097174573Speter over = 0; 1098174573Speter printf(" "); 1099174573Speter percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over); 1100174573Speter printf(" "); 1101174573Speter percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over); 1102174573Speter printf(" "); 1103174573Speter percent(cur.cp_time[CP_IDLE] * lpct, &over); 11041590Srgrimes} 11051590Srgrimes 1106123250Sdesstatic void 1107174573Speterpcpustats(int ncpus, u_long cpumask, int maxid) 1108174573Speter{ 1109174573Speter int state, i; 1110174573Speter double lpct, total; 1111174573Speter long tmp; 1112174573Speter int over; 1113174573Speter 1114174573Speter /* devstats does this for cp_time */ 1115174573Speter for (i = 0; i <= maxid; i++) { 1116175465Speter if ((cpumask & (1ul << i)) == 0) 1117174573Speter continue; 1118174573Speter for (state = 0; state < CPUSTATES; ++state) { 1119174573Speter tmp = cur_cp_times[i * CPUSTATES + state]; 1120174573Speter cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state]; 1121174573Speter last_cp_times[i * CPUSTATES + state] = tmp; 1122174573Speter } 1123174573Speter } 1124174573Speter 1125174573Speter over = 0; 1126174573Speter for (i = 0; i <= maxid; i++) { 1127175465Speter if ((cpumask & (1ul << i)) == 0) 1128174573Speter continue; 1129174573Speter total = 0; 1130174573Speter for (state = 0; state < CPUSTATES; ++state) 1131174573Speter total += cur_cp_times[i * CPUSTATES + state]; 1132174573Speter if (total) 1133174573Speter lpct = 100.0 / total; 1134174573Speter else 1135174573Speter lpct = 0.0; 1136174573Speter printf(" "); 1137174573Speter percent((cur_cp_times[i * CPUSTATES + CP_USER] + 1138174573Speter cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over); 1139174573Speter printf(" "); 1140174573Speter percent((cur_cp_times[i * CPUSTATES + CP_SYS] + 1141174573Speter cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over); 1142174573Speter printf(" "); 1143174573Speter percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over); 1144174573Speter } 1145174573Speter} 1146174573Speter 1147174573Speterstatic void 1148123250Sdesdointr(void) 11491590Srgrimes{ 1150123407Sdes unsigned long *intrcnt, uptime; 1151123409Sdes uint64_t inttotal; 1152123409Sdes size_t clen, inamlen, intrcntlen, istrnamlen; 1153123409Sdes unsigned int i, nintr; 1154121626Sjmg char *intrname, *tintrname; 11551590Srgrimes 11561590Srgrimes uptime = getuptime(); 1157123250Sdes if (kd != NULL) { 1158224198Spluknet kread(X_SINTRCNT, &intrcntlen, sizeof(intrcntlen)); 1159224198Spluknet kread(X_SINTRNAMES, &inamlen, sizeof(inamlen)); 1160123409Sdes if ((intrcnt = malloc(intrcntlen)) == NULL || 1161123290Smarcel (intrname = malloc(inamlen)) == NULL) 1162123250Sdes err(1, "malloc()"); 1163123409Sdes kread(X_INTRCNT, intrcnt, intrcntlen); 1164123290Smarcel kread(X_INTRNAMES, intrname, inamlen); 1165123250Sdes } else { 1166123438Sdes for (intrcnt = NULL, intrcntlen = 1024; ; intrcntlen *= 2) { 1167123438Sdes if ((intrcnt = reallocf(intrcnt, intrcntlen)) == NULL) 1168123438Sdes err(1, "reallocf()"); 1169123438Sdes if (mysysctl("hw.intrcnt", 1170123438Sdes intrcnt, &intrcntlen, NULL, 0) == 0) 1171123438Sdes break; 1172123438Sdes } 1173123250Sdes for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) { 1174123250Sdes if ((intrname = reallocf(intrname, inamlen)) == NULL) 1175123250Sdes err(1, "reallocf()"); 1176123250Sdes if (mysysctl("hw.intrnames", 1177123250Sdes intrname, &inamlen, NULL, 0) == 0) 1178123250Sdes break; 1179123250Sdes } 1180123250Sdes } 1181123409Sdes nintr = intrcntlen / sizeof(unsigned long); 1182121626Sjmg tintrname = intrname; 1183122365Sjmg istrnamlen = strlen("interrupt"); 1184121626Sjmg for (i = 0; i < nintr; i++) { 1185121626Sjmg clen = strlen(tintrname); 1186121626Sjmg if (clen > istrnamlen) 1187121626Sjmg istrnamlen = clen; 1188121626Sjmg tintrname += clen + 1; 1189121626Sjmg } 1190228654Sdim (void)printf("%-*s %20s %10s\n", (int)istrnamlen, "interrupt", "total", 1191121626Sjmg "rate"); 11921590Srgrimes inttotal = 0; 1193123290Smarcel for (i = 0; i < nintr; i++) { 1194123409Sdes if (intrname[0] != '\0' && (*intrcnt != 0 || aflag)) 1195228654Sdim (void)printf("%-*s %20lu %10lu\n", (int)istrnamlen, 1196228654Sdim intrname, *intrcnt, *intrcnt / uptime); 11971590Srgrimes intrname += strlen(intrname) + 1; 11981590Srgrimes inttotal += *intrcnt++; 11991590Srgrimes } 1200228654Sdim (void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen, 1201228654Sdim "Total", inttotal, inttotal / uptime); 12021590Srgrimes} 12031590Srgrimes 1204148413Srwatsonstatic void 1205148413Srwatsondomemstat_malloc(void) 1206148413Srwatson{ 1207148413Srwatson struct memory_type_list *mtlp; 1208148413Srwatson struct memory_type *mtp; 1209148790Srwatson int error, first, i; 1210148413Srwatson 1211148413Srwatson mtlp = memstat_mtl_alloc(); 1212148413Srwatson if (mtlp == NULL) { 1213148413Srwatson warn("memstat_mtl_alloc"); 1214148413Srwatson return; 1215148413Srwatson } 1216148790Srwatson if (kd == NULL) { 1217148790Srwatson if (memstat_sysctl_malloc(mtlp, 0) < 0) { 1218148790Srwatson warnx("memstat_sysctl_malloc: %s", 1219148790Srwatson memstat_strerror(memstat_mtl_geterror(mtlp))); 1220148790Srwatson return; 1221148790Srwatson } 1222148790Srwatson } else { 1223148790Srwatson if (memstat_kvm_malloc(mtlp, kd) < 0) { 1224148790Srwatson error = memstat_mtl_geterror(mtlp); 1225148790Srwatson if (error == MEMSTAT_ERROR_KVM) 1226148790Srwatson warnx("memstat_kvm_malloc: %s", 1227148790Srwatson kvm_geterr(kd)); 1228148790Srwatson else 1229148790Srwatson warnx("memstat_kvm_malloc: %s", 1230148790Srwatson memstat_strerror(error)); 1231148790Srwatson } 1232148413Srwatson } 1233148413Srwatson printf("%13s %5s %6s %7s %8s Size(s)\n", "Type", "InUse", "MemUse", 1234148413Srwatson "HighUse", "Requests"); 1235148413Srwatson for (mtp = memstat_mtl_first(mtlp); mtp != NULL; 1236148413Srwatson mtp = memstat_mtl_next(mtp)) { 1237148413Srwatson if (memstat_get_numallocs(mtp) == 0 && 1238148413Srwatson memstat_get_count(mtp) == 0) 1239148413Srwatson continue; 1240228654Sdim printf("%13s %5" PRIu64 " %5" PRIu64 "K %7s %8" PRIu64 " ", 1241148413Srwatson memstat_get_name(mtp), memstat_get_count(mtp), 1242228654Sdim (memstat_get_bytes(mtp) + 1023) / 1024, "-", 1243148413Srwatson memstat_get_numallocs(mtp)); 1244148413Srwatson first = 1; 1245148413Srwatson for (i = 0; i < 32; i++) { 1246148413Srwatson if (memstat_get_sizemask(mtp) & (1 << i)) { 1247148413Srwatson if (!first) 1248148413Srwatson printf(","); 1249148413Srwatson printf("%d", 1 << (i + 4)); 1250148413Srwatson first = 0; 1251148413Srwatson } 1252148413Srwatson } 1253148413Srwatson printf("\n"); 1254148413Srwatson } 1255148413Srwatson memstat_mtl_free(mtlp); 1256148413Srwatson} 1257148413Srwatson 1258148413Srwatsonstatic void 1259148413Srwatsondomemstat_zone(void) 1260148413Srwatson{ 1261148413Srwatson struct memory_type_list *mtlp; 1262148413Srwatson struct memory_type *mtp; 1263148413Srwatson char name[MEMTYPE_MAXNAME + 1]; 1264148630Srwatson int error; 1265148413Srwatson 1266148413Srwatson mtlp = memstat_mtl_alloc(); 1267148413Srwatson if (mtlp == NULL) { 1268148413Srwatson warn("memstat_mtl_alloc"); 1269148413Srwatson return; 1270148413Srwatson } 1271148630Srwatson if (kd == NULL) { 1272148630Srwatson if (memstat_sysctl_uma(mtlp, 0) < 0) { 1273148630Srwatson warnx("memstat_sysctl_uma: %s", 1274148630Srwatson memstat_strerror(memstat_mtl_geterror(mtlp))); 1275148630Srwatson return; 1276148630Srwatson } 1277148630Srwatson } else { 1278148630Srwatson if (memstat_kvm_uma(mtlp, kd) < 0) { 1279148630Srwatson error = memstat_mtl_geterror(mtlp); 1280148630Srwatson if (error == MEMSTAT_ERROR_KVM) 1281148630Srwatson warnx("memstat_kvm_uma: %s", 1282148630Srwatson kvm_geterr(kd)); 1283148630Srwatson else 1284148630Srwatson warnx("memstat_kvm_uma: %s", 1285148630Srwatson memstat_strerror(error)); 1286148630Srwatson } 1287148413Srwatson } 1288209215Ssbruno printf("%-20s %6s %6s %8s %8s %8s %4s %4s\n\n", "ITEM", "SIZE", 1289209215Ssbruno "LIMIT", "USED", "FREE", "REQ", "FAIL", "SLEEP"); 1290148413Srwatson for (mtp = memstat_mtl_first(mtlp); mtp != NULL; 1291148413Srwatson mtp = memstat_mtl_next(mtp)) { 1292148413Srwatson strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME); 1293148413Srwatson strcat(name, ":"); 1294228654Sdim printf("%-20s %6" PRIu64 ", %6" PRIu64 ",%8" PRIu64 ",%8" PRIu64 1295228654Sdim ",%8" PRIu64 ",%4" PRIu64 ",%4" PRIu64 "\n", name, 1296148413Srwatson memstat_get_size(mtp), memstat_get_countlimit(mtp), 1297148413Srwatson memstat_get_count(mtp), memstat_get_free(mtp), 1298209215Ssbruno memstat_get_numallocs(mtp), memstat_get_failures(mtp), 1299209215Ssbruno memstat_get_sleeps(mtp)); 1300148413Srwatson } 1301148413Srwatson memstat_mtl_free(mtlp); 1302148413Srwatson printf("\n"); 1303148413Srwatson} 1304148413Srwatson 1305148413Srwatson/* 13061590Srgrimes * kread reads something from the kernel, given its nlist index. 13071590Srgrimes */ 1308123250Sdesstatic void 1309131300Sgreenkreado(int nlx, void *addr, size_t size, size_t offset) 13101590Srgrimes{ 1311123825Sdwmalone const char *sym; 13121590Srgrimes 131340690Sjdp if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { 13141590Srgrimes sym = namelist[nlx].n_name; 13151590Srgrimes if (*sym == '_') 13161590Srgrimes ++sym; 131728693Scharnier errx(1, "symbol %s not defined", sym); 13181590Srgrimes } 1319131300Sgreen if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr, 1320131300Sgreen size) != size) { 13211590Srgrimes sym = namelist[nlx].n_name; 13221590Srgrimes if (*sym == '_') 13231590Srgrimes ++sym; 132428693Scharnier errx(1, "%s: %s", sym, kvm_geterr(kd)); 13251590Srgrimes } 13261590Srgrimes} 13271590Srgrimes 1328123250Sdesstatic void 1329131300Sgreenkread(int nlx, void *addr, size_t size) 1330131300Sgreen{ 1331131300Sgreen kreado(nlx, addr, size, 0); 1332131300Sgreen} 1333131300Sgreen 1334131300Sgreenstatic char * 1335131300Sgreenkgetstr(const char *strp) 1336131300Sgreen{ 1337131300Sgreen int n = 0, size = 1; 1338131300Sgreen char *ret = NULL; 1339131300Sgreen 1340131300Sgreen do { 1341131300Sgreen if (size == n + 1) { 1342131300Sgreen ret = realloc(ret, size); 1343131300Sgreen if (ret == NULL) 1344131300Sgreen err(1, "%s: realloc", __func__); 1345131300Sgreen size *= 2; 1346131300Sgreen } 1347131300Sgreen if (kvm_read(kd, (u_long)strp + n, &ret[n], 1) != 1) 1348131300Sgreen errx(1, "%s: %s", __func__, kvm_geterr(kd)); 1349131300Sgreen } while (ret[n++] != '\0'); 1350131300Sgreen return (ret); 1351131300Sgreen} 1352131300Sgreen 1353131300Sgreenstatic void 1354123250Sdesusage(void) 13551590Srgrimes{ 135672887Salfred (void)fprintf(stderr, "%s%s", 1357178063Sru "usage: vmstat [-afHhimPsz] [-c count] [-M core [-N system]] [-w wait]\n", 1358146466Sru " [-n devs] [-p type,if,pass] [disks]\n"); 13591590Srgrimes exit(1); 13601590Srgrimes} 1361