xref: /illumos-gate/usr/src/cmd/sa/sar.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * sar generates a report either from an input data file or by invoking sadc to
35*7c478bd9Sstevel@tonic-gate  * read system activity counters at the specified intervals.
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * usage:  sar [-ubdycwaqvmpgrkA] [-o file] t [n]
38*7c478bd9Sstevel@tonic-gate  *	   sar [-ubdycwaqvmpgrkA][-s hh:mm][-e hh:mm][-i ss][-f file]
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #include <ctype.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
52*7c478bd9Sstevel@tonic-gate #include <limits.h>
53*7c478bd9Sstevel@tonic-gate #include <signal.h>
54*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
55*7c478bd9Sstevel@tonic-gate #include <stdio.h>
56*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
57*7c478bd9Sstevel@tonic-gate #include <string.h>
58*7c478bd9Sstevel@tonic-gate #include <time.h>
59*7c478bd9Sstevel@tonic-gate #include <unistd.h>
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include "sa.h"
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate #define	PGTOBLK(x)	((x) * (pagesize >> 9))
64*7c478bd9Sstevel@tonic-gate #define	BLKTOPG(x)	((x) / (pagesize >> 9))
65*7c478bd9Sstevel@tonic-gate #define	BLKS(x)		((x) >> 9)
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate static void	prpass(int);
68*7c478bd9Sstevel@tonic-gate static void	prtopt(void);
69*7c478bd9Sstevel@tonic-gate static void	prtavg(void);
70*7c478bd9Sstevel@tonic-gate static void	prttim(void);
71*7c478bd9Sstevel@tonic-gate static void	prtmachid(void);
72*7c478bd9Sstevel@tonic-gate static void	prthdg(void);
73*7c478bd9Sstevel@tonic-gate static void	tsttab(void);
74*7c478bd9Sstevel@tonic-gate static void	update_counters(void);
75*7c478bd9Sstevel@tonic-gate static void	usage(void);
76*7c478bd9Sstevel@tonic-gate static void	fail(int, char *, ...);
77*7c478bd9Sstevel@tonic-gate static void	safe_zalloc(void **, int, int);
78*7c478bd9Sstevel@tonic-gate static int	safe_read(int, void *, size_t);
79*7c478bd9Sstevel@tonic-gate static void	safe_write(int, void *, size_t);
80*7c478bd9Sstevel@tonic-gate static int	safe_strtoi(char const *, char *);
81*7c478bd9Sstevel@tonic-gate static void	ulong_delta(ulong_t *, ulong_t *, ulong_t *, ulong_t *,
82*7c478bd9Sstevel@tonic-gate 	int, int);
83*7c478bd9Sstevel@tonic-gate static float	denom(float);
84*7c478bd9Sstevel@tonic-gate static float	freq(float, float);
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static struct sa	nx, ox, ax, dx;
87*7c478bd9Sstevel@tonic-gate static iodevinfo_t	*nxio, *oxio, *axio, *dxio;
88*7c478bd9Sstevel@tonic-gate static struct tm	*curt, args, arge;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static int	sflg, eflg, iflg, oflg, fflg;
91*7c478bd9Sstevel@tonic-gate static int	realtime, passno = 0, do_disk;
92*7c478bd9Sstevel@tonic-gate static int	t = 0, n = 0, lines = 0;
93*7c478bd9Sstevel@tonic-gate static int	hz;
94*7c478bd9Sstevel@tonic-gate static int	niodevs;
95*7c478bd9Sstevel@tonic-gate static int	tabflg;
96*7c478bd9Sstevel@tonic-gate static char	options[30], fopt[30];
97*7c478bd9Sstevel@tonic-gate static float	tdiff, sec_diff, totsec_diff = 0.0, percent;
98*7c478bd9Sstevel@tonic-gate static time_t	ts, te;			/* time interval start and end */
99*7c478bd9Sstevel@tonic-gate static float	start_time, end_time, isec;
100*7c478bd9Sstevel@tonic-gate static int 	fin, fout;
101*7c478bd9Sstevel@tonic-gate static pid_t	childid;
102*7c478bd9Sstevel@tonic-gate static int	pipedes[2];
103*7c478bd9Sstevel@tonic-gate static char	arg1[10], arg2[10];
104*7c478bd9Sstevel@tonic-gate static int	pagesize;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate /*
107*7c478bd9Sstevel@tonic-gate  * To avoid overflow in the kmem allocation data, declare a copy of the
108*7c478bd9Sstevel@tonic-gate  * main kmeminfo_t type with larger data types. Use this for storing
109*7c478bd9Sstevel@tonic-gate  * the data held to display average values
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate static struct kmeminfo_l
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	u_longlong_t	km_mem[KMEM_NCLASS];
114*7c478bd9Sstevel@tonic-gate 	u_longlong_t	km_alloc[KMEM_NCLASS];
115*7c478bd9Sstevel@tonic-gate 	u_longlong_t	km_fail[KMEM_NCLASS];
116*7c478bd9Sstevel@tonic-gate } kmi;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate int
119*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
120*7c478bd9Sstevel@tonic-gate {
121*7c478bd9Sstevel@tonic-gate 	char    flnm[PATH_MAX], ofile[PATH_MAX];
122*7c478bd9Sstevel@tonic-gate 	char	ccc;
123*7c478bd9Sstevel@tonic-gate 	time_t	temp;
124*7c478bd9Sstevel@tonic-gate 	int	i, jj = 0;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	pagesize = sysconf(_SC_PAGESIZE);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	/*
129*7c478bd9Sstevel@tonic-gate 	 * Process options with arguments and pack options
130*7c478bd9Sstevel@tonic-gate 	 * without arguments.
131*7c478bd9Sstevel@tonic-gate 	 */
132*7c478bd9Sstevel@tonic-gate 	while ((i = getopt(argc, argv, "ubdycwaqvmpgrkAo:s:e:i:f:")) != EOF)
133*7c478bd9Sstevel@tonic-gate 		switch (ccc = (char)i) {
134*7c478bd9Sstevel@tonic-gate 		    case 'o':
135*7c478bd9Sstevel@tonic-gate 			oflg++;
136*7c478bd9Sstevel@tonic-gate 			if (strlcpy(ofile, optarg, sizeof (ofile)) >=
137*7c478bd9Sstevel@tonic-gate 			    sizeof (ofile)) {
138*7c478bd9Sstevel@tonic-gate 				fail(2, "-o filename is too long: %s", optarg);
139*7c478bd9Sstevel@tonic-gate 			}
140*7c478bd9Sstevel@tonic-gate 			break;
141*7c478bd9Sstevel@tonic-gate 		    case 's':
142*7c478bd9Sstevel@tonic-gate 			if (sscanf(optarg, "%d:%d:%d",
143*7c478bd9Sstevel@tonic-gate 			    &args.tm_hour, &args.tm_min, &args.tm_sec) < 1)
144*7c478bd9Sstevel@tonic-gate 				fail(0, "-%c %s -- illegal option argument",
145*7c478bd9Sstevel@tonic-gate 				    ccc, optarg);
146*7c478bd9Sstevel@tonic-gate 			else {
147*7c478bd9Sstevel@tonic-gate 				sflg++,
148*7c478bd9Sstevel@tonic-gate 				start_time = args.tm_hour*3600.0 +
149*7c478bd9Sstevel@tonic-gate 				    args.tm_min*60.0 +
150*7c478bd9Sstevel@tonic-gate 				    args.tm_sec;
151*7c478bd9Sstevel@tonic-gate 			}
152*7c478bd9Sstevel@tonic-gate 			break;
153*7c478bd9Sstevel@tonic-gate 		    case 'e':
154*7c478bd9Sstevel@tonic-gate 			if (sscanf(optarg, "%d:%d:%d",
155*7c478bd9Sstevel@tonic-gate 			    &arge.tm_hour, &arge.tm_min, &arge.tm_sec) < 1)
156*7c478bd9Sstevel@tonic-gate 				fail(0, "-%c %s -- illegal option argument",
157*7c478bd9Sstevel@tonic-gate 				    ccc, optarg);
158*7c478bd9Sstevel@tonic-gate 			else {
159*7c478bd9Sstevel@tonic-gate 				eflg++;
160*7c478bd9Sstevel@tonic-gate 				end_time = arge.tm_hour*3600.0 +
161*7c478bd9Sstevel@tonic-gate 				    arge.tm_min*60.0 +
162*7c478bd9Sstevel@tonic-gate 				    arge.tm_sec;
163*7c478bd9Sstevel@tonic-gate 			}
164*7c478bd9Sstevel@tonic-gate 			break;
165*7c478bd9Sstevel@tonic-gate 		    case 'i':
166*7c478bd9Sstevel@tonic-gate 			if (sscanf(optarg, "%f", &isec) < 1)
167*7c478bd9Sstevel@tonic-gate 				fail(0, "-%c %s -- illegal option argument",
168*7c478bd9Sstevel@tonic-gate 				    ccc, optarg);
169*7c478bd9Sstevel@tonic-gate 			else {
170*7c478bd9Sstevel@tonic-gate 				if (isec > 0.0)
171*7c478bd9Sstevel@tonic-gate 					iflg++;
172*7c478bd9Sstevel@tonic-gate 			}
173*7c478bd9Sstevel@tonic-gate 			break;
174*7c478bd9Sstevel@tonic-gate 		    case 'f':
175*7c478bd9Sstevel@tonic-gate 			fflg++;
176*7c478bd9Sstevel@tonic-gate 			if (strlcpy(flnm, optarg, sizeof (flnm)) >=
177*7c478bd9Sstevel@tonic-gate 			    sizeof (ofile)) {
178*7c478bd9Sstevel@tonic-gate 				fail(2, "-f filename is too long: %s", optarg);
179*7c478bd9Sstevel@tonic-gate 			}
180*7c478bd9Sstevel@tonic-gate 			break;
181*7c478bd9Sstevel@tonic-gate 		    case '?':
182*7c478bd9Sstevel@tonic-gate 			usage();
183*7c478bd9Sstevel@tonic-gate 			exit(1);
184*7c478bd9Sstevel@tonic-gate 			break;
185*7c478bd9Sstevel@tonic-gate 		default:
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 			/*
188*7c478bd9Sstevel@tonic-gate 			 * Check for repeated options. To make sure
189*7c478bd9Sstevel@tonic-gate 			 * that options[30] does not overflow.
190*7c478bd9Sstevel@tonic-gate 			 */
191*7c478bd9Sstevel@tonic-gate 			if (strchr(options, ccc) == NULL)
192*7c478bd9Sstevel@tonic-gate 				(void) strncat(options, &ccc, 1);
193*7c478bd9Sstevel@tonic-gate 			break;
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	/*
197*7c478bd9Sstevel@tonic-gate 	 * Are starting and ending times consistent?
198*7c478bd9Sstevel@tonic-gate 	 */
199*7c478bd9Sstevel@tonic-gate 	if ((sflg) && (eflg) && (end_time <= start_time))
200*7c478bd9Sstevel@tonic-gate 		fail(0, "ending time <= starting time");
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	/*
203*7c478bd9Sstevel@tonic-gate 	 * Determine if t and n arguments are given, and whether to run in real
204*7c478bd9Sstevel@tonic-gate 	 * time or from a file.
205*7c478bd9Sstevel@tonic-gate 	 */
206*7c478bd9Sstevel@tonic-gate 	switch (argc - optind) {
207*7c478bd9Sstevel@tonic-gate 	    case 0:		/*   Get input data from file   */
208*7c478bd9Sstevel@tonic-gate 		if (fflg == 0) {
209*7c478bd9Sstevel@tonic-gate 			temp = time(NULL);
210*7c478bd9Sstevel@tonic-gate 			curt = localtime(&temp);
211*7c478bd9Sstevel@tonic-gate 			(void) snprintf(flnm, PATH_MAX, "/var/adm/sa/sa%.2d",
212*7c478bd9Sstevel@tonic-gate 			    curt->tm_mday);
213*7c478bd9Sstevel@tonic-gate 		}
214*7c478bd9Sstevel@tonic-gate 		if ((fin = open(flnm, 0)) == -1)
215*7c478bd9Sstevel@tonic-gate 			fail(1, "can't open %s", flnm);
216*7c478bd9Sstevel@tonic-gate 		break;
217*7c478bd9Sstevel@tonic-gate 	    case 1:		/*   Real time data; one cycle   */
218*7c478bd9Sstevel@tonic-gate 		realtime++;
219*7c478bd9Sstevel@tonic-gate 		t = safe_strtoi(argv[optind], "invalid sampling interval");
220*7c478bd9Sstevel@tonic-gate 		n = 2;
221*7c478bd9Sstevel@tonic-gate 		break;
222*7c478bd9Sstevel@tonic-gate 	    case 2:		/*   Real time data; specified cycles   */
223*7c478bd9Sstevel@tonic-gate 	default:
224*7c478bd9Sstevel@tonic-gate 		realtime++;
225*7c478bd9Sstevel@tonic-gate 		t = safe_strtoi(argv[optind], "invalid sampling interval");
226*7c478bd9Sstevel@tonic-gate 		n = 1 + safe_strtoi(argv[optind+1], "invalid sample count");
227*7c478bd9Sstevel@tonic-gate 		break;
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	/*
231*7c478bd9Sstevel@tonic-gate 	 * "u" is the default option, which displays CPU utilization.
232*7c478bd9Sstevel@tonic-gate 	 */
233*7c478bd9Sstevel@tonic-gate 	if (strlen(options) == 0)
234*7c478bd9Sstevel@tonic-gate 		(void) strcpy(options, "u");
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	/*
237*7c478bd9Sstevel@tonic-gate 	 * "A" means all data options.
238*7c478bd9Sstevel@tonic-gate 	 */
239*7c478bd9Sstevel@tonic-gate 	if (strchr(options, 'A') != NULL)
240*7c478bd9Sstevel@tonic-gate 		(void) strcpy(options, "udqbwcayvmpgrk");
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	if (realtime) {
243*7c478bd9Sstevel@tonic-gate 		/*
244*7c478bd9Sstevel@tonic-gate 		 * Get input data from sadc via pipe.
245*7c478bd9Sstevel@tonic-gate 		 */
246*7c478bd9Sstevel@tonic-gate 		if (t <= 0)
247*7c478bd9Sstevel@tonic-gate 			fail(0, "sampling interval t <= 0 sec");
248*7c478bd9Sstevel@tonic-gate 		if (n < 2)
249*7c478bd9Sstevel@tonic-gate 			fail(0, "number of sample intervals n <= 0");
250*7c478bd9Sstevel@tonic-gate 		(void) sprintf(arg1, "%d", t);
251*7c478bd9Sstevel@tonic-gate 		(void) sprintf(arg2, "%d", n);
252*7c478bd9Sstevel@tonic-gate 		if (pipe(pipedes) == -1)
253*7c478bd9Sstevel@tonic-gate 			fail(1, "pipe failed");
254*7c478bd9Sstevel@tonic-gate 		if ((childid = fork()) == 0) {
255*7c478bd9Sstevel@tonic-gate 			/*
256*7c478bd9Sstevel@tonic-gate 			 * Child:  shift pipedes[write] to stdout,
257*7c478bd9Sstevel@tonic-gate 			 * and close the pipe entries.
258*7c478bd9Sstevel@tonic-gate 			 */
259*7c478bd9Sstevel@tonic-gate 			(void) dup2(pipedes[1], 1);
260*7c478bd9Sstevel@tonic-gate 			if (pipedes[0] != 1)
261*7c478bd9Sstevel@tonic-gate 				(void) close(pipedes[0]);
262*7c478bd9Sstevel@tonic-gate 			if (pipedes[1] != 1)
263*7c478bd9Sstevel@tonic-gate 				(void) close(pipedes[1]);
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 			if (execlp("/usr/lib/sa/sadc",
266*7c478bd9Sstevel@tonic-gate 			    "/usr/lib/sa/sadc", arg1, arg2, 0) == -1)
267*7c478bd9Sstevel@tonic-gate 				fail(1, "exec of /usr/lib/sa/sadc failed");
268*7c478bd9Sstevel@tonic-gate 		} else if (childid == -1) {
269*7c478bd9Sstevel@tonic-gate 			fail(1, "Could not fork to exec sadc");
270*7c478bd9Sstevel@tonic-gate 		}
271*7c478bd9Sstevel@tonic-gate 		/*
272*7c478bd9Sstevel@tonic-gate 		 * Parent:  close unused output.
273*7c478bd9Sstevel@tonic-gate 		 */
274*7c478bd9Sstevel@tonic-gate 		fin = pipedes[0];
275*7c478bd9Sstevel@tonic-gate 		(void) close(pipedes[1]);
276*7c478bd9Sstevel@tonic-gate 	}
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	if (oflg) {
279*7c478bd9Sstevel@tonic-gate 		if (strcmp(ofile, flnm) == 0)
280*7c478bd9Sstevel@tonic-gate 			fail(0, "output file name same as input file name");
281*7c478bd9Sstevel@tonic-gate 		fout = creat(ofile, 00644);
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	hz = sysconf(_SC_CLK_TCK);
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	nxio = oxio = dxio = axio = NULL;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	if (realtime) {
289*7c478bd9Sstevel@tonic-gate 		/*
290*7c478bd9Sstevel@tonic-gate 		 * Make single pass, processing all options.
291*7c478bd9Sstevel@tonic-gate 		 */
292*7c478bd9Sstevel@tonic-gate 		(void) strcpy(fopt, options);
293*7c478bd9Sstevel@tonic-gate 		passno++;
294*7c478bd9Sstevel@tonic-gate 		prpass(realtime);
295*7c478bd9Sstevel@tonic-gate 		(void) kill(childid, SIGINT);
296*7c478bd9Sstevel@tonic-gate 		(void) wait(NULL);
297*7c478bd9Sstevel@tonic-gate 	} else {
298*7c478bd9Sstevel@tonic-gate 		/*
299*7c478bd9Sstevel@tonic-gate 		 * Make multiple passes, one for each option.
300*7c478bd9Sstevel@tonic-gate 		 */
301*7c478bd9Sstevel@tonic-gate 		while (strlen(strncpy(fopt, &options[jj++], 1))) {
302*7c478bd9Sstevel@tonic-gate 			if (lseek(fin, 0, SEEK_SET) == (off_t)-1)
303*7c478bd9Sstevel@tonic-gate 				fail(0, "lseek failed");
304*7c478bd9Sstevel@tonic-gate 			passno++;
305*7c478bd9Sstevel@tonic-gate 			prpass(realtime);
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	return (0);
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate /*
313*7c478bd9Sstevel@tonic-gate  * Read records from input, classify, and decide on printing.
314*7c478bd9Sstevel@tonic-gate  */
315*7c478bd9Sstevel@tonic-gate static void
316*7c478bd9Sstevel@tonic-gate prpass(int input_pipe)
317*7c478bd9Sstevel@tonic-gate {
318*7c478bd9Sstevel@tonic-gate 	size_t size;
319*7c478bd9Sstevel@tonic-gate 	int i, j, state_change, recno = 0;
320*7c478bd9Sstevel@tonic-gate 	kid_t kid;
321*7c478bd9Sstevel@tonic-gate 	float trec, tnext = 0;
322*7c478bd9Sstevel@tonic-gate 	ulong_t old_niodevs = 0, prev_niodevs = 0;
323*7c478bd9Sstevel@tonic-gate 	iodevinfo_t *aio, *dio, *oio;
324*7c478bd9Sstevel@tonic-gate 	struct stat in_stat;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 	do_disk = (strchr(fopt, 'd') != NULL);
327*7c478bd9Sstevel@tonic-gate 	if (!input_pipe && fstat(fin, &in_stat) == -1)
328*7c478bd9Sstevel@tonic-gate 		fail(1, "unable to stat data file");
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	if (sflg)
331*7c478bd9Sstevel@tonic-gate 		tnext = start_time;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	while (safe_read(fin, &nx, sizeof (struct sa))) {
334*7c478bd9Sstevel@tonic-gate 		/*
335*7c478bd9Sstevel@tonic-gate 		 * sadc is the only utility used to generate sar data
336*7c478bd9Sstevel@tonic-gate 		 * and it uses the valid field as follows:
337*7c478bd9Sstevel@tonic-gate 		 * 0 - dummy record
338*7c478bd9Sstevel@tonic-gate 		 * 1 - data record
339*7c478bd9Sstevel@tonic-gate 		 * We can use this fact to improve sar's ability to detect
340*7c478bd9Sstevel@tonic-gate 		 * bad data, since any value apart from 0 or 1 can be
341*7c478bd9Sstevel@tonic-gate 		 * interpreted as invalid data.
342*7c478bd9Sstevel@tonic-gate 		 */
343*7c478bd9Sstevel@tonic-gate 		if (nx.valid != 0 && nx.valid != 1)
344*7c478bd9Sstevel@tonic-gate 			fail(2, "data file not in sar format");
345*7c478bd9Sstevel@tonic-gate 		state_change = 0;
346*7c478bd9Sstevel@tonic-gate 		niodevs = nx.niodevs;
347*7c478bd9Sstevel@tonic-gate 		/*
348*7c478bd9Sstevel@tonic-gate 		 * niodevs has the value of current number of devices
349*7c478bd9Sstevel@tonic-gate 		 * from nx structure.
350*7c478bd9Sstevel@tonic-gate 		 *
351*7c478bd9Sstevel@tonic-gate 		 * The following 'if' condition is to decide whether memory
352*7c478bd9Sstevel@tonic-gate 		 * has to be allocated or not if already allocated memory is
353*7c478bd9Sstevel@tonic-gate 		 * bigger or smaller than memory needed to store the current
354*7c478bd9Sstevel@tonic-gate 		 * niodevs details in memory.
355*7c478bd9Sstevel@tonic-gate 		 *
356*7c478bd9Sstevel@tonic-gate 		 * when first while loop starts, pre_niodevs has 0 and then
357*7c478bd9Sstevel@tonic-gate 		 * always get initialized to the current number of devices
358*7c478bd9Sstevel@tonic-gate 		 * from nx.niodevs if it is different from previously read
359*7c478bd9Sstevel@tonic-gate 		 * niodevs.
360*7c478bd9Sstevel@tonic-gate 		 *
361*7c478bd9Sstevel@tonic-gate 		 * if the current niodevs has the same value of previously
362*7c478bd9Sstevel@tonic-gate 		 * allocated memory i.e, for prev_niodevs, it skips the
363*7c478bd9Sstevel@tonic-gate 		 * following  'if' loop or otherwise it allocates memory for
364*7c478bd9Sstevel@tonic-gate 		 * current devises (niodevs) and stores that value in
365*7c478bd9Sstevel@tonic-gate 		 * prev_niodevs for next time when loop continues to read
366*7c478bd9Sstevel@tonic-gate 		 * from the file.
367*7c478bd9Sstevel@tonic-gate 		 */
368*7c478bd9Sstevel@tonic-gate 		if (niodevs != prev_niodevs) {
369*7c478bd9Sstevel@tonic-gate 			off_t curr_pos;
370*7c478bd9Sstevel@tonic-gate 			/*
371*7c478bd9Sstevel@tonic-gate 			 * The required buffer size must fit in a size_t.
372*7c478bd9Sstevel@tonic-gate 			 */
373*7c478bd9Sstevel@tonic-gate 			if (SIZE_MAX / sizeof (iodevinfo_t) < niodevs)
374*7c478bd9Sstevel@tonic-gate 				fail(2, "insufficient address space to hold "
375*7c478bd9Sstevel@tonic-gate 				    "%lu device records", niodevs);
376*7c478bd9Sstevel@tonic-gate 			size = niodevs * sizeof (iodevinfo_t);
377*7c478bd9Sstevel@tonic-gate 			prev_niodevs = niodevs;
378*7c478bd9Sstevel@tonic-gate 			/*
379*7c478bd9Sstevel@tonic-gate 			 * The data file must exceed this size to be valid.
380*7c478bd9Sstevel@tonic-gate 			 */
381*7c478bd9Sstevel@tonic-gate 			if (!input_pipe) {
382*7c478bd9Sstevel@tonic-gate 			    if ((curr_pos = lseek(fin, 0, SEEK_CUR)) ==
383*7c478bd9Sstevel@tonic-gate 				(off_t)-1)
384*7c478bd9Sstevel@tonic-gate 				    fail(1, "lseek failed");
385*7c478bd9Sstevel@tonic-gate 			    if (in_stat.st_size < curr_pos ||
386*7c478bd9Sstevel@tonic-gate 				size > in_stat.st_size - curr_pos)
387*7c478bd9Sstevel@tonic-gate 				    fail(2, "data file corrupt; specified size"
388*7c478bd9Sstevel@tonic-gate 					"exceeds actual");
389*7c478bd9Sstevel@tonic-gate 			}
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 			safe_zalloc((void **)&nxio, size, 1);
392*7c478bd9Sstevel@tonic-gate 		}
393*7c478bd9Sstevel@tonic-gate 		if (niodevs != old_niodevs)
394*7c478bd9Sstevel@tonic-gate 			state_change = 1;
395*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < niodevs; i++) {
396*7c478bd9Sstevel@tonic-gate 			if (safe_read(fin, &nxio[i], sizeof (iodevinfo_t)) == 0)
397*7c478bd9Sstevel@tonic-gate 				fail(1, "premature end-of-file seen");
398*7c478bd9Sstevel@tonic-gate 			if (i < old_niodevs &&
399*7c478bd9Sstevel@tonic-gate 			    nxio[i].ks.ks_kid != oxio[i].ks.ks_kid)
400*7c478bd9Sstevel@tonic-gate 				state_change = 1;
401*7c478bd9Sstevel@tonic-gate 		}
402*7c478bd9Sstevel@tonic-gate 		curt = localtime(&nx.ts);
403*7c478bd9Sstevel@tonic-gate 		trec = curt->tm_hour * 3600.0 +
404*7c478bd9Sstevel@tonic-gate 		    curt->tm_min * 60.0 +
405*7c478bd9Sstevel@tonic-gate 		    curt->tm_sec;
406*7c478bd9Sstevel@tonic-gate 		if ((recno == 0) && (trec < start_time))
407*7c478bd9Sstevel@tonic-gate 			continue;
408*7c478bd9Sstevel@tonic-gate 		if ((eflg) && (trec > end_time))
409*7c478bd9Sstevel@tonic-gate 			break;
410*7c478bd9Sstevel@tonic-gate 		if ((oflg) && (passno == 1)) {
411*7c478bd9Sstevel@tonic-gate 			safe_write(fout, &nx, sizeof (struct sa));
412*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < niodevs; i++)
413*7c478bd9Sstevel@tonic-gate 				safe_write(fout, &nxio[i],
414*7c478bd9Sstevel@tonic-gate 				    sizeof (iodevinfo_t));
415*7c478bd9Sstevel@tonic-gate 		}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 		if (recno == 0) {
418*7c478bd9Sstevel@tonic-gate 			if (passno == 1)
419*7c478bd9Sstevel@tonic-gate 				prtmachid();
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 			prthdg();
422*7c478bd9Sstevel@tonic-gate 			recno = 1;
423*7c478bd9Sstevel@tonic-gate 			if ((iflg) && (tnext == 0))
424*7c478bd9Sstevel@tonic-gate 				tnext = trec;
425*7c478bd9Sstevel@tonic-gate 		}
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 		if (nx.valid == 0) {
428*7c478bd9Sstevel@tonic-gate 			/*
429*7c478bd9Sstevel@tonic-gate 			 * This dummy record signifies system restart
430*7c478bd9Sstevel@tonic-gate 			 * New initial values of counters follow in next
431*7c478bd9Sstevel@tonic-gate 			 * record.
432*7c478bd9Sstevel@tonic-gate 			 */
433*7c478bd9Sstevel@tonic-gate 			if (!realtime) {
434*7c478bd9Sstevel@tonic-gate 				prttim();
435*7c478bd9Sstevel@tonic-gate 				(void) printf("\tunix restarts\n");
436*7c478bd9Sstevel@tonic-gate 				recno = 1;
437*7c478bd9Sstevel@tonic-gate 				continue;
438*7c478bd9Sstevel@tonic-gate 			}
439*7c478bd9Sstevel@tonic-gate 		}
440*7c478bd9Sstevel@tonic-gate 		if ((iflg) && (trec < tnext))
441*7c478bd9Sstevel@tonic-gate 			continue;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 		if (state_change) {
444*7c478bd9Sstevel@tonic-gate 			/*
445*7c478bd9Sstevel@tonic-gate 			 * Either the number of devices or the ordering of
446*7c478bd9Sstevel@tonic-gate 			 * the kstats has changed.  We need to re-organise
447*7c478bd9Sstevel@tonic-gate 			 * the layout of our avg/delta arrays so that we
448*7c478bd9Sstevel@tonic-gate 			 * can cope with this in update_counters().
449*7c478bd9Sstevel@tonic-gate 			 */
450*7c478bd9Sstevel@tonic-gate 			size = niodevs * sizeof (iodevinfo_t);
451*7c478bd9Sstevel@tonic-gate 			safe_zalloc((void *)&aio, size, 0);
452*7c478bd9Sstevel@tonic-gate 			safe_zalloc((void *)&dio, size, 0);
453*7c478bd9Sstevel@tonic-gate 			safe_zalloc((void *)&oio, size, 0);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 			/*
456*7c478bd9Sstevel@tonic-gate 			 * Loop through all the newly read iodev's, locate
457*7c478bd9Sstevel@tonic-gate 			 * the corresponding entry in the old arrays and
458*7c478bd9Sstevel@tonic-gate 			 * copy the entries into the same bucket of the
459*7c478bd9Sstevel@tonic-gate 			 * new arrays.
460*7c478bd9Sstevel@tonic-gate 			 */
461*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < niodevs; i++) {
462*7c478bd9Sstevel@tonic-gate 				kid = nxio[i].ks.ks_kid;
463*7c478bd9Sstevel@tonic-gate 				for (j = 0; j < old_niodevs; j++) {
464*7c478bd9Sstevel@tonic-gate 					if (oxio[j].ks.ks_kid == kid) {
465*7c478bd9Sstevel@tonic-gate 						oio[i] = oxio[j];
466*7c478bd9Sstevel@tonic-gate 						aio[i] = axio[j];
467*7c478bd9Sstevel@tonic-gate 						dio[i] = dxio[j];
468*7c478bd9Sstevel@tonic-gate 					}
469*7c478bd9Sstevel@tonic-gate 				}
470*7c478bd9Sstevel@tonic-gate 			}
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 			free(axio);
473*7c478bd9Sstevel@tonic-gate 			free(oxio);
474*7c478bd9Sstevel@tonic-gate 			free(dxio);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 			axio = aio;
477*7c478bd9Sstevel@tonic-gate 			oxio = oio;
478*7c478bd9Sstevel@tonic-gate 			dxio = dio;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 			old_niodevs = niodevs;
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 		if (recno++ > 1) {
484*7c478bd9Sstevel@tonic-gate 			ts = ox.csi.cpu[0] + ox.csi.cpu[1] +
485*7c478bd9Sstevel@tonic-gate 				ox.csi.cpu[2] + ox.csi.cpu[3];
486*7c478bd9Sstevel@tonic-gate 			te = nx.csi.cpu[0] + nx.csi.cpu[1] +
487*7c478bd9Sstevel@tonic-gate 				nx.csi.cpu[2] + nx.csi.cpu[3];
488*7c478bd9Sstevel@tonic-gate 			tdiff = (float)(te - ts);
489*7c478bd9Sstevel@tonic-gate 			sec_diff = tdiff / hz;
490*7c478bd9Sstevel@tonic-gate 			percent = 100.0 / tdiff;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 			/*
493*7c478bd9Sstevel@tonic-gate 			 * If the CPU stat counters have rolled
494*7c478bd9Sstevel@tonic-gate 			 * backward, this is our best indication that
495*7c478bd9Sstevel@tonic-gate 			 * a CPU has been offlined.  We don't have
496*7c478bd9Sstevel@tonic-gate 			 * enough data to compute a sensible delta, so
497*7c478bd9Sstevel@tonic-gate 			 * toss out this interval, but compute the next
498*7c478bd9Sstevel@tonic-gate 			 * interval's delta from these values.
499*7c478bd9Sstevel@tonic-gate 			 */
500*7c478bd9Sstevel@tonic-gate 			if (tdiff <= 0) {
501*7c478bd9Sstevel@tonic-gate 				ox = nx;
502*7c478bd9Sstevel@tonic-gate 				continue;
503*7c478bd9Sstevel@tonic-gate 			}
504*7c478bd9Sstevel@tonic-gate 			update_counters();
505*7c478bd9Sstevel@tonic-gate 			prtopt();
506*7c478bd9Sstevel@tonic-gate 			lines++;
507*7c478bd9Sstevel@tonic-gate 			if (passno == 1)
508*7c478bd9Sstevel@tonic-gate 				totsec_diff += sec_diff;
509*7c478bd9Sstevel@tonic-gate 		}
510*7c478bd9Sstevel@tonic-gate 		ox = nx;		/*  Age the data	*/
511*7c478bd9Sstevel@tonic-gate 		(void) memcpy(oxio, nxio, niodevs * sizeof (iodevinfo_t));
512*7c478bd9Sstevel@tonic-gate 		if (isec > 0)
513*7c478bd9Sstevel@tonic-gate 			while (tnext <= trec)
514*7c478bd9Sstevel@tonic-gate 				tnext += isec;
515*7c478bd9Sstevel@tonic-gate 	}
516*7c478bd9Sstevel@tonic-gate 	/*
517*7c478bd9Sstevel@tonic-gate 	 * After this place, all functions are using niodevs to access the
518*7c478bd9Sstevel@tonic-gate 	 * memory for device details. Here, old_niodevs has the correct value
519*7c478bd9Sstevel@tonic-gate 	 * of memory allocated for storing device information. Since niodevs
520*7c478bd9Sstevel@tonic-gate 	 * doesn't have correct value, sometimes, it was corrupting memory.
521*7c478bd9Sstevel@tonic-gate 	 */
522*7c478bd9Sstevel@tonic-gate 	niodevs = old_niodevs;
523*7c478bd9Sstevel@tonic-gate 	if (lines > 1)
524*7c478bd9Sstevel@tonic-gate 		prtavg();
525*7c478bd9Sstevel@tonic-gate 	(void) memset(&ax, 0, sizeof (ax));	/* Zero out the accumulators. */
526*7c478bd9Sstevel@tonic-gate 	(void) memset(&kmi, 0, sizeof (kmi));
527*7c478bd9Sstevel@tonic-gate 	lines = 0;
528*7c478bd9Sstevel@tonic-gate 	/*
529*7c478bd9Sstevel@tonic-gate 	 * axio will not be allocated if the user specified -e or -s, and
530*7c478bd9Sstevel@tonic-gate 	 * no records in the file fell inside the specified time range.
531*7c478bd9Sstevel@tonic-gate 	 */
532*7c478bd9Sstevel@tonic-gate 	if (axio) {
533*7c478bd9Sstevel@tonic-gate 		(void) memset(axio, 0, niodevs * sizeof (iodevinfo_t));
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate /*
538*7c478bd9Sstevel@tonic-gate  * Print time label routine.
539*7c478bd9Sstevel@tonic-gate  */
540*7c478bd9Sstevel@tonic-gate static void
541*7c478bd9Sstevel@tonic-gate prttim(void)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	curt = localtime(&nx.ts);
544*7c478bd9Sstevel@tonic-gate 	(void) printf("%.2d:%.2d:%.2d", curt->tm_hour, curt->tm_min,
545*7c478bd9Sstevel@tonic-gate 	    curt->tm_sec);
546*7c478bd9Sstevel@tonic-gate 	tabflg = 1;
547*7c478bd9Sstevel@tonic-gate }
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate /*
550*7c478bd9Sstevel@tonic-gate  * Test if 8-spaces to be added routine.
551*7c478bd9Sstevel@tonic-gate  */
552*7c478bd9Sstevel@tonic-gate static void
553*7c478bd9Sstevel@tonic-gate tsttab(void)
554*7c478bd9Sstevel@tonic-gate {
555*7c478bd9Sstevel@tonic-gate 	if (tabflg == 0)
556*7c478bd9Sstevel@tonic-gate 		(void) printf("        ");
557*7c478bd9Sstevel@tonic-gate 	else
558*7c478bd9Sstevel@tonic-gate 		tabflg = 0;
559*7c478bd9Sstevel@tonic-gate }
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate /*
562*7c478bd9Sstevel@tonic-gate  * Print machine identification.
563*7c478bd9Sstevel@tonic-gate  */
564*7c478bd9Sstevel@tonic-gate static void
565*7c478bd9Sstevel@tonic-gate prtmachid(void)
566*7c478bd9Sstevel@tonic-gate {
567*7c478bd9Sstevel@tonic-gate 	struct utsname name;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	(void) uname(&name);
570*7c478bd9Sstevel@tonic-gate 	(void) printf("\n%s %s %s %s %s    %.2d/%.2d/%.4d\n",
571*7c478bd9Sstevel@tonic-gate 	    name.sysname, name.nodename, name.release, name.version,
572*7c478bd9Sstevel@tonic-gate 	    name.machine, curt->tm_mon + 1, curt->tm_mday,
573*7c478bd9Sstevel@tonic-gate 	    curt->tm_year + 1900);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate /*
577*7c478bd9Sstevel@tonic-gate  * Print report heading routine.
578*7c478bd9Sstevel@tonic-gate  */
579*7c478bd9Sstevel@tonic-gate static void
580*7c478bd9Sstevel@tonic-gate prthdg(void)
581*7c478bd9Sstevel@tonic-gate {
582*7c478bd9Sstevel@tonic-gate 	int	jj = 0;
583*7c478bd9Sstevel@tonic-gate 	char	ccc;
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
586*7c478bd9Sstevel@tonic-gate 	prttim();
587*7c478bd9Sstevel@tonic-gate 	while ((ccc = fopt[jj++]) != NULL) {
588*7c478bd9Sstevel@tonic-gate 		tsttab();
589*7c478bd9Sstevel@tonic-gate 		switch (ccc) {
590*7c478bd9Sstevel@tonic-gate 		    case 'u':
591*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s\n",
592*7c478bd9Sstevel@tonic-gate 				"%usr",
593*7c478bd9Sstevel@tonic-gate 				"%sys",
594*7c478bd9Sstevel@tonic-gate 				"%wio",
595*7c478bd9Sstevel@tonic-gate 				"%idle");
596*7c478bd9Sstevel@tonic-gate 			break;
597*7c478bd9Sstevel@tonic-gate 		    case 'b':
598*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s %7s %7s\n",
599*7c478bd9Sstevel@tonic-gate 				"bread/s",
600*7c478bd9Sstevel@tonic-gate 				"lread/s",
601*7c478bd9Sstevel@tonic-gate 				"%rcache",
602*7c478bd9Sstevel@tonic-gate 				"bwrit/s",
603*7c478bd9Sstevel@tonic-gate 				"lwrit/s",
604*7c478bd9Sstevel@tonic-gate 				"%wcache",
605*7c478bd9Sstevel@tonic-gate 				"pread/s",
606*7c478bd9Sstevel@tonic-gate 				"pwrit/s");
607*7c478bd9Sstevel@tonic-gate 			break;
608*7c478bd9Sstevel@tonic-gate 		    case 'd':
609*7c478bd9Sstevel@tonic-gate 			(void) printf("   %-8.8s    %7s %7s %7s %7s %7s %7s\n",
610*7c478bd9Sstevel@tonic-gate 				"device",
611*7c478bd9Sstevel@tonic-gate 				"%busy",
612*7c478bd9Sstevel@tonic-gate 				"avque",
613*7c478bd9Sstevel@tonic-gate 				"r+w/s",
614*7c478bd9Sstevel@tonic-gate 				"blks/s",
615*7c478bd9Sstevel@tonic-gate 				"avwait",
616*7c478bd9Sstevel@tonic-gate 				"avserv");
617*7c478bd9Sstevel@tonic-gate 			break;
618*7c478bd9Sstevel@tonic-gate 		    case 'y':
619*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s\n",
620*7c478bd9Sstevel@tonic-gate 				"rawch/s",
621*7c478bd9Sstevel@tonic-gate 				"canch/s",
622*7c478bd9Sstevel@tonic-gate 				"outch/s",
623*7c478bd9Sstevel@tonic-gate 				"rcvin/s",
624*7c478bd9Sstevel@tonic-gate 				"xmtin/s",
625*7c478bd9Sstevel@tonic-gate 				"mdmin/s");
626*7c478bd9Sstevel@tonic-gate 			break;
627*7c478bd9Sstevel@tonic-gate 		    case 'c':
628*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s %7s\n",
629*7c478bd9Sstevel@tonic-gate 				"scall/s",
630*7c478bd9Sstevel@tonic-gate 				"sread/s",
631*7c478bd9Sstevel@tonic-gate 				"swrit/s",
632*7c478bd9Sstevel@tonic-gate 				"fork/s",
633*7c478bd9Sstevel@tonic-gate 				"exec/s",
634*7c478bd9Sstevel@tonic-gate 				"rchar/s",
635*7c478bd9Sstevel@tonic-gate 				"wchar/s");
636*7c478bd9Sstevel@tonic-gate 			break;
637*7c478bd9Sstevel@tonic-gate 		    case 'w':
638*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s\n",
639*7c478bd9Sstevel@tonic-gate 				"swpin/s",
640*7c478bd9Sstevel@tonic-gate 				"bswin/s",
641*7c478bd9Sstevel@tonic-gate 				"swpot/s",
642*7c478bd9Sstevel@tonic-gate 				"bswot/s",
643*7c478bd9Sstevel@tonic-gate 				"pswch/s");
644*7c478bd9Sstevel@tonic-gate 			break;
645*7c478bd9Sstevel@tonic-gate 		    case 'a':
646*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s\n",
647*7c478bd9Sstevel@tonic-gate 				"iget/s",
648*7c478bd9Sstevel@tonic-gate 				"namei/s",
649*7c478bd9Sstevel@tonic-gate 				"dirbk/s");
650*7c478bd9Sstevel@tonic-gate 			break;
651*7c478bd9Sstevel@tonic-gate 		    case 'q':
652*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s\n",
653*7c478bd9Sstevel@tonic-gate 				"runq-sz",
654*7c478bd9Sstevel@tonic-gate 				"%runocc",
655*7c478bd9Sstevel@tonic-gate 				"swpq-sz",
656*7c478bd9Sstevel@tonic-gate 				"%swpocc");
657*7c478bd9Sstevel@tonic-gate 			break;
658*7c478bd9Sstevel@tonic-gate 		    case 'v':
659*7c478bd9Sstevel@tonic-gate 			(void) printf("  %s  %s  %s   %s\n",
660*7c478bd9Sstevel@tonic-gate 				"proc-sz    ov",
661*7c478bd9Sstevel@tonic-gate 				"inod-sz    ov",
662*7c478bd9Sstevel@tonic-gate 				"file-sz    ov",
663*7c478bd9Sstevel@tonic-gate 				"lock-sz");
664*7c478bd9Sstevel@tonic-gate 			break;
665*7c478bd9Sstevel@tonic-gate 		    case 'm':
666*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s\n",
667*7c478bd9Sstevel@tonic-gate 				"msg/s",
668*7c478bd9Sstevel@tonic-gate 				"sema/s");
669*7c478bd9Sstevel@tonic-gate 			break;
670*7c478bd9Sstevel@tonic-gate 		    case 'p':
671*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %7s %7s %7s %7s\n",
672*7c478bd9Sstevel@tonic-gate 				"atch/s",
673*7c478bd9Sstevel@tonic-gate 				"pgin/s",
674*7c478bd9Sstevel@tonic-gate 				"ppgin/s",
675*7c478bd9Sstevel@tonic-gate 				"pflt/s",
676*7c478bd9Sstevel@tonic-gate 				"vflt/s",
677*7c478bd9Sstevel@tonic-gate 				"slock/s");
678*7c478bd9Sstevel@tonic-gate 			break;
679*7c478bd9Sstevel@tonic-gate 		    case 'g':
680*7c478bd9Sstevel@tonic-gate 			(void) printf(" %8s %8s %8s %8s %8s\n",
681*7c478bd9Sstevel@tonic-gate 				"pgout/s",
682*7c478bd9Sstevel@tonic-gate 				"ppgout/s",
683*7c478bd9Sstevel@tonic-gate 				"pgfree/s",
684*7c478bd9Sstevel@tonic-gate 				"pgscan/s",
685*7c478bd9Sstevel@tonic-gate 				"%ufs_ipf");
686*7c478bd9Sstevel@tonic-gate 			break;
687*7c478bd9Sstevel@tonic-gate 		    case 'r':
688*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %8s\n",
689*7c478bd9Sstevel@tonic-gate 				"freemem",
690*7c478bd9Sstevel@tonic-gate 				"freeswap");
691*7c478bd9Sstevel@tonic-gate 			break;
692*7c478bd9Sstevel@tonic-gate 		    case 'k':
693*7c478bd9Sstevel@tonic-gate 			(void) printf(" %7s %7s %5s %7s %7s %5s %11s %5s\n",
694*7c478bd9Sstevel@tonic-gate 				"sml_mem",
695*7c478bd9Sstevel@tonic-gate 				"alloc",
696*7c478bd9Sstevel@tonic-gate 				"fail",
697*7c478bd9Sstevel@tonic-gate 				"lg_mem",
698*7c478bd9Sstevel@tonic-gate 				"alloc",
699*7c478bd9Sstevel@tonic-gate 				"fail",
700*7c478bd9Sstevel@tonic-gate 				"ovsz_alloc",
701*7c478bd9Sstevel@tonic-gate 				"fail");
702*7c478bd9Sstevel@tonic-gate 			break;
703*7c478bd9Sstevel@tonic-gate 		}
704*7c478bd9Sstevel@tonic-gate 	}
705*7c478bd9Sstevel@tonic-gate 	if (jj > 2 || do_disk)
706*7c478bd9Sstevel@tonic-gate 		(void) printf("\n");
707*7c478bd9Sstevel@tonic-gate }
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate /*
710*7c478bd9Sstevel@tonic-gate  * compute deltas and update accumulators
711*7c478bd9Sstevel@tonic-gate  */
712*7c478bd9Sstevel@tonic-gate static void
713*7c478bd9Sstevel@tonic-gate update_counters(void)
714*7c478bd9Sstevel@tonic-gate {
715*7c478bd9Sstevel@tonic-gate 	int i;
716*7c478bd9Sstevel@tonic-gate 	iodevinfo_t *nio, *oio, *aio, *dio;
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	ulong_delta((ulong_t *)&nx.csi, (ulong_t *)&ox.csi,
719*7c478bd9Sstevel@tonic-gate 		(ulong_t *)&dx.csi, (ulong_t *)&ax.csi, 0, sizeof (ax.csi));
720*7c478bd9Sstevel@tonic-gate 	ulong_delta((ulong_t *)&nx.si, (ulong_t *)&ox.si,
721*7c478bd9Sstevel@tonic-gate 		(ulong_t *)&dx.si, (ulong_t *)&ax.si, 0, sizeof (ax.si));
722*7c478bd9Sstevel@tonic-gate 	ulong_delta((ulong_t *)&nx.cvmi, (ulong_t *)&ox.cvmi,
723*7c478bd9Sstevel@tonic-gate 		(ulong_t *)&dx.cvmi, (ulong_t *)&ax.cvmi, 0,
724*7c478bd9Sstevel@tonic-gate 		sizeof (ax.cvmi));
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	ax.vmi.freemem += dx.vmi.freemem = nx.vmi.freemem - ox.vmi.freemem;
727*7c478bd9Sstevel@tonic-gate 	ax.vmi.swap_avail += dx.vmi.swap_avail =
728*7c478bd9Sstevel@tonic-gate 		nx.vmi.swap_avail - ox.vmi.swap_avail;
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	nio = nxio;
731*7c478bd9Sstevel@tonic-gate 	oio = oxio;
732*7c478bd9Sstevel@tonic-gate 	aio = axio;
733*7c478bd9Sstevel@tonic-gate 	dio = dxio;
734*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < niodevs; i++) {
735*7c478bd9Sstevel@tonic-gate 		aio->kios.wlastupdate += dio->kios.wlastupdate
736*7c478bd9Sstevel@tonic-gate 			= nio->kios.wlastupdate - oio->kios.wlastupdate;
737*7c478bd9Sstevel@tonic-gate 		aio->kios.reads += dio->kios.reads
738*7c478bd9Sstevel@tonic-gate 			= nio->kios.reads - oio->kios.reads;
739*7c478bd9Sstevel@tonic-gate 		aio->kios.writes += dio->kios.writes
740*7c478bd9Sstevel@tonic-gate 			= nio->kios.writes - oio->kios.writes;
741*7c478bd9Sstevel@tonic-gate 		aio->kios.nread += dio->kios.nread
742*7c478bd9Sstevel@tonic-gate 			= nio->kios.nread - oio->kios.nread;
743*7c478bd9Sstevel@tonic-gate 		aio->kios.nwritten += dio->kios.nwritten
744*7c478bd9Sstevel@tonic-gate 			= nio->kios.nwritten - oio->kios.nwritten;
745*7c478bd9Sstevel@tonic-gate 		aio->kios.wlentime += dio->kios.wlentime
746*7c478bd9Sstevel@tonic-gate 			= nio->kios.wlentime - oio->kios.wlentime;
747*7c478bd9Sstevel@tonic-gate 		aio->kios.rlentime += dio->kios.rlentime
748*7c478bd9Sstevel@tonic-gate 			= nio->kios.rlentime - oio->kios.rlentime;
749*7c478bd9Sstevel@tonic-gate 		aio->kios.wtime += dio->kios.wtime
750*7c478bd9Sstevel@tonic-gate 			= nio->kios.wtime - oio->kios.wtime;
751*7c478bd9Sstevel@tonic-gate 		aio->kios.rtime += dio->kios.rtime
752*7c478bd9Sstevel@tonic-gate 			= nio->kios.rtime - oio->kios.rtime;
753*7c478bd9Sstevel@tonic-gate 		nio++;
754*7c478bd9Sstevel@tonic-gate 		oio++;
755*7c478bd9Sstevel@tonic-gate 		aio++;
756*7c478bd9Sstevel@tonic-gate 		dio++;
757*7c478bd9Sstevel@tonic-gate 	}
758*7c478bd9Sstevel@tonic-gate }
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate static void
761*7c478bd9Sstevel@tonic-gate prt_u_opt(struct sa *xx)
762*7c478bd9Sstevel@tonic-gate {
763*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.0f\n",
764*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[1] * percent,
765*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[2] * percent,
766*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[3] * percent,
767*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.cpu[0] * percent);
768*7c478bd9Sstevel@tonic-gate }
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate static void
771*7c478bd9Sstevel@tonic-gate prt_b_opt(struct sa *xx)
772*7c478bd9Sstevel@tonic-gate {
773*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n",
774*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.bread / sec_diff,
775*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.lread / sec_diff,
776*7c478bd9Sstevel@tonic-gate 		freq((float)xx->csi.lread, (float)xx->csi.bread),
777*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.bwrite / sec_diff,
778*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.lwrite / sec_diff,
779*7c478bd9Sstevel@tonic-gate 		freq((float)xx->csi.lwrite, (float)xx->csi.bwrite),
780*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.phread / sec_diff,
781*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.phwrite / sec_diff);
782*7c478bd9Sstevel@tonic-gate }
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate static void
785*7c478bd9Sstevel@tonic-gate prt_d_opt(int ii, iodevinfo_t *xio)
786*7c478bd9Sstevel@tonic-gate {
787*7c478bd9Sstevel@tonic-gate 	double etime, hr_etime, tps, avq, avs;
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	tsttab();
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	hr_etime = (double)xio[ii].kios.wlastupdate;
792*7c478bd9Sstevel@tonic-gate 	if (hr_etime == 0.0)
793*7c478bd9Sstevel@tonic-gate 		hr_etime = (double)NANOSEC;
794*7c478bd9Sstevel@tonic-gate 	etime = hr_etime / (double)NANOSEC;
795*7c478bd9Sstevel@tonic-gate 	tps = (double)(xio[ii].kios.reads + xio[ii].kios.writes) / etime;
796*7c478bd9Sstevel@tonic-gate 	avq = (double)xio[ii].kios.wlentime / hr_etime;
797*7c478bd9Sstevel@tonic-gate 	avs = (double)xio[ii].kios.rlentime / hr_etime;
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 	(void) printf("   %-8.8s    ", nxio[ii].ks.ks_name);
800*7c478bd9Sstevel@tonic-gate 	(void) printf("%7.0f %7.1f %7.0f %7.0f %7.1f %7.1f\n",
801*7c478bd9Sstevel@tonic-gate 		(double)xio[ii].kios.rtime * 100.0 / hr_etime,
802*7c478bd9Sstevel@tonic-gate 		avq + avs,
803*7c478bd9Sstevel@tonic-gate 		tps,
804*7c478bd9Sstevel@tonic-gate 		BLKS(xio[ii].kios.nread + xio[ii].kios.nwritten) / etime,
805*7c478bd9Sstevel@tonic-gate 		(tps > 0 ? avq / tps * 1000.0 : 0.0),
806*7c478bd9Sstevel@tonic-gate 		(tps > 0 ? avs / tps * 1000.0 : 0.0));
807*7c478bd9Sstevel@tonic-gate }
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate static void
810*7c478bd9Sstevel@tonic-gate prt_y_opt(struct sa *xx)
811*7c478bd9Sstevel@tonic-gate {
812*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.0f %7.0f %7.0f\n",
813*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.rawch / sec_diff,
814*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.canch / sec_diff,
815*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.outch / sec_diff,
816*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.rcvint / sec_diff,
817*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.xmtint / sec_diff,
818*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.mdmint / sec_diff);
819*7c478bd9Sstevel@tonic-gate }
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate static void
822*7c478bd9Sstevel@tonic-gate prt_c_opt(struct sa *xx)
823*7c478bd9Sstevel@tonic-gate {
824*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f %7.2f %7.2f %7.0f %7.0f\n",
825*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.syscall / sec_diff,
826*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.sysread / sec_diff,
827*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.syswrite / sec_diff,
828*7c478bd9Sstevel@tonic-gate 		(float)(xx->csi.sysfork + xx->csi.sysvfork) / sec_diff,
829*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.sysexec / sec_diff,
830*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.readch / sec_diff,
831*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.writech / sec_diff);
832*7c478bd9Sstevel@tonic-gate }
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate static void
835*7c478bd9Sstevel@tonic-gate prt_w_opt(struct sa *xx)
836*7c478bd9Sstevel@tonic-gate {
837*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.2f %7.1f %7.2f %7.1f %7.0f\n",
838*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.swapin / sec_diff,
839*7c478bd9Sstevel@tonic-gate 		(float)PGTOBLK(xx->cvmi.pgswapin) / sec_diff,
840*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.swapout / sec_diff,
841*7c478bd9Sstevel@tonic-gate 		(float)PGTOBLK(xx->cvmi.pgswapout) / sec_diff,
842*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.pswitch / sec_diff);
843*7c478bd9Sstevel@tonic-gate }
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate static void
846*7c478bd9Sstevel@tonic-gate prt_a_opt(struct sa *xx)
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %7.0f %7.0f\n",
849*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.ufsiget / sec_diff,
850*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.namei / sec_diff,
851*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.ufsdirblk / sec_diff);
852*7c478bd9Sstevel@tonic-gate }
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate static void
855*7c478bd9Sstevel@tonic-gate prt_q_opt(struct sa *xx)
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	if (xx->si.runocc == 0)
858*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f", 0., 0.);
859*7c478bd9Sstevel@tonic-gate 	else {
860*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f",
861*7c478bd9Sstevel@tonic-gate 		    (float)xx->si.runque / (float)xx->si.runocc,
862*7c478bd9Sstevel@tonic-gate 		    (float)xx->si.runocc / sec_diff * 100.0);
863*7c478bd9Sstevel@tonic-gate 	}
864*7c478bd9Sstevel@tonic-gate 	if (xx->si.swpocc == 0)
865*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f\n", 0., 0.);
866*7c478bd9Sstevel@tonic-gate 	else {
867*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7.1f %7.0f\n",
868*7c478bd9Sstevel@tonic-gate 		    (float)xx->si.swpque / (float)xx->si.swpocc,
869*7c478bd9Sstevel@tonic-gate 		    (float)xx->si.swpocc / sec_diff * 100.0);
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate }
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate static void
874*7c478bd9Sstevel@tonic-gate prt_v_opt(struct sa *xx)
875*7c478bd9Sstevel@tonic-gate {
876*7c478bd9Sstevel@tonic-gate 	(void) printf(" %4lu/%-4lu %4u %4lu/%-4lu %4u %4lu/%-4lu "
877*7c478bd9Sstevel@tonic-gate 	    "%4u %4lu/%-4lu\n",
878*7c478bd9Sstevel@tonic-gate 	    nx.szproc, nx.mszproc, xx->csi.procovf,
879*7c478bd9Sstevel@tonic-gate 	    nx.szinode, nx.mszinode, xx->csi.inodeovf,
880*7c478bd9Sstevel@tonic-gate 	    nx.szfile, nx.mszfile, xx->csi.fileovf,
881*7c478bd9Sstevel@tonic-gate 	    nx.szlckr, nx.mszlckr);
882*7c478bd9Sstevel@tonic-gate }
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate static void
885*7c478bd9Sstevel@tonic-gate prt_m_opt(struct sa *xx)
886*7c478bd9Sstevel@tonic-gate {
887*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.2f %7.2f\n",
888*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.msg / sec_diff,
889*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.sema / sec_diff);
890*7c478bd9Sstevel@tonic-gate }
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate static void
893*7c478bd9Sstevel@tonic-gate prt_p_opt(struct sa *xx)
894*7c478bd9Sstevel@tonic-gate {
895*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
896*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgfrec / sec_diff,
897*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgin / sec_diff,
898*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgpgin / sec_diff,
899*7c478bd9Sstevel@tonic-gate 		(float)(xx->cvmi.prot_fault + xx->cvmi.cow_fault) / sec_diff,
900*7c478bd9Sstevel@tonic-gate 		(float)(xx->cvmi.hat_fault + xx->cvmi.as_fault) / sec_diff,
901*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.softlock / sec_diff);
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate static void
905*7c478bd9Sstevel@tonic-gate prt_g_opt(struct sa *xx)
906*7c478bd9Sstevel@tonic-gate {
907*7c478bd9Sstevel@tonic-gate 	(void) printf(" %8.2f %8.2f %8.2f %8.2f %8.2f\n",
908*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgout / sec_diff,
909*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.pgpgout / sec_diff,
910*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.dfree / sec_diff,
911*7c478bd9Sstevel@tonic-gate 		(float)xx->cvmi.scan / sec_diff,
912*7c478bd9Sstevel@tonic-gate 		(float)xx->csi.ufsipage * 100.0 /
913*7c478bd9Sstevel@tonic-gate 			denom((float)xx->csi.ufsipage +
914*7c478bd9Sstevel@tonic-gate 			(float)xx->csi.ufsinopage));
915*7c478bd9Sstevel@tonic-gate }
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate static void
918*7c478bd9Sstevel@tonic-gate prt_r_opt(struct sa *xx)
919*7c478bd9Sstevel@tonic-gate {
920*7c478bd9Sstevel@tonic-gate 	(void) printf(" %7.0f %8.0f\n",
921*7c478bd9Sstevel@tonic-gate 		(double)xx->vmi.freemem / sec_diff,
922*7c478bd9Sstevel@tonic-gate 		(double)PGTOBLK(xx->vmi.swap_avail) / sec_diff);
923*7c478bd9Sstevel@tonic-gate }
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate static void
926*7c478bd9Sstevel@tonic-gate prt_k_opt(struct sa *xx, int n)
927*7c478bd9Sstevel@tonic-gate {
928*7c478bd9Sstevel@tonic-gate 	if (n != 1) {
929*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f"
930*7c478bd9Sstevel@tonic-gate 		    " %5.0f\n",
931*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_mem[KMEM_SMALL] / n,
932*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_alloc[KMEM_SMALL] / n,
933*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_fail[KMEM_SMALL] / n,
934*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_mem[KMEM_LARGE] / n,
935*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_alloc[KMEM_LARGE] / n,
936*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_fail[KMEM_LARGE] / n,
937*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_alloc[KMEM_OSIZE] / n,
938*7c478bd9Sstevel@tonic-gate 		    (float)kmi.km_fail[KMEM_OSIZE] / n);
939*7c478bd9Sstevel@tonic-gate 	} else {
940*7c478bd9Sstevel@tonic-gate 		/*
941*7c478bd9Sstevel@tonic-gate 		 * If we are not reporting averages, use the read values
942*7c478bd9Sstevel@tonic-gate 		 * directly.
943*7c478bd9Sstevel@tonic-gate 		 */
944*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7.0f %7.0f %5.0f %7.0f %7.0f %5.0f %11.0f"
945*7c478bd9Sstevel@tonic-gate 		    " %5.0f\n",
946*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_mem[KMEM_SMALL],
947*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_alloc[KMEM_SMALL],
948*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_fail[KMEM_SMALL],
949*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_mem[KMEM_LARGE],
950*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_alloc[KMEM_LARGE],
951*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_fail[KMEM_LARGE],
952*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_alloc[KMEM_OSIZE],
953*7c478bd9Sstevel@tonic-gate 		    (float)xx->kmi.km_fail[KMEM_OSIZE]);
954*7c478bd9Sstevel@tonic-gate 	}
955*7c478bd9Sstevel@tonic-gate }
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate /*
958*7c478bd9Sstevel@tonic-gate  * Print options routine.
959*7c478bd9Sstevel@tonic-gate  */
960*7c478bd9Sstevel@tonic-gate static void
961*7c478bd9Sstevel@tonic-gate prtopt(void)
962*7c478bd9Sstevel@tonic-gate {
963*7c478bd9Sstevel@tonic-gate 	int	ii, jj = 0;
964*7c478bd9Sstevel@tonic-gate 	char	ccc;
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	prttim();
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	while ((ccc = fopt[jj++]) != NULL) {
969*7c478bd9Sstevel@tonic-gate 		if (ccc != 'd')
970*7c478bd9Sstevel@tonic-gate 			tsttab();
971*7c478bd9Sstevel@tonic-gate 		switch (ccc) {
972*7c478bd9Sstevel@tonic-gate 		    case 'u':
973*7c478bd9Sstevel@tonic-gate 			prt_u_opt(&dx);
974*7c478bd9Sstevel@tonic-gate 			break;
975*7c478bd9Sstevel@tonic-gate 		    case 'b':
976*7c478bd9Sstevel@tonic-gate 			prt_b_opt(&dx);
977*7c478bd9Sstevel@tonic-gate 			break;
978*7c478bd9Sstevel@tonic-gate 		    case 'd':
979*7c478bd9Sstevel@tonic-gate 			for (ii = 0; ii < niodevs; ii++)
980*7c478bd9Sstevel@tonic-gate 				prt_d_opt(ii, dxio);
981*7c478bd9Sstevel@tonic-gate 			break;
982*7c478bd9Sstevel@tonic-gate 		    case 'y':
983*7c478bd9Sstevel@tonic-gate 			prt_y_opt(&dx);
984*7c478bd9Sstevel@tonic-gate 			break;
985*7c478bd9Sstevel@tonic-gate 		    case 'c':
986*7c478bd9Sstevel@tonic-gate 			prt_c_opt(&dx);
987*7c478bd9Sstevel@tonic-gate 			break;
988*7c478bd9Sstevel@tonic-gate 		    case 'w':
989*7c478bd9Sstevel@tonic-gate 			prt_w_opt(&dx);
990*7c478bd9Sstevel@tonic-gate 			break;
991*7c478bd9Sstevel@tonic-gate 		    case 'a':
992*7c478bd9Sstevel@tonic-gate 			prt_a_opt(&dx);
993*7c478bd9Sstevel@tonic-gate 			break;
994*7c478bd9Sstevel@tonic-gate 		    case 'q':
995*7c478bd9Sstevel@tonic-gate 			prt_q_opt(&dx);
996*7c478bd9Sstevel@tonic-gate 			break;
997*7c478bd9Sstevel@tonic-gate 		    case 'v':
998*7c478bd9Sstevel@tonic-gate 			prt_v_opt(&dx);
999*7c478bd9Sstevel@tonic-gate 			break;
1000*7c478bd9Sstevel@tonic-gate 		    case 'm':
1001*7c478bd9Sstevel@tonic-gate 			prt_m_opt(&dx);
1002*7c478bd9Sstevel@tonic-gate 			break;
1003*7c478bd9Sstevel@tonic-gate 		    case 'p':
1004*7c478bd9Sstevel@tonic-gate 			prt_p_opt(&dx);
1005*7c478bd9Sstevel@tonic-gate 			break;
1006*7c478bd9Sstevel@tonic-gate 		    case 'g':
1007*7c478bd9Sstevel@tonic-gate 			prt_g_opt(&dx);
1008*7c478bd9Sstevel@tonic-gate 			break;
1009*7c478bd9Sstevel@tonic-gate 		    case 'r':
1010*7c478bd9Sstevel@tonic-gate 			prt_r_opt(&dx);
1011*7c478bd9Sstevel@tonic-gate 			break;
1012*7c478bd9Sstevel@tonic-gate 		    case 'k':
1013*7c478bd9Sstevel@tonic-gate 			prt_k_opt(&nx, 1);
1014*7c478bd9Sstevel@tonic-gate 			/*
1015*7c478bd9Sstevel@tonic-gate 			 * To avoid overflow, copy the data from the sa record
1016*7c478bd9Sstevel@tonic-gate 			 * into a struct kmeminfo_l which has members with
1017*7c478bd9Sstevel@tonic-gate 			 * larger data types.
1018*7c478bd9Sstevel@tonic-gate 			 */
1019*7c478bd9Sstevel@tonic-gate 			kmi.km_mem[KMEM_SMALL] += nx.kmi.km_mem[KMEM_SMALL];
1020*7c478bd9Sstevel@tonic-gate 			kmi.km_alloc[KMEM_SMALL] += nx.kmi.km_alloc[KMEM_SMALL];
1021*7c478bd9Sstevel@tonic-gate 			kmi.km_fail[KMEM_SMALL] += nx.kmi.km_fail[KMEM_SMALL];
1022*7c478bd9Sstevel@tonic-gate 			kmi.km_mem[KMEM_LARGE] += nx.kmi.km_mem[KMEM_LARGE];
1023*7c478bd9Sstevel@tonic-gate 			kmi.km_alloc[KMEM_LARGE] += nx.kmi.km_alloc[KMEM_LARGE];
1024*7c478bd9Sstevel@tonic-gate 			kmi.km_fail[KMEM_LARGE] += nx.kmi.km_fail[KMEM_LARGE];
1025*7c478bd9Sstevel@tonic-gate 			kmi.km_alloc[KMEM_OSIZE] += nx.kmi.km_alloc[KMEM_OSIZE];
1026*7c478bd9Sstevel@tonic-gate 			kmi.km_fail[KMEM_OSIZE] += nx.kmi.km_fail[KMEM_OSIZE];
1027*7c478bd9Sstevel@tonic-gate 			break;
1028*7c478bd9Sstevel@tonic-gate 		}
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 	if (jj > 2 || do_disk)
1031*7c478bd9Sstevel@tonic-gate 		(void) printf("\n");
1032*7c478bd9Sstevel@tonic-gate 	if (realtime)
1033*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
1034*7c478bd9Sstevel@tonic-gate }
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate /*
1037*7c478bd9Sstevel@tonic-gate  * Print average routine.
1038*7c478bd9Sstevel@tonic-gate  */
1039*7c478bd9Sstevel@tonic-gate static void
1040*7c478bd9Sstevel@tonic-gate prtavg(void)
1041*7c478bd9Sstevel@tonic-gate {
1042*7c478bd9Sstevel@tonic-gate 	int	ii, jj = 0;
1043*7c478bd9Sstevel@tonic-gate 	char	ccc;
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 	tdiff = ax.csi.cpu[0] + ax.csi.cpu[1] + ax.csi.cpu[2] + ax.csi.cpu[3];
1046*7c478bd9Sstevel@tonic-gate 	if (tdiff <= 0.0)
1047*7c478bd9Sstevel@tonic-gate 		return;
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	sec_diff = tdiff / hz;
1050*7c478bd9Sstevel@tonic-gate 	percent = 100.0 / tdiff;
1051*7c478bd9Sstevel@tonic-gate 	(void) printf("\n");
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	while ((ccc = fopt[jj++]) != NULL) {
1054*7c478bd9Sstevel@tonic-gate 		if (ccc != 'v')
1055*7c478bd9Sstevel@tonic-gate 			(void) printf("Average ");
1056*7c478bd9Sstevel@tonic-gate 		switch (ccc) {
1057*7c478bd9Sstevel@tonic-gate 		    case 'u':
1058*7c478bd9Sstevel@tonic-gate 			prt_u_opt(&ax);
1059*7c478bd9Sstevel@tonic-gate 			break;
1060*7c478bd9Sstevel@tonic-gate 		    case 'b':
1061*7c478bd9Sstevel@tonic-gate 			prt_b_opt(&ax);
1062*7c478bd9Sstevel@tonic-gate 			break;
1063*7c478bd9Sstevel@tonic-gate 		    case 'd':
1064*7c478bd9Sstevel@tonic-gate 			tabflg = 1;
1065*7c478bd9Sstevel@tonic-gate 			for (ii = 0; ii < niodevs; ii++)
1066*7c478bd9Sstevel@tonic-gate 				prt_d_opt(ii, axio);
1067*7c478bd9Sstevel@tonic-gate 			break;
1068*7c478bd9Sstevel@tonic-gate 		    case 'y':
1069*7c478bd9Sstevel@tonic-gate 			prt_y_opt(&ax);
1070*7c478bd9Sstevel@tonic-gate 			break;
1071*7c478bd9Sstevel@tonic-gate 		    case 'c':
1072*7c478bd9Sstevel@tonic-gate 			prt_c_opt(&ax);
1073*7c478bd9Sstevel@tonic-gate 			break;
1074*7c478bd9Sstevel@tonic-gate 		    case 'w':
1075*7c478bd9Sstevel@tonic-gate 			prt_w_opt(&ax);
1076*7c478bd9Sstevel@tonic-gate 			break;
1077*7c478bd9Sstevel@tonic-gate 		    case 'a':
1078*7c478bd9Sstevel@tonic-gate 			prt_a_opt(&ax);
1079*7c478bd9Sstevel@tonic-gate 			break;
1080*7c478bd9Sstevel@tonic-gate 		    case 'q':
1081*7c478bd9Sstevel@tonic-gate 			prt_q_opt(&ax);
1082*7c478bd9Sstevel@tonic-gate 			break;
1083*7c478bd9Sstevel@tonic-gate 		    case 'v':
1084*7c478bd9Sstevel@tonic-gate 			break;
1085*7c478bd9Sstevel@tonic-gate 		    case 'm':
1086*7c478bd9Sstevel@tonic-gate 			prt_m_opt(&ax);
1087*7c478bd9Sstevel@tonic-gate 			break;
1088*7c478bd9Sstevel@tonic-gate 		    case 'p':
1089*7c478bd9Sstevel@tonic-gate 			prt_p_opt(&ax);
1090*7c478bd9Sstevel@tonic-gate 			break;
1091*7c478bd9Sstevel@tonic-gate 		    case 'g':
1092*7c478bd9Sstevel@tonic-gate 			prt_g_opt(&ax);
1093*7c478bd9Sstevel@tonic-gate 			break;
1094*7c478bd9Sstevel@tonic-gate 		    case 'r':
1095*7c478bd9Sstevel@tonic-gate 			prt_r_opt(&ax);
1096*7c478bd9Sstevel@tonic-gate 			break;
1097*7c478bd9Sstevel@tonic-gate 		    case 'k':
1098*7c478bd9Sstevel@tonic-gate 			prt_k_opt(&ax, lines);
1099*7c478bd9Sstevel@tonic-gate 			break;
1100*7c478bd9Sstevel@tonic-gate 		}
1101*7c478bd9Sstevel@tonic-gate 	}
1102*7c478bd9Sstevel@tonic-gate }
1103*7c478bd9Sstevel@tonic-gate 
1104*7c478bd9Sstevel@tonic-gate static void
1105*7c478bd9Sstevel@tonic-gate ulong_delta(ulong_t *new, ulong_t *old, ulong_t *delta, ulong_t *accum,
1106*7c478bd9Sstevel@tonic-gate 	int begin, int end)
1107*7c478bd9Sstevel@tonic-gate {
1108*7c478bd9Sstevel@tonic-gate 	int i;
1109*7c478bd9Sstevel@tonic-gate 	ulong_t *np, *op, *dp, *ap;
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 	np = new;
1112*7c478bd9Sstevel@tonic-gate 	op = old;
1113*7c478bd9Sstevel@tonic-gate 	dp = delta;
1114*7c478bd9Sstevel@tonic-gate 	ap = accum;
1115*7c478bd9Sstevel@tonic-gate 	for (i = begin; i < end; i += sizeof (ulong_t))
1116*7c478bd9Sstevel@tonic-gate 		*ap++ += *dp++ = *np++ - *op++;
1117*7c478bd9Sstevel@tonic-gate }
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate /*
1120*7c478bd9Sstevel@tonic-gate  * used to prevent zero denominators
1121*7c478bd9Sstevel@tonic-gate  */
1122*7c478bd9Sstevel@tonic-gate static float
1123*7c478bd9Sstevel@tonic-gate denom(float x)
1124*7c478bd9Sstevel@tonic-gate {
1125*7c478bd9Sstevel@tonic-gate 	return ((x > 0.5) ? x : 1.0);
1126*7c478bd9Sstevel@tonic-gate }
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate /*
1129*7c478bd9Sstevel@tonic-gate  * a little calculation that comes up often when computing frequency
1130*7c478bd9Sstevel@tonic-gate  * of one operation relative to another
1131*7c478bd9Sstevel@tonic-gate  */
1132*7c478bd9Sstevel@tonic-gate static float
1133*7c478bd9Sstevel@tonic-gate freq(float x, float y)
1134*7c478bd9Sstevel@tonic-gate {
1135*7c478bd9Sstevel@tonic-gate 	return ((x < 0.5) ? 100.0 : (x - y) / x * 100.0);
1136*7c478bd9Sstevel@tonic-gate }
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate static void
1139*7c478bd9Sstevel@tonic-gate usage(void)
1140*7c478bd9Sstevel@tonic-gate {
1141*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
1142*7c478bd9Sstevel@tonic-gate 	    "usage: sar [-ubdycwaqvmpgrkA][-o file] t [n]\n"
1143*7c478bd9Sstevel@tonic-gate 	    "\tsar [-ubdycwaqvmpgrkA] [-s hh:mm][-e hh:mm][-i ss][-f file]\n");
1144*7c478bd9Sstevel@tonic-gate }
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate static void
1147*7c478bd9Sstevel@tonic-gate fail(int do_perror, char *message, ...)
1148*7c478bd9Sstevel@tonic-gate {
1149*7c478bd9Sstevel@tonic-gate 	va_list args;
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate 	va_start(args, message);
1152*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "sar: ");
1153*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, message, args);
1154*7c478bd9Sstevel@tonic-gate 	va_end(args);
1155*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n");
1156*7c478bd9Sstevel@tonic-gate 	switch (do_perror) {
1157*7c478bd9Sstevel@tonic-gate 	case 0:				/* usage message */
1158*7c478bd9Sstevel@tonic-gate 		usage();
1159*7c478bd9Sstevel@tonic-gate 		break;
1160*7c478bd9Sstevel@tonic-gate 	case 1:				/* perror output */
1161*7c478bd9Sstevel@tonic-gate 		perror("");
1162*7c478bd9Sstevel@tonic-gate 		break;
1163*7c478bd9Sstevel@tonic-gate 	case 2:				/* no further output */
1164*7c478bd9Sstevel@tonic-gate 		break;
1165*7c478bd9Sstevel@tonic-gate 	default:			/* error */
1166*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "unsupported failure mode\n");
1167*7c478bd9Sstevel@tonic-gate 		break;
1168*7c478bd9Sstevel@tonic-gate 	}
1169*7c478bd9Sstevel@tonic-gate 	exit(2);
1170*7c478bd9Sstevel@tonic-gate }
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate static int
1173*7c478bd9Sstevel@tonic-gate safe_strtoi(char const *val, char *errmsg)
1174*7c478bd9Sstevel@tonic-gate {
1175*7c478bd9Sstevel@tonic-gate 	char *end;
1176*7c478bd9Sstevel@tonic-gate 	long tmp;
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	errno = 0;
1179*7c478bd9Sstevel@tonic-gate 	tmp = strtol(val, &end, 10);
1180*7c478bd9Sstevel@tonic-gate 	if (*end != '\0' || errno)
1181*7c478bd9Sstevel@tonic-gate 		fail(0, "%s %s", errmsg, val);
1182*7c478bd9Sstevel@tonic-gate 	return ((int)tmp);
1183*7c478bd9Sstevel@tonic-gate }
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate static void
1186*7c478bd9Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first)
1187*7c478bd9Sstevel@tonic-gate {
1188*7c478bd9Sstevel@tonic-gate 	if (free_first && *ptr != NULL)
1189*7c478bd9Sstevel@tonic-gate 		free(*ptr);
1190*7c478bd9Sstevel@tonic-gate 	if ((*ptr = malloc(size)) == NULL)
1191*7c478bd9Sstevel@tonic-gate 		fail(1, "malloc failed");
1192*7c478bd9Sstevel@tonic-gate 	(void) memset(*ptr, 0, size);
1193*7c478bd9Sstevel@tonic-gate }
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate static int
1196*7c478bd9Sstevel@tonic-gate safe_read(int fd, void *buf, size_t size)
1197*7c478bd9Sstevel@tonic-gate {
1198*7c478bd9Sstevel@tonic-gate 	size_t rsize = read(fd, buf, size);
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate 	if (rsize == 0)
1201*7c478bd9Sstevel@tonic-gate 		return (0);
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	if (rsize != size)
1204*7c478bd9Sstevel@tonic-gate 		fail(1, "read failed");
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	return (1);
1207*7c478bd9Sstevel@tonic-gate }
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate static void
1210*7c478bd9Sstevel@tonic-gate safe_write(int fd, void *buf, size_t size)
1211*7c478bd9Sstevel@tonic-gate {
1212*7c478bd9Sstevel@tonic-gate 	if (write(fd, buf, size) != size)
1213*7c478bd9Sstevel@tonic-gate 		fail(1, "write failed");
1214*7c478bd9Sstevel@tonic-gate }
1215