xref: /illumos-gate/usr/src/cmd/sa/sar.c (revision b9b602f4ba30beaa44f307d5c80e638c486a39ad)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b2d230ebSjc  * Common Development and Distribution License (the "License").
6b2d230ebSjc  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*b9b602f4Sjs  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * sar generates a report either from an input data file or by invoking sadc to
347c478bd9Sstevel@tonic-gate  * read system activity counters at the specified intervals.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * usage:  sar [-ubdycwaqvmpgrkA] [-o file] t [n]
377c478bd9Sstevel@tonic-gate  *	   sar [-ubdycwaqvmpgrkA][-s hh:mm][-e hh:mm][-i ss][-f file]
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
437c478bd9Sstevel@tonic-gate #include <sys/time.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
467c478bd9Sstevel@tonic-gate #include <sys/wait.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include <ctype.h>
497c478bd9Sstevel@tonic-gate #include <errno.h>
507c478bd9Sstevel@tonic-gate #include <fcntl.h>
517c478bd9Sstevel@tonic-gate #include <limits.h>
527c478bd9Sstevel@tonic-gate #include <signal.h>
537c478bd9Sstevel@tonic-gate #include <stdarg.h>
547c478bd9Sstevel@tonic-gate #include <stdio.h>
557c478bd9Sstevel@tonic-gate #include <stdlib.h>
567c478bd9Sstevel@tonic-gate #include <string.h>
577c478bd9Sstevel@tonic-gate #include <time.h>
587c478bd9Sstevel@tonic-gate #include <unistd.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #include "sa.h"
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #define	PGTOBLK(x)	((x) * (pagesize >> 9))
637c478bd9Sstevel@tonic-gate #define	BLKTOPG(x)	((x) / (pagesize >> 9))
647c478bd9Sstevel@tonic-gate #define	BLKS(x)		((x) >> 9)
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static void	prpass(int);
677c478bd9Sstevel@tonic-gate static void	prtopt(void);
687c478bd9Sstevel@tonic-gate static void	prtavg(void);
697c478bd9Sstevel@tonic-gate static void	prttim(void);
707c478bd9Sstevel@tonic-gate static void	prtmachid(void);
717c478bd9Sstevel@tonic-gate static void	prthdg(void);
727c478bd9Sstevel@tonic-gate static void	tsttab(void);
737c478bd9Sstevel@tonic-gate static void	update_counters(void);
747c478bd9Sstevel@tonic-gate static void	usage(void);
757c478bd9Sstevel@tonic-gate static void	fail(int, char *, ...);
767c478bd9Sstevel@tonic-gate static void	safe_zalloc(void **, int, int);
777c478bd9Sstevel@tonic-gate static int	safe_read(int, void *, size_t);
787c478bd9Sstevel@tonic-gate static void	safe_write(int, void *, size_t);
797c478bd9Sstevel@tonic-gate static int	safe_strtoi(char const *, char *);
80*b9b602f4Sjs static void	ulong_delta(uint64_t *, uint64_t *, uint64_t *, uint64_t *,
817c478bd9Sstevel@tonic-gate 	int, int);
827c478bd9Sstevel@tonic-gate static float	denom(float);
837c478bd9Sstevel@tonic-gate static float	freq(float, float);
847c478bd9Sstevel@tonic-gate 
85*b9b602f4Sjs static struct sa64	nx, ox, ax, dx;
867c478bd9Sstevel@tonic-gate static iodevinfo_t	*nxio, *oxio, *axio, *dxio;
877c478bd9Sstevel@tonic-gate static struct tm	*curt, args, arge;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static int	sflg, eflg, iflg, oflg, fflg;
907c478bd9Sstevel@tonic-gate static int	realtime, passno = 0, do_disk;
917c478bd9Sstevel@tonic-gate static int	t = 0, n = 0, lines = 0;
927c478bd9Sstevel@tonic-gate static int	hz;
937c478bd9Sstevel@tonic-gate static int	niodevs;
947c478bd9Sstevel@tonic-gate static int	tabflg;
957c478bd9Sstevel@tonic-gate static char	options[30], fopt[30];
967c478bd9Sstevel@tonic-gate static float	tdiff, sec_diff, totsec_diff = 0.0, percent;
977c478bd9Sstevel@tonic-gate static float	start_time, end_time, isec;
987c478bd9Sstevel@tonic-gate static int 	fin, fout;
997c478bd9Sstevel@tonic-gate static pid_t	childid;
1007c478bd9Sstevel@tonic-gate static int	pipedes[2];
1017c478bd9Sstevel@tonic-gate static char	arg1[10], arg2[10];
1027c478bd9Sstevel@tonic-gate static int	pagesize;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * To avoid overflow in the kmem allocation data, declare a copy of the
1067c478bd9Sstevel@tonic-gate  * main kmeminfo_t type with larger data types. Use this for storing
1077c478bd9Sstevel@tonic-gate  * the data held to display average values
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static struct kmeminfo_l
1107c478bd9Sstevel@tonic-gate {
1117c478bd9Sstevel@tonic-gate 	u_longlong_t	km_mem[KMEM_NCLASS];
1127c478bd9Sstevel@tonic-gate 	u_longlong_t	km_alloc[KMEM_NCLASS];
1137c478bd9Sstevel@tonic-gate 	u_longlong_t	km_fail[KMEM_NCLASS];
1147c478bd9Sstevel@tonic-gate } kmi;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate int
1177c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	char    flnm[PATH_MAX], ofile[PATH_MAX];
1207c478bd9Sstevel@tonic-gate 	char	ccc;
1217c478bd9Sstevel@tonic-gate 	time_t	temp;
1227c478bd9Sstevel@tonic-gate 	int	i, jj = 0;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	pagesize = sysconf(_SC_PAGESIZE);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/*
1277c478bd9Sstevel@tonic-gate 	 * Process options with arguments and pack options
1287c478bd9Sstevel@tonic-gate 	 * without arguments.
1297c478bd9Sstevel@tonic-gate 	 */
1307c478bd9Sstevel@tonic-gate 	while ((i = getopt(argc, argv, "ubdycwaqvmpgrkAo:s:e:i:f:")) != EOF)
1317c478bd9Sstevel@tonic-gate 		switch (ccc = (char)i) {
1327c478bd9Sstevel@tonic-gate 		    case 'o':
1337c478bd9Sstevel@tonic-gate 			oflg++;
1347c478bd9Sstevel@tonic-gate 			if (strlcpy(ofile, optarg, sizeof (ofile)) >=
1357c478bd9Sstevel@tonic-gate 			    sizeof (ofile)) {
1367c478bd9Sstevel@tonic-gate 				fail(2, "-o filename is too long: %s", optarg);
1377c478bd9Sstevel@tonic-gate 			}
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 		    case 's':
1407c478bd9Sstevel@tonic-gate 			if (sscanf(optarg, "%d:%d:%d",
1417c478bd9Sstevel@tonic-gate 			    &args.tm_hour, &args.tm_min, &args.tm_sec) < 1)
1427c478bd9Sstevel@tonic-gate 				fail(0, "-%c %s -- illegal option argument",
1437c478bd9Sstevel@tonic-gate 				    ccc, optarg);
1447c478bd9Sstevel@tonic-gate 			else {
1457c478bd9Sstevel@tonic-gate 				sflg++,
1467c478bd9Sstevel@tonic-gate 				start_time = args.tm_hour*3600.0 +
1477c478bd9Sstevel@tonic-gate 				    args.tm_min*60.0 +
1487c478bd9Sstevel@tonic-gate 				    args.tm_sec;
1497c478bd9Sstevel@tonic-gate 			}
1507c478bd9Sstevel@tonic-gate 			break;
1517c478bd9Sstevel@tonic-gate 		    case 'e':
1527c478bd9Sstevel@tonic-gate 			if (sscanf(optarg, "%d:%d:%d",
1537c478bd9Sstevel@tonic-gate 			    &arge.tm_hour, &arge.tm_min, &arge.tm_sec) < 1)
1547c478bd9Sstevel@tonic-gate 				fail(0, "-%c %s -- illegal option argument",
1557c478bd9Sstevel@tonic-gate 				    ccc, optarg);
1567c478bd9Sstevel@tonic-gate 			else {
1577c478bd9Sstevel@tonic-gate 				eflg++;
1587c478bd9Sstevel@tonic-gate 				end_time = arge.tm_hour*3600.0 +
1597c478bd9Sstevel@tonic-gate 				    arge.tm_min*60.0 +
1607c478bd9Sstevel@tonic-gate 				    arge.tm_sec;
1617c478bd9Sstevel@tonic-gate 			}
1627c478bd9Sstevel@tonic-gate 			break;
1637c478bd9Sstevel@tonic-gate 		    case 'i':
1647c478bd9Sstevel@tonic-gate 			if (sscanf(optarg, "%f", &isec) < 1)
1657c478bd9Sstevel@tonic-gate 				fail(0, "-%c %s -- illegal option argument",
1667c478bd9Sstevel@tonic-gate 				    ccc, optarg);
1677c478bd9Sstevel@tonic-gate 			else {
1687c478bd9Sstevel@tonic-gate 				if (isec > 0.0)
1697c478bd9Sstevel@tonic-gate 					iflg++;
1707c478bd9Sstevel@tonic-gate 			}
1717c478bd9Sstevel@tonic-gate 			break;
1727c478bd9Sstevel@tonic-gate 		    case 'f':
1737c478bd9Sstevel@tonic-gate 			fflg++;
1747c478bd9Sstevel@tonic-gate 			if (strlcpy(flnm, optarg, sizeof (flnm)) >=
1757c478bd9Sstevel@tonic-gate 			    sizeof (ofile)) {
1767c478bd9Sstevel@tonic-gate 				fail(2, "-f filename is too long: %s", optarg);
1777c478bd9Sstevel@tonic-gate 			}
1787c478bd9Sstevel@tonic-gate 			break;
1797c478bd9Sstevel@tonic-gate 		    case '?':
1807c478bd9Sstevel@tonic-gate 			usage();
1817c478bd9Sstevel@tonic-gate 			exit(1);
1827c478bd9Sstevel@tonic-gate 			break;
1837c478bd9Sstevel@tonic-gate 		default:
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 			/*
1867c478bd9Sstevel@tonic-gate 			 * Check for repeated options. To make sure
1877c478bd9Sstevel@tonic-gate 			 * that options[30] does not overflow.
1887c478bd9Sstevel@tonic-gate 			 */
1897c478bd9Sstevel@tonic-gate 			if (strchr(options, ccc) == NULL)
1907c478bd9Sstevel@tonic-gate 				(void) strncat(options, &ccc, 1);
1917c478bd9Sstevel@tonic-gate 			break;
1927c478bd9Sstevel@tonic-gate 		}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/*
1957c478bd9Sstevel@tonic-gate 	 * Are starting and ending times consistent?
1967c478bd9Sstevel@tonic-gate 	 */
1977c478bd9Sstevel@tonic-gate 	if ((sflg) && (eflg) && (end_time <= start_time))
1987c478bd9Sstevel@tonic-gate 		fail(0, "ending time <= starting time");
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/*
2017c478bd9Sstevel@tonic-gate 	 * Determine if t and n arguments are given, and whether to run in real
2027c478bd9Sstevel@tonic-gate 	 * time or from a file.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	switch (argc - optind) {
2057c478bd9Sstevel@tonic-gate 	    case 0:		/*   Get input data from file   */
2067c478bd9Sstevel@tonic-gate 		if (fflg == 0) {
2077c478bd9Sstevel@tonic-gate 			temp = time(NULL);
2087c478bd9Sstevel@tonic-gate 			curt = localtime(&temp);
2097c478bd9Sstevel@tonic-gate 			(void) snprintf(flnm, PATH_MAX, "/var/adm/sa/sa%.2d",
2107c478bd9Sstevel@tonic-gate 			    curt->tm_mday);
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 		if ((fin = open(flnm, 0)) == -1)
2137c478bd9Sstevel@tonic-gate 			fail(1, "can't open %s", flnm);
2147c478bd9Sstevel@tonic-gate 		break;
2157c478bd9Sstevel@tonic-gate 	    case 1:		/*   Real time data; one cycle   */
2167c478bd9Sstevel@tonic-gate 		realtime++;
2177c478bd9Sstevel@tonic-gate 		t = safe_strtoi(argv[optind], "invalid sampling interval");
2187c478bd9Sstevel@tonic-gate 		n = 2;
2197c478bd9Sstevel@tonic-gate 		break;
2207c478bd9Sstevel@tonic-gate 	    case 2:		/*   Real time data; specified cycles   */
2217c478bd9Sstevel@tonic-gate 	default:
2227c478bd9Sstevel@tonic-gate 		realtime++;
2237c478bd9Sstevel@tonic-gate 		t = safe_strtoi(argv[optind], "invalid sampling interval");
2247c478bd9Sstevel@tonic-gate 		n = 1 + safe_strtoi(argv[optind+1], "invalid sample count");
2257c478bd9Sstevel@tonic-gate 		break;
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/*
2297c478bd9Sstevel@tonic-gate 	 * "u" is the default option, which displays CPU utilization.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 	if (strlen(options) == 0)
2327c478bd9Sstevel@tonic-gate 		(void) strcpy(options, "u");
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	/*
2357c478bd9Sstevel@tonic-gate 	 * "A" means all data options.
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	if (strchr(options, 'A') != NULL)
2387c478bd9Sstevel@tonic-gate 		(void) strcpy(options, "udqbwcayvmpgrk");
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (realtime) {
2417c478bd9Sstevel@tonic-gate 		/*
2427c478bd9Sstevel@tonic-gate 		 * Get input data from sadc via pipe.
2437c478bd9Sstevel@tonic-gate 		 */
2447c478bd9Sstevel@tonic-gate 		if (t <= 0)
2457c478bd9Sstevel@tonic-gate 			fail(0, "sampling interval t <= 0 sec");
2467c478bd9Sstevel@tonic-gate 		if (n < 2)
2477c478bd9Sstevel@tonic-gate 			fail(0, "number of sample intervals n <= 0");
2487c478bd9Sstevel@tonic-gate 		(void) sprintf(arg1, "%d", t);
2497c478bd9Sstevel@tonic-gate 		(void) sprintf(arg2, "%d", n);
2507c478bd9Sstevel@tonic-gate 		if (pipe(pipedes) == -1)
2517c478bd9Sstevel@tonic-gate 			fail(1, "pipe failed");
2527c478bd9Sstevel@tonic-gate 		if ((childid = fork()) == 0) {
2537c478bd9Sstevel@tonic-gate 			/*
2547c478bd9Sstevel@tonic-gate 			 * Child:  shift pipedes[write] to stdout,
2557c478bd9Sstevel@tonic-gate 			 * and close the pipe entries.
2567c478bd9Sstevel@tonic-gate 			 */
2577c478bd9Sstevel@tonic-gate 			(void) dup2(pipedes[1], 1);
2587c478bd9Sstevel@tonic-gate 			if (pipedes[0] != 1)
2597c478bd9Sstevel@tonic-gate 				(void) close(pipedes[0]);
2607c478bd9Sstevel@tonic-gate 			if (pipedes[1] != 1)
2617c478bd9Sstevel@tonic-gate 				(void) close(pipedes[1]);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 			if (execlp("/usr/lib/sa/sadc",
2647c478bd9Sstevel@tonic-gate 			    "/usr/lib/sa/sadc", arg1, arg2, 0) == -1)
2657c478bd9Sstevel@tonic-gate 				fail(1, "exec of /usr/lib/sa/sadc failed");
2667c478bd9Sstevel@tonic-gate 		} else if (childid == -1) {
2677c478bd9Sstevel@tonic-gate 			fail(1, "Could not fork to exec sadc");
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 		/*
2707c478bd9Sstevel@tonic-gate 		 * Parent:  close unused output.
2717c478bd9Sstevel@tonic-gate 		 */
2727c478bd9Sstevel@tonic-gate 		fin = pipedes[0];
2737c478bd9Sstevel@tonic-gate 		(void) close(pipedes[1]);
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if (oflg) {
2777c478bd9Sstevel@tonic-gate 		if (strcmp(ofile, flnm) == 0)
2787c478bd9Sstevel@tonic-gate 			fail(0, "output file name same as input file name");
2797c478bd9Sstevel@tonic-gate 		fout = creat(ofile, 00644);
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	hz = sysconf(_SC_CLK_TCK);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	nxio = oxio = dxio = axio = NULL;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	if (realtime) {
2877c478bd9Sstevel@tonic-gate 		/*
2887c478bd9Sstevel@tonic-gate 		 * Make single pass, processing all options.
2897c478bd9Sstevel@tonic-gate 		 */
2907c478bd9Sstevel@tonic-gate 		(void) strcpy(fopt, options);
2917c478bd9Sstevel@tonic-gate 		passno++;
2927c478bd9Sstevel@tonic-gate 		prpass(realtime);
2937c478bd9Sstevel@tonic-gate 		(void) kill(childid, SIGINT);
2947c478bd9Sstevel@tonic-gate 		(void) wait(NULL);
2957c478bd9Sstevel@tonic-gate 	} else {
2967c478bd9Sstevel@tonic-gate 		/*
2977c478bd9Sstevel@tonic-gate 		 * Make multiple passes, one for each option.
2987c478bd9Sstevel@tonic-gate 		 */
2997c478bd9Sstevel@tonic-gate 		while (strlen(strncpy(fopt, &options[jj++], 1))) {
3007c478bd9Sstevel@tonic-gate 			if (lseek(fin, 0, SEEK_SET) == (off_t)-1)
3017c478bd9Sstevel@tonic-gate 				fail(0, "lseek failed");
3027c478bd9Sstevel@tonic-gate 			passno++;
3037c478bd9Sstevel@tonic-gate 			prpass(realtime);
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	return (0);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
310*b9b602f4Sjs /*
311*b9b602f4Sjs  * Convert array of 32-bit uints to 64-bit uints
312*b9b602f4Sjs  */
313*b9b602f4Sjs static void
314*b9b602f4Sjs convert_32to64(uint64_t *dst, uint_t *src, int size)
315*b9b602f4Sjs {
316*b9b602f4Sjs 	for (; size > 0; size--)
317*b9b602f4Sjs 		*dst++ = (uint64_t)(*src++);
318*b9b602f4Sjs }
319*b9b602f4Sjs 
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate  * Read records from input, classify, and decide on printing.
3227c478bd9Sstevel@tonic-gate  */
3237c478bd9Sstevel@tonic-gate static void
3247c478bd9Sstevel@tonic-gate prpass(int input_pipe)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	size_t size;
3277c478bd9Sstevel@tonic-gate 	int i, j, state_change, recno = 0;
3287c478bd9Sstevel@tonic-gate 	kid_t kid;
3297c478bd9Sstevel@tonic-gate 	float trec, tnext = 0;
3307c478bd9Sstevel@tonic-gate 	ulong_t old_niodevs = 0, prev_niodevs = 0;
3317c478bd9Sstevel@tonic-gate 	iodevinfo_t *aio, *dio, *oio;
3327c478bd9Sstevel@tonic-gate 	struct stat in_stat;
333*b9b602f4Sjs 	struct sa tx;
334*b9b602f4Sjs 	uint64_t ts, te; /* time interval start and end */
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	do_disk = (strchr(fopt, 'd') != NULL);
3377c478bd9Sstevel@tonic-gate 	if (!input_pipe && fstat(fin, &in_stat) == -1)
3387c478bd9Sstevel@tonic-gate 		fail(1, "unable to stat data file");
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (sflg)
3417c478bd9Sstevel@tonic-gate 		tnext = start_time;
3427c478bd9Sstevel@tonic-gate 
343*b9b602f4Sjs 	while (safe_read(fin, &tx, sizeof (struct sa))) {
344*b9b602f4Sjs 		/*
345*b9b602f4Sjs 		 * First, we convert 32bit tx to 64bit nx structure
346*b9b602f4Sjs 		 * which is used later. Conversion could be done
347*b9b602f4Sjs 		 * after initial operations, right before calculations,
348*b9b602f4Sjs 		 * but it would introduce additional juggling with vars.
349*b9b602f4Sjs 		 * Thus, we convert all data now, and don't care about
350*b9b602f4Sjs 		 * tx any further.
351*b9b602f4Sjs 		 */
352*b9b602f4Sjs 		nx.valid = tx.valid;
353*b9b602f4Sjs 		nx.ts = tx.ts;
354*b9b602f4Sjs 		convert_32to64((uint64_t *)&nx.csi, (uint_t *)&tx.csi,
355*b9b602f4Sjs 		    sizeof (tx.csi) / sizeof (uint_t));
356*b9b602f4Sjs 		convert_32to64((uint64_t *)&nx.cvmi, (uint_t *)&tx.cvmi,
357*b9b602f4Sjs 		    sizeof (tx.cvmi) / sizeof (uint_t));
358*b9b602f4Sjs 		convert_32to64((uint64_t *)&nx.si, (uint_t *)&tx.si,
359*b9b602f4Sjs 		    sizeof (tx.si) / sizeof (uint_t));
360*b9b602f4Sjs 		(void) memcpy(&nx.vmi, &tx.vmi,
361*b9b602f4Sjs 		    sizeof (tx) - (((char *)&tx.vmi) - ((char *)&tx)));
3627c478bd9Sstevel@tonic-gate 		/*
3637c478bd9Sstevel@tonic-gate 		 * sadc is the only utility used to generate sar data
3647c478bd9Sstevel@tonic-gate 		 * and it uses the valid field as follows:
3657c478bd9Sstevel@tonic-gate 		 * 0 - dummy record
3667c478bd9Sstevel@tonic-gate 		 * 1 - data record
3677c478bd9Sstevel@tonic-gate 		 * We can use this fact to improve sar's ability to detect
3687c478bd9Sstevel@tonic-gate 		 * bad data, since any value apart from 0 or 1 can be
3697c478bd9Sstevel@tonic-gate 		 * interpreted as invalid data.
3707c478bd9Sstevel@tonic-gate 		 */
3717c478bd9Sstevel@tonic-gate 		if (nx.valid != 0 && nx.valid != 1)
3727c478bd9Sstevel@tonic-gate 			fail(2, "data file not in sar format");
3737c478bd9Sstevel@tonic-gate 		state_change = 0;
3747c478bd9Sstevel@tonic-gate 		niodevs = nx.niodevs;
3757c478bd9Sstevel@tonic-gate 		/*
3767c478bd9Sstevel@tonic-gate 		 * niodevs has the value of current number of devices
3777c478bd9Sstevel@tonic-gate 		 * from nx structure.
3787c478bd9Sstevel@tonic-gate 		 *
3797c478bd9Sstevel@tonic-gate 		 * The following 'if' condition is to decide whether memory
3807c478bd9Sstevel@tonic-gate 		 * has to be allocated or not if already allocated memory is
3817c478bd9Sstevel@tonic-gate 		 * bigger or smaller than memory needed to store the current
3827c478bd9Sstevel@tonic-gate 		 * niodevs details in memory.
3837c478bd9Sstevel@tonic-gate 		 *
3847c478bd9Sstevel@tonic-gate 		 * when first while loop starts, pre_niodevs has 0 and then
3857c478bd9Sstevel@tonic-gate 		 * always get initialized to the current number of devices
3867c478bd9Sstevel@tonic-gate 		 * from nx.niodevs if it is different from previously read
3877c478bd9Sstevel@tonic-gate 		 * niodevs.
3887c478bd9Sstevel@tonic-gate 		 *
3897c478bd9Sstevel@tonic-gate 		 * if the current niodevs has the same value of previously
3907c478bd9Sstevel@tonic-gate 		 * allocated memory i.e, for prev_niodevs, it skips the
3917c478bd9Sstevel@tonic-gate 		 * following  'if' loop or otherwise it allocates memory for
3927c478bd9Sstevel@tonic-gate 		 * current devises (niodevs) and stores that value in
3937c478bd9Sstevel@tonic-gate 		 * prev_niodevs for next time when loop continues to read
3947c478bd9Sstevel@tonic-gate 		 * from the file.
3957c478bd9Sstevel@tonic-gate 		 */
3967c478bd9Sstevel@tonic-gate 		if (niodevs != prev_niodevs) {
3977c478bd9Sstevel@tonic-gate 			off_t curr_pos;
3987c478bd9Sstevel@tonic-gate 			/*
3997c478bd9Sstevel@tonic-gate 			 * The required buffer size must fit in a size_t.
4007c478bd9Sstevel@tonic-gate 			 */
4017c478bd9Sstevel@tonic-gate 			if (SIZE_MAX / sizeof (iodevinfo_t) < niodevs)
4027c478bd9Sstevel@tonic-gate 				fail(2, "insufficient address space to hold "
4037c478bd9Sstevel@tonic-gate 				    "%lu device records", niodevs);
4047c478bd9Sstevel@tonic-gate 			size = niodevs * sizeof (iodevinfo_t);
4057c478bd9Sstevel@tonic-gate 			prev_niodevs = niodevs;
4067c478bd9Sstevel@tonic-gate 			/*
4077c478bd9Sstevel@tonic-gate 			 * The data file must exceed this size to be valid.
4087c478bd9Sstevel@tonic-gate 			 */
4097c478bd9Sstevel@tonic-gate 			if (!input_pipe) {
4107c478bd9Sstevel@tonic-gate 			    if ((curr_pos = lseek(fin, 0, SEEK_CUR)) ==
4117c478bd9Sstevel@tonic-gate 				(off_t)-1)
4127c478bd9Sstevel@tonic-gate 				    fail(1, "lseek failed");
4137c478bd9Sstevel@tonic-gate 			    if (in_stat.st_size < curr_pos ||
4147c478bd9Sstevel@tonic-gate 				size > in_stat.st_size - curr_pos)
4157c478bd9Sstevel@tonic-gate 				    fail(2, "data file corrupt; specified size"
4167c478bd9Sstevel@tonic-gate 					"exceeds actual");
4177c478bd9Sstevel@tonic-gate 			}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 			safe_zalloc((void **)&nxio, size, 1);
4207c478bd9Sstevel@tonic-gate 		}
4217c478bd9Sstevel@tonic-gate 		if (niodevs != old_niodevs)
4227c478bd9Sstevel@tonic-gate 			state_change = 1;
4237c478bd9Sstevel@tonic-gate 		for (i = 0; i < niodevs; i++) {
4247c478bd9Sstevel@tonic-gate 			if (safe_read(fin, &nxio[i], sizeof (iodevinfo_t)) == 0)
4257c478bd9Sstevel@tonic-gate 				fail(1, "premature end-of-file seen");
4267c478bd9Sstevel@tonic-gate 			if (i < old_niodevs &&
4277c478bd9Sstevel@tonic-gate 			    nxio[i].ks.ks_kid != oxio[i].ks.ks_kid)
4287c478bd9Sstevel@tonic-gate 				state_change = 1;
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		curt = localtime(&nx.ts);
4317c478bd9Sstevel@tonic-gate 		trec = curt->tm_hour * 3600.0 +
4327c478bd9Sstevel@tonic-gate 		    curt->tm_min * 60.0 +
4337c478bd9Sstevel@tonic-gate 		    curt->tm_sec;
4347c478bd9Sstevel@tonic-gate 		if ((recno == 0) && (trec < start_time))
4357c478bd9Sstevel@tonic-gate 			continue;
4367c478bd9Sstevel@tonic-gate 		if ((eflg) && (trec > end_time))
4377c478bd9Sstevel@tonic-gate 			break;
4387c478bd9Sstevel@tonic-gate 		if ((oflg) && (passno == 1)) {
4397c478bd9Sstevel@tonic-gate 			safe_write(fout, &nx, sizeof (struct sa));
4407c478bd9Sstevel@tonic-gate 			for (i = 0; i < niodevs; i++)
4417c478bd9Sstevel@tonic-gate 				safe_write(fout, &nxio[i],
4427c478bd9Sstevel@tonic-gate 				    sizeof (iodevinfo_t));
4437c478bd9Sstevel@tonic-gate 		}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		if (recno == 0) {
4467c478bd9Sstevel@tonic-gate 			if (passno == 1)
4477c478bd9Sstevel@tonic-gate 				prtmachid();
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 			prthdg();
4507c478bd9Sstevel@tonic-gate 			recno = 1;
4517c478bd9Sstevel@tonic-gate 			if ((iflg) && (tnext == 0))
4527c478bd9Sstevel@tonic-gate 				tnext = trec;
4537c478bd9Sstevel@tonic-gate 		}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 		if (nx.valid == 0) {
4567c478bd9Sstevel@tonic-gate 			/*
4577c478bd9Sstevel@tonic-gate 			 * This dummy record signifies system restart
4587c478bd9Sstevel@tonic-gate 			 * New initial values of counters follow in next
4597c478bd9Sstevel@tonic-gate 			 * record.
4607c478bd9Sstevel@tonic-gate 			 */
4617c478bd9Sstevel@tonic-gate 			if (!realtime) {
4627c478bd9Sstevel@tonic-gate 				prttim();
4637c478bd9Sstevel@tonic-gate 				(void) printf("\tunix restarts\n");
4647c478bd9Sstevel@tonic-gate 				recno = 1;
4657c478bd9Sstevel@tonic-gate 				continue;
4667c478bd9Sstevel@tonic-gate 			}
4677c478bd9Sstevel@tonic-gate 		}
4687c478bd9Sstevel@tonic-gate 		if ((iflg) && (trec < tnext))
4697c478bd9Sstevel@tonic-gate 			continue;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		if (state_change) {
4727c478bd9Sstevel@tonic-gate 			/*
4737c478bd9Sstevel@tonic-gate 			 * Either the number of devices or the ordering of
4747c478bd9Sstevel@tonic-gate 			 * the kstats has changed.  We need to re-organise
4757c478bd9Sstevel@tonic-gate 			 * the layout of our avg/delta arrays so that we
4767c478bd9Sstevel@tonic-gate 			 * can cope with this in update_counters().
4777c478bd9Sstevel@tonic-gate 			 */
4787c478bd9Sstevel@tonic-gate 			size = niodevs * sizeof (iodevinfo_t);
4797c478bd9Sstevel@tonic-gate 			safe_zalloc((void *)&aio, size, 0);
4807c478bd9Sstevel@tonic-gate 			safe_zalloc((void *)&dio, size, 0);
4817c478bd9Sstevel@tonic-gate 			safe_zalloc((void *)&oio, size, 0);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 			/*
4847c478bd9Sstevel@tonic-gate 			 * Loop through all the newly read iodev's, locate
4857c478bd9Sstevel@tonic-gate 			 * the corresponding entry in the old arrays and
4867c478bd9Sstevel@tonic-gate 			 * copy the entries into the same bucket of the
4877c478bd9Sstevel@tonic-gate 			 * new arrays.
4887c478bd9Sstevel@tonic-gate 			 */
4897c478bd9Sstevel@tonic-gate 			for (i = 0; i < niodevs; i++) {
4907c478bd9Sstevel@tonic-gate 				kid = nxio[i].ks.ks_kid;
4917c478bd9Sstevel@tonic-gate 				for (j = 0; j < old_niodevs; j++) {
4927c478bd9Sstevel@tonic-gate 					if (oxio[j].ks.ks_kid == kid) {
4937c478bd9Sstevel@tonic-gate 						oio[i] = oxio[j];
4947c478bd9Sstevel@tonic-gate 						aio[i] = axio[j];
4957c478bd9Sstevel@tonic-gate 						dio[i] = dxio[j];
4967c478bd9Sstevel@tonic-gate 					}
4977c478bd9Sstevel@tonic-gate 				}
4987c478bd9Sstevel@tonic-gate 			}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 			free(axio);
5017c478bd9Sstevel@tonic-gate 			free(oxio);
5027c478bd9Sstevel@tonic-gate 			free(dxio);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 			axio = aio;
5057c478bd9Sstevel@tonic-gate 			oxio = oio;
5067c478bd9Sstevel@tonic-gate 			dxio = dio;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 			old_niodevs = niodevs;
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		if (recno++ > 1) {
5127c478bd9Sstevel@tonic-gate 			ts = ox.csi.cpu[0] + ox.csi.cpu[1] +
5137c478bd9Sstevel@tonic-gate 				ox.csi.cpu[2] + ox.csi.cpu[3];
5147c478bd9Sstevel@tonic-gate 			te = nx.csi.cpu[0] + nx.csi.cpu[1] +
5157c478bd9Sstevel@tonic-gate 				nx.csi.cpu[2] + nx.csi.cpu[3];
5167c478bd9Sstevel@tonic-gate 			tdiff = (float)(te - ts);
5177c478bd9Sstevel@tonic-gate 			sec_diff = tdiff / hz;
5187c478bd9Sstevel@tonic-gate 			percent = 100.0 / tdiff;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 			/*
5217c478bd9Sstevel@tonic-gate 			 * If the CPU stat counters have rolled
5227c478bd9Sstevel@tonic-gate 			 * backward, this is our best indication that
5237c478bd9Sstevel@tonic-gate 			 * a CPU has been offlined.  We don't have
5247c478bd9Sstevel@tonic-gate 			 * enough data to compute a sensible delta, so
5257c478bd9Sstevel@tonic-gate 			 * toss out this interval, but compute the next
5267c478bd9Sstevel@tonic-gate 			 * interval's delta from these values.
5277c478bd9Sstevel@tonic-gate 			 */
5287c478bd9Sstevel@tonic-gate 			if (tdiff <= 0) {
5297c478bd9Sstevel@tonic-gate 				ox = nx;
5307c478bd9Sstevel@tonic-gate 				continue;
5317c478bd9Sstevel@tonic-gate 			}
5327c478bd9Sstevel@tonic-gate 			update_counters();
5337c478bd9Sstevel@tonic-gate 			prtopt();
5347c478bd9Sstevel@tonic-gate 			lines++;
5357c478bd9Sstevel@tonic-gate 			if (passno == 1)
5367c478bd9Sstevel@tonic-gate 				totsec_diff += sec_diff;
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 		ox = nx;		/*  Age the data	*/
5397c478bd9Sstevel@tonic-gate 		(void) memcpy(oxio, nxio, niodevs * sizeof (iodevinfo_t));
5407c478bd9Sstevel@tonic-gate 		if (isec > 0)
5417c478bd9Sstevel@tonic-gate 			while (tnext <= trec)
5427c478bd9Sstevel@tonic-gate 				tnext += isec;
5437c478bd9Sstevel@tonic-gate 	}
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * After this place, all functions are using niodevs to access the
5467c478bd9Sstevel@tonic-gate 	 * memory for device details. Here, old_niodevs has the correct value
5477c478bd9Sstevel@tonic-gate 	 * of memory allocated for storing device information. Since niodevs
5487c478bd9Sstevel@tonic-gate 	 * doesn't have correct value, sometimes, it was corrupting memory.
5497c478bd9Sstevel@tonic-gate 	 */
5507c478bd9Sstevel@tonic-gate 	niodevs = old_niodevs;
5517c478bd9Sstevel@tonic-gate 	if (lines > 1)
5527c478bd9Sstevel@tonic-gate 		prtavg();
5537c478bd9Sstevel@tonic-gate 	(void) memset(&ax, 0, sizeof (ax));	/* Zero out the accumulators. */
5547c478bd9Sstevel@tonic-gate 	(void) memset(&kmi, 0, sizeof (kmi));
5557c478bd9Sstevel@tonic-gate 	lines = 0;
5567c478bd9Sstevel@tonic-gate 	/*
5577c478bd9Sstevel@tonic-gate 	 * axio will not be allocated if the user specified -e or -s, and
5587c478bd9Sstevel@tonic-gate 	 * no records in the file fell inside the specified time range.
5597c478bd9Sstevel@tonic-gate 	 */
5607c478bd9Sstevel@tonic-gate 	if (axio) {
5617c478bd9Sstevel@tonic-gate 		(void) memset(axio, 0, niodevs * sizeof (iodevinfo_t));
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate  * Print time label routine.
5677c478bd9Sstevel@tonic-gate  */
5687c478bd9Sstevel@tonic-gate static void
5697c478bd9Sstevel@tonic-gate prttim(void)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	curt = localtime(&nx.ts);
5727c478bd9Sstevel@tonic-gate 	(void) printf("%.2d:%.2d:%.2d", curt->tm_hour, curt->tm_min,
5737c478bd9Sstevel@tonic-gate 	    curt->tm_sec);
5747c478bd9Sstevel@tonic-gate 	tabflg = 1;
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * Test if 8-spaces to be added routine.
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate static void
5817c478bd9Sstevel@tonic-gate tsttab(void)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	if (tabflg == 0)
5847c478bd9Sstevel@tonic-gate 		(void) printf("        ");
5857c478bd9Sstevel@tonic-gate 	else
5867c478bd9Sstevel@tonic-gate 		tabflg = 0;
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate /*
5907c478bd9Sstevel@tonic-gate  * Print machine identification.
5917c478bd9Sstevel@tonic-gate  */
5927c478bd9Sstevel@tonic-gate static void
5937c478bd9Sstevel@tonic-gate prtmachid(void)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	struct utsname name;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	(void) uname(&name);
5987c478bd9Sstevel@tonic-gate 	(void) printf("\n%s %s %s %s %s    %.2d/%.2d/%.4d\n",
5997c478bd9Sstevel@tonic-gate 	    name.sysname, name.nodename, name.release, name.version,
6007c478bd9Sstevel@tonic-gate 	    name.machine, curt->tm_mon + 1, curt->tm_mday,
6017c478bd9Sstevel@tonic-gate 	    curt->tm_year + 1900);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate  * Print report heading routine.
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate static void
6087c478bd9Sstevel@tonic-gate prthdg(void)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	int	jj = 0;
6117c478bd9Sstevel@tonic-gate 	char	ccc;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	(void) printf("\n");
6147c478bd9Sstevel@tonic-gate 	prttim();
6157c478bd9Sstevel@tonic-gate 	while ((ccc = fopt[jj++]) != NULL) {
6167c478bd9Sstevel@tonic-gate 		tsttab();
6177c478bd9Sstevel@tonic-gate 		switch (ccc) {
6187c478bd9Sstevel@tonic-gate 		    case 'u':
6197c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s\n",
6207c478bd9Sstevel@tonic-gate 				"%usr",
6217c478bd9Sstevel@tonic-gate 				"%sys",
6227c478bd9Sstevel@tonic-gate 				"%wio",
6237c478bd9Sstevel@tonic-gate 				"%idle");
6247c478bd9Sstevel@tonic-gate 			break;
6257c478bd9Sstevel@tonic-gate 		    case 'b':
6267c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s %7s %7s\n",
6277c478bd9Sstevel@tonic-gate 				"bread/s",
6287c478bd9Sstevel@tonic-gate 				"lread/s",
6297c478bd9Sstevel@tonic-gate 				"%rcache",
6307c478bd9Sstevel@tonic-gate 				"bwrit/s",
6317c478bd9Sstevel@tonic-gate 				"lwrit/s",
6327c478bd9Sstevel@tonic-gate 				"%wcache",
6337c478bd9Sstevel@tonic-gate 				"pread/s",
6347c478bd9Sstevel@tonic-gate 				"pwrit/s");
6357c478bd9Sstevel@tonic-gate 			break;
6367c478bd9Sstevel@tonic-gate 		    case 'd':
6377c478bd9Sstevel@tonic-gate 			(void) printf("   %-8.8s    %7s %7s %7s %7s %7s %7s\n",
6387c478bd9Sstevel@tonic-gate 				"device",
6397c478bd9Sstevel@tonic-gate 				"%busy",
6407c478bd9Sstevel@tonic-gate 				"avque",
6417c478bd9Sstevel@tonic-gate 				"r+w/s",
6427c478bd9Sstevel@tonic-gate 				"blks/s",
6437c478bd9Sstevel@tonic-gate 				"avwait",
6447c478bd9Sstevel@tonic-gate 				"avserv");
6457c478bd9Sstevel@tonic-gate 			break;
6467c478bd9Sstevel@tonic-gate 		    case 'y':
6477c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s\n",
6487c478bd9Sstevel@tonic-gate 				"rawch/s",
6497c478bd9Sstevel@tonic-gate 				"canch/s",
6507c478bd9Sstevel@tonic-gate 				"outch/s",
6517c478bd9Sstevel@tonic-gate 				"rcvin/s",
6527c478bd9Sstevel@tonic-gate 				"xmtin/s",
6537c478bd9Sstevel@tonic-gate 				"mdmin/s");
6547c478bd9Sstevel@tonic-gate 			break;
6557c478bd9Sstevel@tonic-gate 		    case 'c':
6567c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s %7s\n",
6577c478bd9Sstevel@tonic-gate 				"scall/s",
6587c478bd9Sstevel@tonic-gate 				"sread/s",
6597c478bd9Sstevel@tonic-gate 				"swrit/s",
6607c478bd9Sstevel@tonic-gate 				"fork/s",
6617c478bd9Sstevel@tonic-gate 				"exec/s",
6627c478bd9Sstevel@tonic-gate 				"rchar/s",
6637c478bd9Sstevel@tonic-gate 				"wchar/s");
6647c478bd9Sstevel@tonic-gate 			break;
6657c478bd9Sstevel@tonic-gate 		    case 'w':
6667c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s\n",
6677c478bd9Sstevel@tonic-gate 				"swpin/s",
6687c478bd9Sstevel@tonic-gate 				"bswin/s",
6697c478bd9Sstevel@tonic-gate 				"swpot/s",
6707c478bd9Sstevel@tonic-gate 				"bswot/s",
6717c478bd9Sstevel@tonic-gate 				"pswch/s");
6727c478bd9Sstevel@tonic-gate 			break;
6737c478bd9Sstevel@tonic-gate 		    case 'a':
6747c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s\n",
6757c478bd9Sstevel@tonic-gate 				"iget/s",
6767c478bd9Sstevel@tonic-gate 				"namei/s",
6777c478bd9Sstevel@tonic-gate 				"dirbk/s");
6787c478bd9Sstevel@tonic-gate 			break;
6797c478bd9Sstevel@tonic-gate 		    case 'q':
6807c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s\n",
6817c478bd9Sstevel@tonic-gate 				"runq-sz",
6827c478bd9Sstevel@tonic-gate 				"%runocc",
6837c478bd9Sstevel@tonic-gate 				"swpq-sz",
6847c478bd9Sstevel@tonic-gate 				"%swpocc");
6857c478bd9Sstevel@tonic-gate 			break;
6867c478bd9Sstevel@tonic-gate 		    case 'v':
6877c478bd9Sstevel@tonic-gate 			(void) printf("  %s  %s  %s   %s\n",
6887c478bd9Sstevel@tonic-gate 				"proc-sz    ov",
6897c478bd9Sstevel@tonic-gate 				"inod-sz    ov",
6907c478bd9Sstevel@tonic-gate 				"file-sz    ov",
6917c478bd9Sstevel@tonic-gate 				"lock-sz");
6927c478bd9Sstevel@tonic-gate 			break;
6937c478bd9Sstevel@tonic-gate 		    case 'm':
6947c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s\n",
6957c478bd9Sstevel@tonic-gate 				"msg/s",
6967c478bd9Sstevel@tonic-gate 				"sema/s");
6977c478bd9Sstevel@tonic-gate 			break;
6987c478bd9Sstevel@tonic-gate 		    case 'p':
6997c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s\n",
7007c478bd9Sstevel@tonic-gate 				"atch/s",
7017c478bd9Sstevel@tonic-gate 				"pgin/s",
7027c478bd9Sstevel@tonic-gate 				"ppgin/s",
7037c478bd9Sstevel@tonic-gate 				"pflt/s",
7047c478bd9Sstevel@tonic-gate 				"vflt/s",
7057c478bd9Sstevel@tonic-gate 				"slock/s");
7067c478bd9Sstevel@tonic-gate 			break;
7077c478bd9Sstevel@tonic-gate 		    case 'g':
7087c478bd9Sstevel@tonic-gate 			(void) printf(" %8s %8s %8s %8s %8s\n",
7097c478bd9Sstevel@tonic-gate 				"pgout/s",
7107c478bd9Sstevel@tonic-gate 				"ppgout/s",
7117c478bd9Sstevel@tonic-gate 				"pgfree/s",
7127c478bd9Sstevel@tonic-gate 				"pgscan/s",
7137c478bd9Sstevel@tonic-gate 				"%ufs_ipf");
7147c478bd9Sstevel@tonic-gate 			break;
7157c478bd9Sstevel@tonic-gate 		    case 'r':
7167c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %8s\n",
7177c478bd9Sstevel@tonic-gate 				"freemem",
7187c478bd9Sstevel@tonic-gate 				"freeswap");
7197c478bd9Sstevel@tonic-gate 			break;
7207c478bd9Sstevel@tonic-gate 		    case 'k':
7217c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %5s %7s %7s %5s %11s %5s\n",
7227c478bd9Sstevel@tonic-gate 				"sml_mem",
7237c478bd9Sstevel@tonic-gate 				"alloc",
7247c478bd9Sstevel@tonic-gate 				"fail",
7257c478bd9Sstevel@tonic-gate 				"lg_mem",
7267c478bd9Sstevel@tonic-gate 				"alloc",
7277c478bd9Sstevel@tonic-gate 				"fail",
7287c478bd9Sstevel@tonic-gate 				"ovsz_alloc",
7297c478bd9Sstevel@tonic-gate 				"fail");
7307c478bd9Sstevel@tonic-gate 			break;
7317c478bd9Sstevel@tonic-gate 		}
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 	if (jj > 2 || do_disk)
7347c478bd9Sstevel@tonic-gate 		(void) printf("\n");
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate /*
7387c478bd9Sstevel@tonic-gate  * compute deltas and update accumulators
7397c478bd9Sstevel@tonic-gate  */
7407c478bd9Sstevel@tonic-gate static void
7417c478bd9Sstevel@tonic-gate update_counters(void)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	int i;
7447c478bd9Sstevel@tonic-gate 	iodevinfo_t *nio, *oio, *aio, *dio;
7457c478bd9Sstevel@tonic-gate 
746*b9b602f4Sjs 	ulong_delta((uint64_t *)&nx.csi, (uint64_t *)&ox.csi,
747*b9b602f4Sjs 		(uint64_t *)&dx.csi, (uint64_t *)&ax.csi, 0, sizeof (ax.csi));
748*b9b602f4Sjs 	ulong_delta((uint64_t *)&nx.si, (uint64_t *)&ox.si,
749*b9b602f4Sjs 		(uint64_t *)&dx.si, (uint64_t *)&ax.si, 0, sizeof (ax.si));
750*b9b602f4Sjs 	ulong_delta((uint64_t *)&nx.cvmi, (uint64_t *)&ox.cvmi,
751*b9b602f4Sjs 		(uint64_t *)&dx.cvmi, (uint64_t *)&ax.cvmi, 0,
7527c478bd9Sstevel@tonic-gate 		sizeof (ax.cvmi));
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	ax.vmi.freemem += dx.vmi.freemem = nx.vmi.freemem - ox.vmi.freemem;
7557c478bd9Sstevel@tonic-gate 	ax.vmi.swap_avail += dx.vmi.swap_avail =
7567c478bd9Sstevel@tonic-gate 		nx.vmi.swap_avail - ox.vmi.swap_avail;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	nio = nxio;
7597c478bd9Sstevel@tonic-gate 	oio = oxio;
7607c478bd9Sstevel@tonic-gate 	aio = axio;
7617c478bd9Sstevel@tonic-gate 	dio = dxio;
7627c478bd9Sstevel@tonic-gate 	for (i = 0; i < niodevs; i++) {
7637c478bd9Sstevel@tonic-gate 		aio->kios.wlastupdate += dio->kios.wlastupdate
7647c478bd9Sstevel@tonic-gate 			= nio->kios.wlastupdate - oio->kios.wlastupdate;
7657c478bd9Sstevel@tonic-gate 		aio->kios.reads += dio->kios.reads
7667c478bd9Sstevel@tonic-gate 			= nio->kios.reads - oio->kios.reads;
7677c478bd9Sstevel@tonic-gate 		aio->kios.writes += dio->kios.writes
7687c478bd9Sstevel@tonic-gate 			= nio->kios.writes - oio->kios.writes;
7697c478bd9Sstevel@tonic-gate 		aio->kios.nread += dio->kios.nread
7707c478bd9Sstevel@tonic-gate 			= nio->kios.nread - oio->kios.nread;
7717c478bd9Sstevel@tonic-gate 		aio->kios.nwritten += dio->kios.nwritten
7727c478bd9Sstevel@tonic-gate 			= nio->kios.nwritten - oio->kios.nwritten;
7737c478bd9Sstevel@tonic-gate 		aio->kios.wlentime += dio->kios.wlentime
7747c478bd9Sstevel@tonic-gate 			= nio->kios.wlentime - oio->kios.wlentime;
7757c478bd9Sstevel@tonic-gate 		aio->kios.rlentime += dio->kios.rlentime
7767c478bd9Sstevel@tonic-gate 			= nio->kios.rlentime - oio->kios.rlentime;
7777c478bd9Sstevel@tonic-gate 		aio->kios.wtime += dio->kios.wtime
7787c478bd9Sstevel@tonic-gate 			= nio->kios.wtime - oio->kios.wtime;
7797c478bd9Sstevel@tonic-gate 		aio->kios.rtime += dio->kios.rtime
7807c478bd9Sstevel@tonic-gate 			= nio->kios.rtime - oio->kios.rtime;
7817c478bd9Sstevel@tonic-gate 		nio++;
7827c478bd9Sstevel@tonic-gate 		oio++;
7837c478bd9Sstevel@tonic-gate 		aio++;
7847c478bd9Sstevel@tonic-gate 		dio++;
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate static void
789*b9b602f4Sjs prt_u_opt(struct sa64 *xx)
7907c478bd9Sstevel@tonic-gate {
7917c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.0f\n",
7927c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[1] * percent,
7937c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[2] * percent,
7947c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[3] * percent,
7957c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[0] * percent);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate static void
799*b9b602f4Sjs prt_b_opt(struct sa64 *xx)
8007c478bd9Sstevel@tonic-gate {
8017c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n",
8027c478bd9Sstevel@tonic-gate 		(float)xx->csi.bread / sec_diff,
8037c478bd9Sstevel@tonic-gate 		(float)xx->csi.lread / sec_diff,
8047c478bd9Sstevel@tonic-gate 		freq((float)xx->csi.lread, (float)xx->csi.bread),
8057c478bd9Sstevel@tonic-gate 		(float)xx->csi.bwrite / sec_diff,
8067c478bd9Sstevel@tonic-gate 		(float)xx->csi.lwrite / sec_diff,
8077c478bd9Sstevel@tonic-gate 		freq((float)xx->csi.lwrite, (float)xx->csi.bwrite),
8087c478bd9Sstevel@tonic-gate 		(float)xx->csi.phread / sec_diff,
8097c478bd9Sstevel@tonic-gate 		(float)xx->csi.phwrite / sec_diff);
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate static void
8137c478bd9Sstevel@tonic-gate prt_d_opt(int ii, iodevinfo_t *xio)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate 	double etime, hr_etime, tps, avq, avs;
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	tsttab();
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	hr_etime = (double)xio[ii].kios.wlastupdate;
8207c478bd9Sstevel@tonic-gate 	if (hr_etime == 0.0)
8217c478bd9Sstevel@tonic-gate 		hr_etime = (double)NANOSEC;
8227c478bd9Sstevel@tonic-gate 	etime = hr_etime / (double)NANOSEC;
8237c478bd9Sstevel@tonic-gate 	tps = (double)(xio[ii].kios.reads + xio[ii].kios.writes) / etime;
8247c478bd9Sstevel@tonic-gate 	avq = (double)xio[ii].kios.wlentime / hr_etime;
8257c478bd9Sstevel@tonic-gate 	avs = (double)xio[ii].kios.rlentime / hr_etime;
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	(void) printf("   %-8.8s    ", nxio[ii].ks.ks_name);
8287c478bd9Sstevel@tonic-gate 	(void) printf("%7.0f %7.1f %7.0f %7.0f %7.1f %7.1f\n",
8297c478bd9Sstevel@tonic-gate 		(double)xio[ii].kios.rtime * 100.0 / hr_etime,
8307c478bd9Sstevel@tonic-gate 		avq + avs,
8317c478bd9Sstevel@tonic-gate 		tps,
8327c478bd9Sstevel@tonic-gate 		BLKS(xio[ii].kios.nread + xio[ii].kios.nwritten) / etime,
8337c478bd9Sstevel@tonic-gate 		(tps > 0 ? avq / tps * 1000.0 : 0.0),
8347c478bd9Sstevel@tonic-gate 		(tps > 0 ? avs / tps * 1000.0 : 0.0));
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate static void
838*b9b602f4Sjs prt_y_opt(struct sa64 *xx)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n",
8417c478bd9Sstevel@tonic-gate 		(float)xx->csi.rawch / sec_diff,
8427c478bd9Sstevel@tonic-gate 		(float)xx->csi.canch / sec_diff,
8437c478bd9Sstevel@tonic-gate 		(float)xx->csi.outch / sec_diff,
8447c478bd9Sstevel@tonic-gate 		(float)xx->csi.rcvint / sec_diff,
8457c478bd9Sstevel@tonic-gate 		(float)xx->csi.xmtint / sec_diff,
8467c478bd9Sstevel@tonic-gate 		(float)xx->csi.mdmint / sec_diff);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate static void
850*b9b602f4Sjs prt_c_opt(struct sa64 *xx)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.2f %7.2f %7.0f %7.0f\n",
8537c478bd9Sstevel@tonic-gate 		(float)xx->csi.syscall / sec_diff,
8547c478bd9Sstevel@tonic-gate 		(float)xx->csi.sysread / sec_diff,
8557c478bd9Sstevel@tonic-gate 		(float)xx->csi.syswrite / sec_diff,
8567c478bd9Sstevel@tonic-gate 		(float)(xx->csi.sysfork + xx->csi.sysvfork) / sec_diff,
8577c478bd9Sstevel@tonic-gate 		(float)xx->csi.sysexec / sec_diff,
8587c478bd9Sstevel@tonic-gate 		(float)xx->csi.readch / sec_diff,
8597c478bd9Sstevel@tonic-gate 		(float)xx->csi.writech / sec_diff);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate static void
863*b9b602f4Sjs prt_w_opt(struct sa64 *xx)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate 	(void) printf(" %7.2f %7.1f %7.2f %7.1f %7.0f\n",
8667c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.swapin / sec_diff,
8677c478bd9Sstevel@tonic-gate 		(float)PGTOBLK(xx->cvmi.pgswapin) / sec_diff,
8687c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.swapout / sec_diff,
8697c478bd9Sstevel@tonic-gate 		(float)PGTOBLK(xx->cvmi.pgswapout) / sec_diff,
8707c478bd9Sstevel@tonic-gate 		(float)xx->csi.pswitch / sec_diff);
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate static void
874*b9b602f4Sjs prt_a_opt(struct sa64 *xx)
8757c478bd9Sstevel@tonic-gate {
8767c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f\n",
8777c478bd9Sstevel@tonic-gate 		(float)xx->csi.ufsiget / sec_diff,
8787c478bd9Sstevel@tonic-gate 		(float)xx->csi.namei / sec_diff,
8797c478bd9Sstevel@tonic-gate 		(float)xx->csi.ufsdirblk / sec_diff);
8807c478bd9Sstevel@tonic-gate }
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate static void
883*b9b602f4Sjs prt_q_opt(struct sa64 *xx)
8847c478bd9Sstevel@tonic-gate {
885b2d230ebSjc 	if (xx->si.runocc == 0 || xx->si.updates == 0)
8867c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f", 0., 0.);
8877c478bd9Sstevel@tonic-gate 	else {
8887c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f",
8897c478bd9Sstevel@tonic-gate 		    (float)xx->si.runque / (float)xx->si.runocc,
890b2d230ebSjc 		    (float)xx->si.runocc / (float)xx->si.updates * 100.0);
8917c478bd9Sstevel@tonic-gate 	}
892b2d230ebSjc 	if (xx->si.swpocc == 0 || xx->si.updates == 0)
8937c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f\n", 0., 0.);
8947c478bd9Sstevel@tonic-gate 	else {
8957c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f\n",
8967c478bd9Sstevel@tonic-gate 		    (float)xx->si.swpque / (float)xx->si.swpocc,
897b2d230ebSjc 		    (float)xx->si.swpocc / (float)xx->si.updates * 100.0);
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate }
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate static void
902*b9b602f4Sjs prt_v_opt(struct sa64 *xx)
9037c478bd9Sstevel@tonic-gate {
904*b9b602f4Sjs 	(void) printf(" %4lu/%-4lu %4llu %4lu/%-4lu %4llu %4lu/%-4lu "
905*b9b602f4Sjs 	    "%4llu %4lu/%-4lu\n",
9067c478bd9Sstevel@tonic-gate 	    nx.szproc, nx.mszproc, xx->csi.procovf,
9077c478bd9Sstevel@tonic-gate 	    nx.szinode, nx.mszinode, xx->csi.inodeovf,
9087c478bd9Sstevel@tonic-gate 	    nx.szfile, nx.mszfile, xx->csi.fileovf,
9097c478bd9Sstevel@tonic-gate 	    nx.szlckr, nx.mszlckr);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate static void
913*b9b602f4Sjs prt_m_opt(struct sa64 *xx)
9147c478bd9Sstevel@tonic-gate {
9157c478bd9Sstevel@tonic-gate 	(void) printf(" %7.2f %7.2f\n",
9167c478bd9Sstevel@tonic-gate 		(float)xx->csi.msg / sec_diff,
9177c478bd9Sstevel@tonic-gate 		(float)xx->csi.sema / sec_diff);
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate static void
921*b9b602f4Sjs prt_p_opt(struct sa64 *xx)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	(void) printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
9247c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgfrec / sec_diff,
9257c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgin / sec_diff,
9267c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgpgin / sec_diff,
9277c478bd9Sstevel@tonic-gate 		(float)(xx->cvmi.prot_fault + xx->cvmi.cow_fault) / sec_diff,
9287c478bd9Sstevel@tonic-gate 		(float)(xx->cvmi.hat_fault + xx->cvmi.as_fault) / sec_diff,
9297c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.softlock / sec_diff);
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate static void
933*b9b602f4Sjs prt_g_opt(struct sa64 *xx)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	(void) printf(" %8.2f %8.2f %8.2f %8.2f %8.2f\n",
9367c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgout / sec_diff,
9377c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgpgout / sec_diff,
9387c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.dfree / sec_diff,
9397c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.scan / sec_diff,
9407c478bd9Sstevel@tonic-gate 		(float)xx->csi.ufsipage * 100.0 /
9417c478bd9Sstevel@tonic-gate 			denom((float)xx->csi.ufsipage +
9427c478bd9Sstevel@tonic-gate 			(float)xx->csi.ufsinopage));
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate static void
946*b9b602f4Sjs prt_r_opt(struct sa64 *xx)
9477c478bd9Sstevel@tonic-gate {
948b2d230ebSjc 	/* Avoid divide by Zero - Should never happen */
949b2d230ebSjc 	if (xx->si.updates == 0)
950b2d230ebSjc 		(void) printf(" %7.0f %8.0f\n", 0., 0.);
951b2d230ebSjc 	else {
952b2d230ebSjc 		(void) printf(" %7.0f %8.0f\n",
953b2d230ebSjc 		    (double)xx->vmi.freemem / (float)xx->si.updates,
954b2d230ebSjc 		    (double)PGTOBLK(xx->vmi.swap_avail) /
955b2d230ebSjc 			(float)xx->si.updates);
956b2d230ebSjc 	}
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate static void
960*b9b602f4Sjs prt_k_opt(struct sa64 *xx, int n)
9617c478bd9Sstevel@tonic-gate {
9627c478bd9Sstevel@tonic-gate 	if (n != 1) {
9637c478bd9Sstevel@tonic-gate 		(void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f"
9647c478bd9Sstevel@tonic-gate 		    " %5.0f\n",
9657c478bd9Sstevel@tonic-gate 		    (float)kmi.km_mem[KMEM_SMALL] / n,
9667c478bd9Sstevel@tonic-gate 		    (float)kmi.km_alloc[KMEM_SMALL] / n,
9677c478bd9Sstevel@tonic-gate 		    (float)kmi.km_fail[KMEM_SMALL] / n,
9687c478bd9Sstevel@tonic-gate 		    (float)kmi.km_mem[KMEM_LARGE] / n,
9697c478bd9Sstevel@tonic-gate 		    (float)kmi.km_alloc[KMEM_LARGE] / n,
9707c478bd9Sstevel@tonic-gate 		    (float)kmi.km_fail[KMEM_LARGE] / n,
9717c478bd9Sstevel@tonic-gate 		    (float)kmi.km_alloc[KMEM_OSIZE] / n,
9727c478bd9Sstevel@tonic-gate 		    (float)kmi.km_fail[KMEM_OSIZE] / n);
9737c478bd9Sstevel@tonic-gate 	} else {
9747c478bd9Sstevel@tonic-gate 		/*
9757c478bd9Sstevel@tonic-gate 		 * If we are not reporting averages, use the read values
9767c478bd9Sstevel@tonic-gate 		 * directly.
9777c478bd9Sstevel@tonic-gate 		 */
9787c478bd9Sstevel@tonic-gate 		(void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f"
9797c478bd9Sstevel@tonic-gate 		    " %5.0f\n",
9807c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_mem[KMEM_SMALL],
9817c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_alloc[KMEM_SMALL],
9827c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_fail[KMEM_SMALL],
9837c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_mem[KMEM_LARGE],
9847c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_alloc[KMEM_LARGE],
9857c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_fail[KMEM_LARGE],
9867c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_alloc[KMEM_OSIZE],
9877c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_fail[KMEM_OSIZE]);
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate /*
9927c478bd9Sstevel@tonic-gate  * Print options routine.
9937c478bd9Sstevel@tonic-gate  */
9947c478bd9Sstevel@tonic-gate static void
9957c478bd9Sstevel@tonic-gate prtopt(void)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate 	int	ii, jj = 0;
9987c478bd9Sstevel@tonic-gate 	char	ccc;
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	prttim();
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	while ((ccc = fopt[jj++]) != NULL) {
10037c478bd9Sstevel@tonic-gate 		if (ccc != 'd')
10047c478bd9Sstevel@tonic-gate 			tsttab();
10057c478bd9Sstevel@tonic-gate 		switch (ccc) {
10067c478bd9Sstevel@tonic-gate 		    case 'u':
10077c478bd9Sstevel@tonic-gate 			prt_u_opt(&dx);
10087c478bd9Sstevel@tonic-gate 			break;
10097c478bd9Sstevel@tonic-gate 		    case 'b':
10107c478bd9Sstevel@tonic-gate 			prt_b_opt(&dx);
10117c478bd9Sstevel@tonic-gate 			break;
10127c478bd9Sstevel@tonic-gate 		    case 'd':
10137c478bd9Sstevel@tonic-gate 			for (ii = 0; ii < niodevs; ii++)
10147c478bd9Sstevel@tonic-gate 				prt_d_opt(ii, dxio);
10157c478bd9Sstevel@tonic-gate 			break;
10167c478bd9Sstevel@tonic-gate 		    case 'y':
10177c478bd9Sstevel@tonic-gate 			prt_y_opt(&dx);
10187c478bd9Sstevel@tonic-gate 			break;
10197c478bd9Sstevel@tonic-gate 		    case 'c':
10207c478bd9Sstevel@tonic-gate 			prt_c_opt(&dx);
10217c478bd9Sstevel@tonic-gate 			break;
10227c478bd9Sstevel@tonic-gate 		    case 'w':
10237c478bd9Sstevel@tonic-gate 			prt_w_opt(&dx);
10247c478bd9Sstevel@tonic-gate 			break;
10257c478bd9Sstevel@tonic-gate 		    case 'a':
10267c478bd9Sstevel@tonic-gate 			prt_a_opt(&dx);
10277c478bd9Sstevel@tonic-gate 			break;
10287c478bd9Sstevel@tonic-gate 		    case 'q':
10297c478bd9Sstevel@tonic-gate 			prt_q_opt(&dx);
10307c478bd9Sstevel@tonic-gate 			break;
10317c478bd9Sstevel@tonic-gate 		    case 'v':
10327c478bd9Sstevel@tonic-gate 			prt_v_opt(&dx);
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 		    case 'm':
10357c478bd9Sstevel@tonic-gate 			prt_m_opt(&dx);
10367c478bd9Sstevel@tonic-gate 			break;
10377c478bd9Sstevel@tonic-gate 		    case 'p':
10387c478bd9Sstevel@tonic-gate 			prt_p_opt(&dx);
10397c478bd9Sstevel@tonic-gate 			break;
10407c478bd9Sstevel@tonic-gate 		    case 'g':
10417c478bd9Sstevel@tonic-gate 			prt_g_opt(&dx);
10427c478bd9Sstevel@tonic-gate 			break;
10437c478bd9Sstevel@tonic-gate 		    case 'r':
10447c478bd9Sstevel@tonic-gate 			prt_r_opt(&dx);
10457c478bd9Sstevel@tonic-gate 			break;
10467c478bd9Sstevel@tonic-gate 		    case 'k':
10477c478bd9Sstevel@tonic-gate 			prt_k_opt(&nx, 1);
10487c478bd9Sstevel@tonic-gate 			/*
10497c478bd9Sstevel@tonic-gate 			 * To avoid overflow, copy the data from the sa record
10507c478bd9Sstevel@tonic-gate 			 * into a struct kmeminfo_l which has members with
10517c478bd9Sstevel@tonic-gate 			 * larger data types.
10527c478bd9Sstevel@tonic-gate 			 */
10537c478bd9Sstevel@tonic-gate 			kmi.km_mem[KMEM_SMALL] += nx.kmi.km_mem[KMEM_SMALL];
10547c478bd9Sstevel@tonic-gate 			kmi.km_alloc[KMEM_SMALL] += nx.kmi.km_alloc[KMEM_SMALL];
10557c478bd9Sstevel@tonic-gate 			kmi.km_fail[KMEM_SMALL] += nx.kmi.km_fail[KMEM_SMALL];
10567c478bd9Sstevel@tonic-gate 			kmi.km_mem[KMEM_LARGE] += nx.kmi.km_mem[KMEM_LARGE];
10577c478bd9Sstevel@tonic-gate 			kmi.km_alloc[KMEM_LARGE] += nx.kmi.km_alloc[KMEM_LARGE];
10587c478bd9Sstevel@tonic-gate 			kmi.km_fail[KMEM_LARGE] += nx.kmi.km_fail[KMEM_LARGE];
10597c478bd9Sstevel@tonic-gate 			kmi.km_alloc[KMEM_OSIZE] += nx.kmi.km_alloc[KMEM_OSIZE];
10607c478bd9Sstevel@tonic-gate 			kmi.km_fail[KMEM_OSIZE] += nx.kmi.km_fail[KMEM_OSIZE];
10617c478bd9Sstevel@tonic-gate 			break;
10627c478bd9Sstevel@tonic-gate 		}
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 	if (jj > 2 || do_disk)
10657c478bd9Sstevel@tonic-gate 		(void) printf("\n");
10667c478bd9Sstevel@tonic-gate 	if (realtime)
10677c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate  * Print average routine.
10727c478bd9Sstevel@tonic-gate  */
10737c478bd9Sstevel@tonic-gate static void
10747c478bd9Sstevel@tonic-gate prtavg(void)
10757c478bd9Sstevel@tonic-gate {
10767c478bd9Sstevel@tonic-gate 	int	ii, jj = 0;
10777c478bd9Sstevel@tonic-gate 	char	ccc;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	tdiff = ax.csi.cpu[0] + ax.csi.cpu[1] + ax.csi.cpu[2] + ax.csi.cpu[3];
10807c478bd9Sstevel@tonic-gate 	if (tdiff <= 0.0)
10817c478bd9Sstevel@tonic-gate 		return;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	sec_diff = tdiff / hz;
10847c478bd9Sstevel@tonic-gate 	percent = 100.0 / tdiff;
10857c478bd9Sstevel@tonic-gate 	(void) printf("\n");
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	while ((ccc = fopt[jj++]) != NULL) {
10887c478bd9Sstevel@tonic-gate 		if (ccc != 'v')
10897c478bd9Sstevel@tonic-gate 			(void) printf("Average ");
10907c478bd9Sstevel@tonic-gate 		switch (ccc) {
10917c478bd9Sstevel@tonic-gate 		    case 'u':
10927c478bd9Sstevel@tonic-gate 			prt_u_opt(&ax);
10937c478bd9Sstevel@tonic-gate 			break;
10947c478bd9Sstevel@tonic-gate 		    case 'b':
10957c478bd9Sstevel@tonic-gate 			prt_b_opt(&ax);
10967c478bd9Sstevel@tonic-gate 			break;
10977c478bd9Sstevel@tonic-gate 		    case 'd':
10987c478bd9Sstevel@tonic-gate 			tabflg = 1;
10997c478bd9Sstevel@tonic-gate 			for (ii = 0; ii < niodevs; ii++)
11007c478bd9Sstevel@tonic-gate 				prt_d_opt(ii, axio);
11017c478bd9Sstevel@tonic-gate 			break;
11027c478bd9Sstevel@tonic-gate 		    case 'y':
11037c478bd9Sstevel@tonic-gate 			prt_y_opt(&ax);
11047c478bd9Sstevel@tonic-gate 			break;
11057c478bd9Sstevel@tonic-gate 		    case 'c':
11067c478bd9Sstevel@tonic-gate 			prt_c_opt(&ax);
11077c478bd9Sstevel@tonic-gate 			break;
11087c478bd9Sstevel@tonic-gate 		    case 'w':
11097c478bd9Sstevel@tonic-gate 			prt_w_opt(&ax);
11107c478bd9Sstevel@tonic-gate 			break;
11117c478bd9Sstevel@tonic-gate 		    case 'a':
11127c478bd9Sstevel@tonic-gate 			prt_a_opt(&ax);
11137c478bd9Sstevel@tonic-gate 			break;
11147c478bd9Sstevel@tonic-gate 		    case 'q':
11157c478bd9Sstevel@tonic-gate 			prt_q_opt(&ax);
11167c478bd9Sstevel@tonic-gate 			break;
11177c478bd9Sstevel@tonic-gate 		    case 'v':
11187c478bd9Sstevel@tonic-gate 			break;
11197c478bd9Sstevel@tonic-gate 		    case 'm':
11207c478bd9Sstevel@tonic-gate 			prt_m_opt(&ax);
11217c478bd9Sstevel@tonic-gate 			break;
11227c478bd9Sstevel@tonic-gate 		    case 'p':
11237c478bd9Sstevel@tonic-gate 			prt_p_opt(&ax);
11247c478bd9Sstevel@tonic-gate 			break;
11257c478bd9Sstevel@tonic-gate 		    case 'g':
11267c478bd9Sstevel@tonic-gate 			prt_g_opt(&ax);
11277c478bd9Sstevel@tonic-gate 			break;
11287c478bd9Sstevel@tonic-gate 		    case 'r':
11297c478bd9Sstevel@tonic-gate 			prt_r_opt(&ax);
11307c478bd9Sstevel@tonic-gate 			break;
11317c478bd9Sstevel@tonic-gate 		    case 'k':
11327c478bd9Sstevel@tonic-gate 			prt_k_opt(&ax, lines);
11337c478bd9Sstevel@tonic-gate 			break;
11347c478bd9Sstevel@tonic-gate 		}
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate static void
1139*b9b602f4Sjs ulong_delta(uint64_t *new, uint64_t *old, uint64_t *delta, uint64_t *accum,
11407c478bd9Sstevel@tonic-gate 	int begin, int end)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate 	int i;
1143*b9b602f4Sjs 	uint64_t n, o, d;
1144*b9b602f4Sjs 
1145*b9b602f4Sjs 	for (i = begin; i < end; i += sizeof (uint64_t)) {
1146*b9b602f4Sjs 		n = *new++;
1147*b9b602f4Sjs 		o = *old++;
1148*b9b602f4Sjs 		if (o > n) {
1149*b9b602f4Sjs 			d = n + 0x100000000LL - o;
1150*b9b602f4Sjs 		} else {
1151*b9b602f4Sjs 			d = n - o;
1152*b9b602f4Sjs 		}
1153*b9b602f4Sjs 		*accum++ += *delta++ = d;
1154*b9b602f4Sjs 	}
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate /*
11587c478bd9Sstevel@tonic-gate  * used to prevent zero denominators
11597c478bd9Sstevel@tonic-gate  */
11607c478bd9Sstevel@tonic-gate static float
11617c478bd9Sstevel@tonic-gate denom(float x)
11627c478bd9Sstevel@tonic-gate {
11637c478bd9Sstevel@tonic-gate 	return ((x > 0.5) ? x : 1.0);
11647c478bd9Sstevel@tonic-gate }
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate /*
11677c478bd9Sstevel@tonic-gate  * a little calculation that comes up often when computing frequency
11687c478bd9Sstevel@tonic-gate  * of one operation relative to another
11697c478bd9Sstevel@tonic-gate  */
11707c478bd9Sstevel@tonic-gate static float
11717c478bd9Sstevel@tonic-gate freq(float x, float y)
11727c478bd9Sstevel@tonic-gate {
11737c478bd9Sstevel@tonic-gate 	return ((x < 0.5) ? 100.0 : (x - y) / x * 100.0);
11747c478bd9Sstevel@tonic-gate }
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate static void
11777c478bd9Sstevel@tonic-gate usage(void)
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
11807c478bd9Sstevel@tonic-gate 	    "usage: sar [-ubdycwaqvmpgrkA][-o file] t [n]\n"
11817c478bd9Sstevel@tonic-gate 	    "\tsar [-ubdycwaqvmpgrkA] [-s hh:mm][-e hh:mm][-i ss][-f file]\n");
11827c478bd9Sstevel@tonic-gate }
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate static void
11857c478bd9Sstevel@tonic-gate fail(int do_perror, char *message, ...)
11867c478bd9Sstevel@tonic-gate {
11877c478bd9Sstevel@tonic-gate 	va_list args;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 	va_start(args, message);
11907c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "sar: ");
11917c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, message, args);
11927c478bd9Sstevel@tonic-gate 	va_end(args);
11937c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
11947c478bd9Sstevel@tonic-gate 	switch (do_perror) {
11957c478bd9Sstevel@tonic-gate 	case 0:				/* usage message */
11967c478bd9Sstevel@tonic-gate 		usage();
11977c478bd9Sstevel@tonic-gate 		break;
11987c478bd9Sstevel@tonic-gate 	case 1:				/* perror output */
11997c478bd9Sstevel@tonic-gate 		perror("");
12007c478bd9Sstevel@tonic-gate 		break;
12017c478bd9Sstevel@tonic-gate 	case 2:				/* no further output */
12027c478bd9Sstevel@tonic-gate 		break;
12037c478bd9Sstevel@tonic-gate 	default:			/* error */
12047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "unsupported failure mode\n");
12057c478bd9Sstevel@tonic-gate 		break;
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 	exit(2);
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate static int
12117c478bd9Sstevel@tonic-gate safe_strtoi(char const *val, char *errmsg)
12127c478bd9Sstevel@tonic-gate {
12137c478bd9Sstevel@tonic-gate 	char *end;
12147c478bd9Sstevel@tonic-gate 	long tmp;
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	errno = 0;
12177c478bd9Sstevel@tonic-gate 	tmp = strtol(val, &end, 10);
12187c478bd9Sstevel@tonic-gate 	if (*end != '\0' || errno)
12197c478bd9Sstevel@tonic-gate 		fail(0, "%s %s", errmsg, val);
12207c478bd9Sstevel@tonic-gate 	return ((int)tmp);
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate static void
12247c478bd9Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first)
12257c478bd9Sstevel@tonic-gate {
12267c478bd9Sstevel@tonic-gate 	if (free_first && *ptr != NULL)
12277c478bd9Sstevel@tonic-gate 		free(*ptr);
12287c478bd9Sstevel@tonic-gate 	if ((*ptr = malloc(size)) == NULL)
12297c478bd9Sstevel@tonic-gate 		fail(1, "malloc failed");
12307c478bd9Sstevel@tonic-gate 	(void) memset(*ptr, 0, size);
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate static int
12347c478bd9Sstevel@tonic-gate safe_read(int fd, void *buf, size_t size)
12357c478bd9Sstevel@tonic-gate {
12367c478bd9Sstevel@tonic-gate 	size_t rsize = read(fd, buf, size);
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	if (rsize == 0)
12397c478bd9Sstevel@tonic-gate 		return (0);
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	if (rsize != size)
12427c478bd9Sstevel@tonic-gate 		fail(1, "read failed");
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	return (1);
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate static void
12487c478bd9Sstevel@tonic-gate safe_write(int fd, void *buf, size_t size)
12497c478bd9Sstevel@tonic-gate {
12507c478bd9Sstevel@tonic-gate 	if (write(fd, buf, size) != size)
12517c478bd9Sstevel@tonic-gate 		fail(1, "write failed");
12527c478bd9Sstevel@tonic-gate }
1253