xref: /onnv-gate/usr/src/cmd/stat/vmstat/vmstat.c (revision 10265:b988146c84e5)
10Sstevel@tonic-gate /*
29123Sjohn.levon@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*
70Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
80Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
90Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
100Sstevel@tonic-gate  */
110Sstevel@tonic-gate 
120Sstevel@tonic-gate /* from UCB 5.4 5/17/86 */
130Sstevel@tonic-gate /* from SunOS 4.1, SID 1.31 */
140Sstevel@tonic-gate 
150Sstevel@tonic-gate #include <stdio.h>
160Sstevel@tonic-gate #include <stdlib.h>
170Sstevel@tonic-gate #include <stdarg.h>
180Sstevel@tonic-gate #include <ctype.h>
190Sstevel@tonic-gate #include <unistd.h>
200Sstevel@tonic-gate #include <memory.h>
210Sstevel@tonic-gate #include <string.h>
220Sstevel@tonic-gate #include <fcntl.h>
230Sstevel@tonic-gate #include <errno.h>
240Sstevel@tonic-gate #include <signal.h>
250Sstevel@tonic-gate #include <values.h>
260Sstevel@tonic-gate #include <poll.h>
279123Sjohn.levon@sun.com #include <locale.h>
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "statcommon.h"
300Sstevel@tonic-gate 
315461Stc35445 char *cmdname = "vmstat";
325461Stc35445 int caught_cont = 0;
330Sstevel@tonic-gate 
34*10265SKrishnendu.Sadhukhan@Sun.COM static uint_t timestamp_fmt = NODATE;
359123Sjohn.levon@sun.com 
360Sstevel@tonic-gate static	int	hz;
370Sstevel@tonic-gate static	int	pagesize;
380Sstevel@tonic-gate static	double	etime;
390Sstevel@tonic-gate static	int	lines = 1;
400Sstevel@tonic-gate static	int	swflag = 0, cflag = 0, pflag = 0;
410Sstevel@tonic-gate static	int	suppress_state;
420Sstevel@tonic-gate static	long	iter = 0;
435461Stc35445 static	hrtime_t period_n = 0;
440Sstevel@tonic-gate static  struct	snapshot *ss;
450Sstevel@tonic-gate 
460Sstevel@tonic-gate struct iodev_filter df;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	pgtok(a) ((a) * (pagesize >> 10))
490Sstevel@tonic-gate #define	denom(x) ((x) ? (x) : 1)
500Sstevel@tonic-gate #define	REPRINT	19
510Sstevel@tonic-gate 
520Sstevel@tonic-gate static	void	dovmstats(struct snapshot *old, struct snapshot *new);
530Sstevel@tonic-gate static	void	printhdr(int);
540Sstevel@tonic-gate static	void	dosum(struct sys_snapshot *ss);
550Sstevel@tonic-gate static	void	dointr(struct snapshot *ss);
565461Stc35445 static	void	docachestats(kstat_ctl_t *kc, hrtime_t interval, int forever);
570Sstevel@tonic-gate static	void	usage(void);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate int
600Sstevel@tonic-gate main(int argc, char **argv)
610Sstevel@tonic-gate {
620Sstevel@tonic-gate 	struct snapshot *old = NULL;
630Sstevel@tonic-gate 	enum snapshot_types types = SNAP_SYSTEM;
640Sstevel@tonic-gate 	int summary = 0;
650Sstevel@tonic-gate 	int intr = 0;
660Sstevel@tonic-gate 	kstat_ctl_t *kc;
675461Stc35445 	int forever = 0;
685461Stc35445 	hrtime_t start_n;
699123Sjohn.levon@sun.com 	int c;
709123Sjohn.levon@sun.com 
719123Sjohn.levon@sun.com 	(void) setlocale(LC_ALL, "");
729123Sjohn.levon@sun.com #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
739123Sjohn.levon@sun.com #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it weren't */
749123Sjohn.levon@sun.com #endif
759123Sjohn.levon@sun.com 	(void) textdomain(TEXT_DOMAIN);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	pagesize = sysconf(_SC_PAGESIZE);
780Sstevel@tonic-gate 	hz = sysconf(_SC_CLK_TCK);
790Sstevel@tonic-gate 
809123Sjohn.levon@sun.com 	while ((c = getopt(argc, argv, "cipqsST:")) != EOF)
819123Sjohn.levon@sun.com 		switch (c) {
829123Sjohn.levon@sun.com 		case 'S':
839123Sjohn.levon@sun.com 			swflag = !swflag;
849123Sjohn.levon@sun.com 			break;
859123Sjohn.levon@sun.com 		case 's':
869123Sjohn.levon@sun.com 			summary = 1;
879123Sjohn.levon@sun.com 			break;
889123Sjohn.levon@sun.com 		case 'i':
899123Sjohn.levon@sun.com 			intr = 1;
909123Sjohn.levon@sun.com 			break;
919123Sjohn.levon@sun.com 		case 'c':
929123Sjohn.levon@sun.com 			cflag++;
939123Sjohn.levon@sun.com 			break;
949123Sjohn.levon@sun.com 		case 'q':
959123Sjohn.levon@sun.com 			suppress_state = 1;
969123Sjohn.levon@sun.com 			break;
979123Sjohn.levon@sun.com 		case 'p':
989123Sjohn.levon@sun.com 			pflag++;	/* detailed paging info */
999123Sjohn.levon@sun.com 			break;
1009123Sjohn.levon@sun.com 		case 'T':
1019123Sjohn.levon@sun.com 			if (optarg) {
1029123Sjohn.levon@sun.com 				if (*optarg == 'u')
1039123Sjohn.levon@sun.com 					timestamp_fmt = UDATE;
1049123Sjohn.levon@sun.com 				else if (*optarg == 'd')
1059123Sjohn.levon@sun.com 					timestamp_fmt = DDATE;
1069123Sjohn.levon@sun.com 				else
1079123Sjohn.levon@sun.com 					usage();
1089123Sjohn.levon@sun.com 			} else {
1090Sstevel@tonic-gate 				usage();
1100Sstevel@tonic-gate 			}
1119123Sjohn.levon@sun.com 			break;
1129123Sjohn.levon@sun.com 		default:
1139123Sjohn.levon@sun.com 			usage();
1140Sstevel@tonic-gate 		}
1159123Sjohn.levon@sun.com 
1169123Sjohn.levon@sun.com 	argc -= optind;
1179123Sjohn.levon@sun.com 	argv += optind;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/* consistency with iostat */
1200Sstevel@tonic-gate 	types |= SNAP_CPUS;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (intr)
1230Sstevel@tonic-gate 		types |= SNAP_INTERRUPTS;
1240Sstevel@tonic-gate 	if (cflag)
1250Sstevel@tonic-gate 		types |= SNAP_FLUSHES;
1260Sstevel@tonic-gate 	if (!intr)
1270Sstevel@tonic-gate 		types |= SNAP_IODEVS;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	/* max to fit in less than 80 characters */
1300Sstevel@tonic-gate 	df.if_max_iodevs = 4;
1310Sstevel@tonic-gate 	df.if_allowed_types = IODEV_DISK;
1320Sstevel@tonic-gate 	df.if_nr_names = 0;
1330Sstevel@tonic-gate 	df.if_names = safe_alloc(df.if_max_iodevs * sizeof (char *));
1340Sstevel@tonic-gate 	(void) memset(df.if_names, 0, df.if_max_iodevs * sizeof (char *));
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	while (argc > 0 && !isdigit(argv[0][0]) &&
1379123Sjohn.levon@sun.com 	    df.if_nr_names < df.if_max_iodevs) {
1380Sstevel@tonic-gate 		df.if_names[df.if_nr_names] = *argv;
1390Sstevel@tonic-gate 		df.if_nr_names++;
1400Sstevel@tonic-gate 		argc--, argv++;
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	kc = open_kstat();
1440Sstevel@tonic-gate 
1455461Stc35445 	start_n = gethrtime();
1465461Stc35445 
1470Sstevel@tonic-gate 	ss = acquire_snapshot(kc, types, &df);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/* time, in seconds, since boot */
1500Sstevel@tonic-gate 	etime = ss->s_sys.ss_ticks / hz;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	if (intr) {
1530Sstevel@tonic-gate 		dointr(ss);
1540Sstevel@tonic-gate 		free_snapshot(ss);
1550Sstevel@tonic-gate 		exit(0);
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 	if (summary) {
1580Sstevel@tonic-gate 		dosum(&ss->s_sys);
1590Sstevel@tonic-gate 		free_snapshot(ss);
1600Sstevel@tonic-gate 		exit(0);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if (argc > 0) {
1640Sstevel@tonic-gate 		long interval;
1650Sstevel@tonic-gate 		char *endptr;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 		errno = 0;
1680Sstevel@tonic-gate 		interval = strtol(argv[0], &endptr, 10);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 		if (errno > 0 || *endptr != '\0' || interval <= 0 ||
1710Sstevel@tonic-gate 		    interval > MAXINT)
1720Sstevel@tonic-gate 			usage();
1735461Stc35445 		period_n = (hrtime_t)interval * NANOSEC;
1745461Stc35445 		if (period_n <= 0)
1750Sstevel@tonic-gate 			usage();
1760Sstevel@tonic-gate 		iter = MAXLONG;
1770Sstevel@tonic-gate 		if (argc > 1) {
1780Sstevel@tonic-gate 			iter = strtol(argv[1], NULL, 10);
1790Sstevel@tonic-gate 			if (errno > 0 || *endptr != '\0' || iter <= 0)
1800Sstevel@tonic-gate 				usage();
1815461Stc35445 		} else
1825461Stc35445 			forever = 1;
1830Sstevel@tonic-gate 		if (argc > 2)
1840Sstevel@tonic-gate 			usage();
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	if (cflag) {
1880Sstevel@tonic-gate 		free_snapshot(ss);
1895461Stc35445 		docachestats(kc, period_n, forever);
1900Sstevel@tonic-gate 		exit(0);
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	(void) sigset(SIGCONT, printhdr);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	dovmstats(old, ss);
1965461Stc35445 	while (forever || --iter > 0) {
1975461Stc35445 		/* (void) poll(NULL, 0, poll_interval); */
1985461Stc35445 
1995461Stc35445 		/* Have a kip */
2005461Stc35445 		sleep_until(&start_n, period_n, forever, &caught_cont);
2015461Stc35445 
2020Sstevel@tonic-gate 		free_snapshot(old);
2030Sstevel@tonic-gate 		old = ss;
2040Sstevel@tonic-gate 		ss = acquire_snapshot(kc, types, &df);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		if (!suppress_state)
2070Sstevel@tonic-gate 			snapshot_report_changes(old, ss);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 		/* if config changed, show stats from boot */
2100Sstevel@tonic-gate 		if (snapshot_has_changed(old, ss)) {
2110Sstevel@tonic-gate 			free_snapshot(old);
2120Sstevel@tonic-gate 			old = NULL;
2130Sstevel@tonic-gate 		}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 		dovmstats(old, ss);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	free_snapshot(old);
2190Sstevel@tonic-gate 	free_snapshot(ss);
2200Sstevel@tonic-gate 	free(df.if_names);
2210Sstevel@tonic-gate 	(void) kstat_close(kc);
2220Sstevel@tonic-gate 	return (0);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate #define	DELTA(v) (new->v - (old ? old->v : 0))
2260Sstevel@tonic-gate #define	ADJ(n)	((adj <= 0) ? n : (adj >= n) ? 1 : n - adj)
2270Sstevel@tonic-gate #define	adjprintf(fmt, n, val)	adj -= (n + 1) - printf(fmt, ADJ(n), val)
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate static int adj;	/* number of excess columns */
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*ARGSUSED*/
2320Sstevel@tonic-gate static void
2330Sstevel@tonic-gate show_disk(void *v1, void *v2, void *d)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	struct iodev_snapshot *old = (struct iodev_snapshot *)v1;
2360Sstevel@tonic-gate 	struct iodev_snapshot *new = (struct iodev_snapshot *)v2;
2370Sstevel@tonic-gate 	hrtime_t oldtime = new->is_crtime;
2380Sstevel@tonic-gate 	double hr_etime;
2390Sstevel@tonic-gate 	double reads, writes;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	if (new == NULL)
2420Sstevel@tonic-gate 		return;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (old)
2450Sstevel@tonic-gate 		oldtime = old->is_stats.wlastupdate;
2460Sstevel@tonic-gate 	hr_etime = new->is_stats.wlastupdate - oldtime;
2470Sstevel@tonic-gate 	if (hr_etime == 0.0)
2480Sstevel@tonic-gate 		hr_etime = NANOSEC;
2490Sstevel@tonic-gate 	reads = new->is_stats.reads - (old ? old->is_stats.reads : 0);
2500Sstevel@tonic-gate 	writes = new->is_stats.writes - (old ? old->is_stats.writes : 0);
2510Sstevel@tonic-gate 	adjprintf(" %*.0f", 2, (reads + writes) / hr_etime * NANOSEC);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate static void
2550Sstevel@tonic-gate dovmstats(struct snapshot *old, struct snapshot *new)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate 	kstat_t *oldsys = NULL;
2580Sstevel@tonic-gate 	kstat_t *newsys = &new->s_sys.ss_agg_sys;
2590Sstevel@tonic-gate 	kstat_t *oldvm = NULL;
2600Sstevel@tonic-gate 	kstat_t *newvm = &new->s_sys.ss_agg_vm;
2610Sstevel@tonic-gate 	double percent_factor;
2620Sstevel@tonic-gate 	ulong_t updates;
2630Sstevel@tonic-gate 	int count;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	adj = 0;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	if (old) {
2680Sstevel@tonic-gate 		oldsys = &old->s_sys.ss_agg_sys;
2690Sstevel@tonic-gate 		oldvm = &old->s_sys.ss_agg_vm;
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	etime = cpu_ticks_delta(oldsys, newsys);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	percent_factor = 100.0 / denom(etime);
2750Sstevel@tonic-gate 	/*
2760Sstevel@tonic-gate 	 * If any time has passed, convert etime to seconds per CPU
2770Sstevel@tonic-gate 	 */
2780Sstevel@tonic-gate 	etime = etime >= 1.0 ? (etime / nr_active_cpus(new)) / hz : 1.0;
2790Sstevel@tonic-gate 	updates = denom(DELTA(s_sys.ss_sysinfo.updates));
2800Sstevel@tonic-gate 
2819123Sjohn.levon@sun.com 	if (timestamp_fmt != NODATE) {
282*10265SKrishnendu.Sadhukhan@Sun.COM 		print_timestamp(timestamp_fmt);
2839123Sjohn.levon@sun.com 		lines--;
2849123Sjohn.levon@sun.com 	}
2859123Sjohn.levon@sun.com 
2869123Sjohn.levon@sun.com 	if (--lines <= 0)
2870Sstevel@tonic-gate 		printhdr(0);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	adj = 0;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	if (pflag) {
2920Sstevel@tonic-gate 		adjprintf(" %*u", 6,
2930Sstevel@tonic-gate 		    pgtok((int)(DELTA(s_sys.ss_vminfo.swap_avail) / updates)));
2940Sstevel@tonic-gate 		adjprintf(" %*u", 5,
2950Sstevel@tonic-gate 		    pgtok((int)(DELTA(s_sys.ss_vminfo.freemem) / updates)));
2960Sstevel@tonic-gate 		adjprintf(" %*.0f", 3, kstat_delta(oldvm, newvm, "pgrec")
2970Sstevel@tonic-gate 		    / etime);
2980Sstevel@tonic-gate 		adjprintf(" %*.0f", 3, (kstat_delta(oldvm, newvm, "hat_fault") +
2990Sstevel@tonic-gate 		    kstat_delta(oldvm, newvm, "as_fault")) / etime);
3000Sstevel@tonic-gate 		adjprintf(" %*.0f", 3, pgtok(kstat_delta(oldvm, newvm, "dfree"))
3010Sstevel@tonic-gate 		    / etime);
3020Sstevel@tonic-gate 		adjprintf(" %*ld", 3, pgtok(new->s_sys.ss_deficit));
3030Sstevel@tonic-gate 		adjprintf(" %*.0f", 3, kstat_delta(oldvm, newvm, "scan")
3040Sstevel@tonic-gate 		    / etime);
3050Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3060Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "execpgin")) / etime);
3070Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3080Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "execpgout")) / etime);
3090Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3100Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "execfree")) / etime);
3110Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3120Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "anonpgin")) / etime);
3130Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3140Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "anonpgout")) / etime);
3150Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3160Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "anonfree")) / etime);
3170Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3180Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "fspgin")) / etime);
3190Sstevel@tonic-gate 		adjprintf(" %*.0f", 4,
3200Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "fspgout")) / etime);
3210Sstevel@tonic-gate 		adjprintf(" %*.0f\n", 4,
3220Sstevel@tonic-gate 		    pgtok(kstat_delta(oldvm, newvm, "fsfree")) / etime);
3230Sstevel@tonic-gate 		(void) fflush(stdout);
3240Sstevel@tonic-gate 		return;
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.runque) / updates);
3280Sstevel@tonic-gate 	adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.waiting) / updates);
3290Sstevel@tonic-gate 	adjprintf(" %*lu", 1, DELTA(s_sys.ss_sysinfo.swpque) / updates);
3300Sstevel@tonic-gate 	adjprintf(" %*u", 6, pgtok((int)(DELTA(s_sys.ss_vminfo.swap_avail)
3310Sstevel@tonic-gate 	    / updates)));
3320Sstevel@tonic-gate 	adjprintf(" %*u", 5, pgtok((int)(DELTA(s_sys.ss_vminfo.freemem)
3339123Sjohn.levon@sun.com 	    / updates)));
3340Sstevel@tonic-gate 	adjprintf(" %*.0f", 3, swflag?
3350Sstevel@tonic-gate 	    kstat_delta(oldvm, newvm, "swapin") / etime :
3360Sstevel@tonic-gate 	    kstat_delta(oldvm, newvm, "pgrec") / etime);
3370Sstevel@tonic-gate 	adjprintf(" %*.0f", 3, swflag?
3380Sstevel@tonic-gate 	    kstat_delta(oldvm, newvm, "swapout") / etime :
3390Sstevel@tonic-gate 	    (kstat_delta(oldvm, newvm, "hat_fault")
3400Sstevel@tonic-gate 	    + kstat_delta(oldvm, newvm, "as_fault"))
3410Sstevel@tonic-gate 	    / etime);
3420Sstevel@tonic-gate 	adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "pgpgin"))
3430Sstevel@tonic-gate 	    / etime);
3440Sstevel@tonic-gate 	adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "pgpgout"))
3450Sstevel@tonic-gate 	    / etime);
3460Sstevel@tonic-gate 	adjprintf(" %*.0f", 2, pgtok(kstat_delta(oldvm, newvm, "dfree"))
3470Sstevel@tonic-gate 	    / etime);
3480Sstevel@tonic-gate 	adjprintf(" %*ld", 2, pgtok(new->s_sys.ss_deficit));
3490Sstevel@tonic-gate 	adjprintf(" %*.0f", 2, kstat_delta(oldvm, newvm, "scan") / etime);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	(void) snapshot_walk(SNAP_IODEVS, old, new, show_disk, NULL);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	count = df.if_max_iodevs - new->s_nr_iodevs;
3540Sstevel@tonic-gate 	while (count-- > 0)
3550Sstevel@tonic-gate 		adjprintf(" %*d", 2, 0);
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "intr") / etime);
3580Sstevel@tonic-gate 	adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "syscall") / etime);
3590Sstevel@tonic-gate 	adjprintf(" %*.0f", 4, kstat_delta(oldsys, newsys, "pswitch") / etime);
3600Sstevel@tonic-gate 	adjprintf(" %*.0f", 2,
3610Sstevel@tonic-gate 	    kstat_delta(oldsys, newsys, "cpu_ticks_user") * percent_factor);
3620Sstevel@tonic-gate 	adjprintf(" %*.0f", 2, kstat_delta(oldsys, newsys, "cpu_ticks_kernel")
3630Sstevel@tonic-gate 	    * percent_factor);
3640Sstevel@tonic-gate 	adjprintf(" %*.0f\n", 2, (kstat_delta(oldsys, newsys, "cpu_ticks_idle")
3650Sstevel@tonic-gate 	    + kstat_delta(oldsys, newsys, "cpu_ticks_wait"))
3660Sstevel@tonic-gate 	    * percent_factor);
3670Sstevel@tonic-gate 	(void) fflush(stdout);
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate /*ARGSUSED*/
3710Sstevel@tonic-gate static void
3720Sstevel@tonic-gate print_disk(void *v, void *v2, void *d)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate 	struct iodev_snapshot *iodev = (struct iodev_snapshot *)v2;
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	if (iodev == NULL)
3770Sstevel@tonic-gate 		return;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	(void) printf("%c%c ", iodev->is_name[0], iodev->is_name[2]);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate /* ARGSUSED */
3830Sstevel@tonic-gate static void
3840Sstevel@tonic-gate printhdr(int sig)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	int i = df.if_max_iodevs - ss->s_nr_iodevs;
3870Sstevel@tonic-gate 
3885461Stc35445 	if (sig == SIGCONT)
3895461Stc35445 		caught_cont = 1;
3905461Stc35445 
3910Sstevel@tonic-gate 	if (pflag) {
3920Sstevel@tonic-gate 		(void) printf("     memory           page          ");
3930Sstevel@tonic-gate 		(void) printf("executable      anonymous      filesystem \n");
3940Sstevel@tonic-gate 		(void) printf("   swap  free  re  mf  fr  de  sr  ");
3950Sstevel@tonic-gate 		(void) printf("epi  epo  epf  api  apo  apf  fpi  fpo  fpf\n");
3960Sstevel@tonic-gate 		lines = REPRINT;
3970Sstevel@tonic-gate 		return;
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	(void) printf(" kthr      memory            page            ");
4010Sstevel@tonic-gate 	(void) printf("disk          faults      cpu\n");
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if (swflag)
4040Sstevel@tonic-gate 		(void) printf(" r b w   swap  free  si  so pi po fr de sr ");
4050Sstevel@tonic-gate 	else
4060Sstevel@tonic-gate 		(void) printf(" r b w   swap  free  re  mf pi po fr de sr ");
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	(void) snapshot_walk(SNAP_IODEVS, NULL, ss, print_disk, NULL);
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	while (i-- > 0)
4110Sstevel@tonic-gate 		(void) printf("-- ");
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	(void) printf("  in   sy   cs us sy id\n");
4140Sstevel@tonic-gate 	lines = REPRINT;
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate static void
4180Sstevel@tonic-gate sum_out(char const *pretty, kstat_t *ks, char *name)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate 	kstat_named_t *ksn = kstat_data_lookup(ks, name);
4210Sstevel@tonic-gate 	if (ksn == NULL) {
4220Sstevel@tonic-gate 		fail(0, "kstat_data_lookup('%s', '%s') failed",
4239123Sjohn.levon@sun.com 		    ks->ks_name, name);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	(void) printf("%9llu %s\n", ksn->value.ui64, pretty);
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate static void
4300Sstevel@tonic-gate dosum(struct sys_snapshot *ss)
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate 	uint64_t total_faults;
4330Sstevel@tonic-gate 	kstat_named_t *ksn;
4340Sstevel@tonic-gate 	long double nchtotal;
4350Sstevel@tonic-gate 	uint64_t nchhits;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	sum_out("swap ins", &ss->ss_agg_vm, "swapin");
4380Sstevel@tonic-gate 	sum_out("swap outs", &ss->ss_agg_vm, "swapout");
4390Sstevel@tonic-gate 	sum_out("pages swapped in", &ss->ss_agg_vm, "pgswapin");
4400Sstevel@tonic-gate 	sum_out("pages swapped out", &ss->ss_agg_vm, "pgswapout");
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	ksn = kstat_data_lookup(&ss->ss_agg_vm, "hat_fault");
4430Sstevel@tonic-gate 	if (ksn == NULL) {
4440Sstevel@tonic-gate 		fail(0, "kstat_data_lookup('%s', 'hat_fault') failed",
4459123Sjohn.levon@sun.com 		    ss->ss_agg_vm.ks_name);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 	total_faults = ksn->value.ui64;
4480Sstevel@tonic-gate 	ksn = kstat_data_lookup(&ss->ss_agg_vm, "as_fault");
4490Sstevel@tonic-gate 	if (ksn == NULL) {
4500Sstevel@tonic-gate 		fail(0, "kstat_data_lookup('%s', 'as_fault') failed",
4519123Sjohn.levon@sun.com 		    ss->ss_agg_vm.ks_name);
4520Sstevel@tonic-gate 	}
4530Sstevel@tonic-gate 	total_faults += ksn->value.ui64;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	(void) printf("%9llu total address trans. faults taken\n",
4569123Sjohn.levon@sun.com 	    total_faults);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	sum_out("page ins", &ss->ss_agg_vm, "pgin");
4590Sstevel@tonic-gate 	sum_out("page outs", &ss->ss_agg_vm, "pgout");
4600Sstevel@tonic-gate 	sum_out("pages paged in", &ss->ss_agg_vm, "pgpgin");
4610Sstevel@tonic-gate 	sum_out("pages paged out", &ss->ss_agg_vm, "pgpgout");
4620Sstevel@tonic-gate 	sum_out("total reclaims", &ss->ss_agg_vm, "pgrec");
4630Sstevel@tonic-gate 	sum_out("reclaims from free list", &ss->ss_agg_vm, "pgfrec");
4640Sstevel@tonic-gate 	sum_out("micro (hat) faults", &ss->ss_agg_vm, "hat_fault");
4650Sstevel@tonic-gate 	sum_out("minor (as) faults", &ss->ss_agg_vm, "as_fault");
4660Sstevel@tonic-gate 	sum_out("major faults", &ss->ss_agg_vm, "maj_fault");
4670Sstevel@tonic-gate 	sum_out("copy-on-write faults", &ss->ss_agg_vm, "cow_fault");
4680Sstevel@tonic-gate 	sum_out("zero fill page faults", &ss->ss_agg_vm, "zfod");
4690Sstevel@tonic-gate 	sum_out("pages examined by the clock daemon", &ss->ss_agg_vm, "scan");
4700Sstevel@tonic-gate 	sum_out("revolutions of the clock hand", &ss->ss_agg_vm, "rev");
4710Sstevel@tonic-gate 	sum_out("pages freed by the clock daemon", &ss->ss_agg_vm, "dfree");
4720Sstevel@tonic-gate 	sum_out("forks", &ss->ss_agg_sys, "sysfork");
4730Sstevel@tonic-gate 	sum_out("vforks", &ss->ss_agg_sys, "sysvfork");
4740Sstevel@tonic-gate 	sum_out("execs", &ss->ss_agg_sys, "sysexec");
4750Sstevel@tonic-gate 	sum_out("cpu context switches", &ss->ss_agg_sys, "pswitch");
4760Sstevel@tonic-gate 	sum_out("device interrupts", &ss->ss_agg_sys, "intr");
4770Sstevel@tonic-gate 	sum_out("traps", &ss->ss_agg_sys, "trap");
4780Sstevel@tonic-gate 	sum_out("system calls", &ss->ss_agg_sys, "syscall");
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	nchtotal = (long double) ss->ss_nc.ncs_hits.value.ui64 +
4810Sstevel@tonic-gate 	    (long double) ss->ss_nc.ncs_misses.value.ui64;
4820Sstevel@tonic-gate 	nchhits = ss->ss_nc.ncs_hits.value.ui64;
4830Sstevel@tonic-gate 	(void) printf("%9.0Lf total name lookups (cache hits %.0Lf%%)\n",
4840Sstevel@tonic-gate 	    nchtotal, nchhits / denom(nchtotal) * 100);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	sum_out("user   cpu", &ss->ss_agg_sys, "cpu_ticks_user");
4870Sstevel@tonic-gate 	sum_out("system cpu", &ss->ss_agg_sys, "cpu_ticks_kernel");
4880Sstevel@tonic-gate 	sum_out("idle   cpu", &ss->ss_agg_sys, "cpu_ticks_idle");
4890Sstevel@tonic-gate 	sum_out("wait   cpu", &ss->ss_agg_sys, "cpu_ticks_wait");
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate static void
4930Sstevel@tonic-gate dointr(struct snapshot *ss)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate 	size_t i;
4960Sstevel@tonic-gate 	ulong_t total = 0;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	(void) printf("interrupt         total     rate\n");
4990Sstevel@tonic-gate 	(void) printf("--------------------------------\n");
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	for (i = 0; i < ss->s_nr_intrs; i++) {
5020Sstevel@tonic-gate 		(void) printf("%-12.8s %10lu %8.0f\n",
5039123Sjohn.levon@sun.com 		    ss->s_intrs[i].is_name, ss->s_intrs[i].is_total,
5049123Sjohn.levon@sun.com 		    ss->s_intrs[i].is_total / etime);
5050Sstevel@tonic-gate 		total += ss->s_intrs[i].is_total;
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	(void) printf("--------------------------------\n");
5090Sstevel@tonic-gate 	(void) printf("Total        %10lu %8.0f\n", total, total / etime);
5100Sstevel@tonic-gate }
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate static void
5135461Stc35445 docachestats(kstat_ctl_t *kc, hrtime_t interval, int forever)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	struct snapshot *old;
5160Sstevel@tonic-gate 	struct snapshot *new;
5170Sstevel@tonic-gate 	int i;
5185461Stc35445 	hrtime_t start;
5190Sstevel@tonic-gate 
5205461Stc35445 	start = gethrtime();
5210Sstevel@tonic-gate 	old = acquire_snapshot(kc, SNAP_FLUSHES, NULL);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (iter == 0) {
5240Sstevel@tonic-gate 		(void) printf("flush statistics: (totals)\n");
5250Sstevel@tonic-gate 		(void) printf("%8s%8s%8s%8s%8s%8s\n",
5269123Sjohn.levon@sun.com 		    "usr", "ctx", "rgn", "seg", "pag", "par");
5270Sstevel@tonic-gate 		(void) printf(" %7d %7d %7d %7d %7d %7d\n",
5289123Sjohn.levon@sun.com 		    old->s_flushes.f_usr, old->s_flushes.f_ctx,
5299123Sjohn.levon@sun.com 		    old->s_flushes.f_region, old->s_flushes.f_segment,
5309123Sjohn.levon@sun.com 		    old->s_flushes.f_page, old->s_flushes.f_partial);
5310Sstevel@tonic-gate 		return;
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	(void) printf("flush statistics: (interval based)\n");
5350Sstevel@tonic-gate 	for (i = 0; i < iter; i++) {
5360Sstevel@tonic-gate 		if (i % REPRINT == 0)
5370Sstevel@tonic-gate 			(void) printf("%8s%8s%8s%8s%8s%8s\n",
5380Sstevel@tonic-gate 			    "usr", "ctx", "rgn", "seg", "pag", "par");
5390Sstevel@tonic-gate 
5405461Stc35445 		/* Have a kip */
5415461Stc35445 		sleep_until(&start, interval, forever, &caught_cont);
5425461Stc35445 
5430Sstevel@tonic-gate 		new = acquire_snapshot(kc, SNAP_FLUSHES, NULL);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 		(void) printf(" %7d %7d %7d %7d %7d %7d\n",
5469123Sjohn.levon@sun.com 		    new->s_flushes.f_usr - old->s_flushes.f_usr,
5479123Sjohn.levon@sun.com 		    new->s_flushes.f_ctx - old->s_flushes.f_ctx,
5489123Sjohn.levon@sun.com 		    new->s_flushes.f_region - old->s_flushes.f_region,
5499123Sjohn.levon@sun.com 		    new->s_flushes.f_segment - old->s_flushes.f_segment,
5509123Sjohn.levon@sun.com 		    new->s_flushes.f_page - old->s_flushes.f_page,
5519123Sjohn.levon@sun.com 		    new->s_flushes.f_partial- old->s_flushes.f_partial);
5520Sstevel@tonic-gate 		(void) fflush(stdout);
5530Sstevel@tonic-gate 		free_snapshot(old);
5540Sstevel@tonic-gate 		old = new;
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate static void
5590Sstevel@tonic-gate usage(void)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate 	(void) fprintf(stderr,
5629123Sjohn.levon@sun.com 	    "Usage: vmstat [-cipqsS] [-T d|u] [disk ...] "
5639123Sjohn.levon@sun.com 	    "[interval [count]]\n");
5640Sstevel@tonic-gate 	exit(1);
5650Sstevel@tonic-gate }
566