xref: /titanic_44/usr/src/cmd/cpc/common/cpustat.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/processor.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/pset.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/lwp.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/priocntl.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/fxpriocntl.h>
35*7c478bd9Sstevel@tonic-gate #include <time.h>
36*7c478bd9Sstevel@tonic-gate #include <stdio.h>
37*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
38*7c478bd9Sstevel@tonic-gate #include <inttypes.h>
39*7c478bd9Sstevel@tonic-gate #include <unistd.h>
40*7c478bd9Sstevel@tonic-gate #include <limits.h>
41*7c478bd9Sstevel@tonic-gate #include <string.h>
42*7c478bd9Sstevel@tonic-gate #include <strings.h>
43*7c478bd9Sstevel@tonic-gate #include <thread.h>
44*7c478bd9Sstevel@tonic-gate #include <errno.h>
45*7c478bd9Sstevel@tonic-gate #include <libintl.h>
46*7c478bd9Sstevel@tonic-gate #include <locale.h>
47*7c478bd9Sstevel@tonic-gate #include <kstat.h>
48*7c478bd9Sstevel@tonic-gate #include <synch.h>
49*7c478bd9Sstevel@tonic-gate #include <libcpc.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include "cpucmds.h"
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate static struct options {
54*7c478bd9Sstevel@tonic-gate 	int debug;
55*7c478bd9Sstevel@tonic-gate 	int dotitle;
56*7c478bd9Sstevel@tonic-gate 	int dohelp;
57*7c478bd9Sstevel@tonic-gate 	int dotick;
58*7c478bd9Sstevel@tonic-gate 	int dosoaker;
59*7c478bd9Sstevel@tonic-gate 	int doperiod;
60*7c478bd9Sstevel@tonic-gate 	char *pgmname;
61*7c478bd9Sstevel@tonic-gate 	uint_t mseconds;
62*7c478bd9Sstevel@tonic-gate 	uint_t nsamples;
63*7c478bd9Sstevel@tonic-gate 	uint_t nsets;
64*7c478bd9Sstevel@tonic-gate 	uint_t mseconds_rest;
65*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_t *master;
66*7c478bd9Sstevel@tonic-gate } __options;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate /*
69*7c478bd9Sstevel@tonic-gate  * States for soaker threads.
70*7c478bd9Sstevel@tonic-gate  */
71*7c478bd9Sstevel@tonic-gate #define	SOAK_PAUSE	0
72*7c478bd9Sstevel@tonic-gate #define	SOAK_RUN	1
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate struct tstate {
75*7c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
76*7c478bd9Sstevel@tonic-gate 	int		chip_id;
77*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_t	*sgrp;
78*7c478bd9Sstevel@tonic-gate 	int		status;
79*7c478bd9Sstevel@tonic-gate 	thread_t	tid;
80*7c478bd9Sstevel@tonic-gate 	int		soak_state;
81*7c478bd9Sstevel@tonic-gate 	mutex_t		soak_lock;
82*7c478bd9Sstevel@tonic-gate 	cond_t		soak_cv;
83*7c478bd9Sstevel@tonic-gate };
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate static const struct options *opts = (const struct options *)&__options;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate static cpc_t *cpc;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate struct tstate	*gstate;
90*7c478bd9Sstevel@tonic-gate static int	ncpus;
91*7c478bd9Sstevel@tonic-gate static int	max_chip_id;
92*7c478bd9Sstevel@tonic-gate static int	*chip_designees;    /* cpuid of CPU which counts for phs chip */
93*7c478bd9Sstevel@tonic-gate static int	smt = 0;	    /* If set, cpustat needs to be SMT-aware. */
94*7c478bd9Sstevel@tonic-gate static pcinfo_t	fxinfo = { 0, "FX", NULL }; /* FX scheduler class info */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
97*7c478bd9Sstevel@tonic-gate static void
98*7c478bd9Sstevel@tonic-gate cpustat_errfn(const char *fn, int subcode, const char *fmt, va_list ap)
99*7c478bd9Sstevel@tonic-gate {
100*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", opts->pgmname);
101*7c478bd9Sstevel@tonic-gate 	if (opts->debug)
102*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", fn);
103*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
104*7c478bd9Sstevel@tonic-gate }
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate static int cpustat(void);
107*7c478bd9Sstevel@tonic-gate static int get_chipid(kstat_ctl_t *kc, processorid_t cpuid);
108*7c478bd9Sstevel@tonic-gate static void *soaker(void *arg);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
112*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
113*7c478bd9Sstevel@tonic-gate #endif
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate int
116*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate 	struct options	*opts = &__options;
119*7c478bd9Sstevel@tonic-gate 	int		c, errcnt = 0, ret;
120*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_t	*sgrp;
121*7c478bd9Sstevel@tonic-gate 	char		*errstr;
122*7c478bd9Sstevel@tonic-gate 	double		period;
123*7c478bd9Sstevel@tonic-gate 	char		*endp;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
126*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	if ((opts->pgmname = strrchr(argv[0], '/')) == NULL)
129*7c478bd9Sstevel@tonic-gate 		opts->pgmname = argv[0];
130*7c478bd9Sstevel@tonic-gate 	else
131*7c478bd9Sstevel@tonic-gate 		opts->pgmname++;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
134*7c478bd9Sstevel@tonic-gate 		errstr = strerror(errno);
135*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: cannot access performance "
136*7c478bd9Sstevel@tonic-gate 		    "counters - %s\n"), opts->pgmname, errstr);
137*7c478bd9Sstevel@tonic-gate 		return (1);
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 	(void) cpc_seterrhndlr(cpc, cpustat_errfn);
141*7c478bd9Sstevel@tonic-gate 	strtoset_errfn = cpustat_errfn;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	/*
144*7c478bd9Sstevel@tonic-gate 	 * Check to see if cpustat needs to be SMT-aware.
145*7c478bd9Sstevel@tonic-gate 	 */
146*7c478bd9Sstevel@tonic-gate 	smt = smt_limited_cpc_hw(cpc);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	/*
149*7c478bd9Sstevel@tonic-gate 	 * Establish some defaults
150*7c478bd9Sstevel@tonic-gate 	 */
151*7c478bd9Sstevel@tonic-gate 	opts->mseconds = 5000;
152*7c478bd9Sstevel@tonic-gate 	opts->nsamples = UINT_MAX;
153*7c478bd9Sstevel@tonic-gate 	opts->dotitle = 1;
154*7c478bd9Sstevel@tonic-gate 	if ((opts->master = cpc_setgrp_new(cpc, smt)) == NULL) {
155*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: out of heap\n"),
156*7c478bd9Sstevel@tonic-gate 		    opts->pgmname);
157*7c478bd9Sstevel@tonic-gate 		return (1);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "Dc:hntsp:")) != EOF && errcnt == 0)
161*7c478bd9Sstevel@tonic-gate 		switch (c) {
162*7c478bd9Sstevel@tonic-gate 		case 'D':			/* enable debugging */
163*7c478bd9Sstevel@tonic-gate 			opts->debug++;
164*7c478bd9Sstevel@tonic-gate 			break;
165*7c478bd9Sstevel@tonic-gate 		case 'c':			/* specify statistics */
166*7c478bd9Sstevel@tonic-gate 			if ((sgrp = cpc_setgrp_newset(opts->master,
167*7c478bd9Sstevel@tonic-gate 			    optarg, &errcnt)) != NULL)
168*7c478bd9Sstevel@tonic-gate 				opts->master = sgrp;
169*7c478bd9Sstevel@tonic-gate 			break;
170*7c478bd9Sstevel@tonic-gate 		case 'n':			/* no titles */
171*7c478bd9Sstevel@tonic-gate 			opts->dotitle = 0;
172*7c478bd9Sstevel@tonic-gate 			break;
173*7c478bd9Sstevel@tonic-gate 		case 'p':			/* periodic behavior */
174*7c478bd9Sstevel@tonic-gate 			opts->doperiod = 1;
175*7c478bd9Sstevel@tonic-gate 			period = strtod(optarg, &endp);
176*7c478bd9Sstevel@tonic-gate 			if (*endp != '\0') {
177*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: invalid "
178*7c478bd9Sstevel@tonic-gate 				    "parameter \"%s\"\n"), opts->pgmname,
179*7c478bd9Sstevel@tonic-gate 				    optarg);
180*7c478bd9Sstevel@tonic-gate 				errcnt++;
181*7c478bd9Sstevel@tonic-gate 			}
182*7c478bd9Sstevel@tonic-gate 			break;
183*7c478bd9Sstevel@tonic-gate 		case 's':			/* run soaker thread */
184*7c478bd9Sstevel@tonic-gate 			opts->dosoaker = 1;
185*7c478bd9Sstevel@tonic-gate 			break;
186*7c478bd9Sstevel@tonic-gate 		case 't':			/* print %tick */
187*7c478bd9Sstevel@tonic-gate 			opts->dotick = 1;
188*7c478bd9Sstevel@tonic-gate 			break;
189*7c478bd9Sstevel@tonic-gate 		case 'h':			/* help */
190*7c478bd9Sstevel@tonic-gate 			opts->dohelp = 1;
191*7c478bd9Sstevel@tonic-gate 			break;
192*7c478bd9Sstevel@tonic-gate 		case '?':
193*7c478bd9Sstevel@tonic-gate 		default:
194*7c478bd9Sstevel@tonic-gate 			errcnt++;
195*7c478bd9Sstevel@tonic-gate 			break;
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate 	switch (argc - optind) {
199*7c478bd9Sstevel@tonic-gate 	case 0:
200*7c478bd9Sstevel@tonic-gate 		break;
201*7c478bd9Sstevel@tonic-gate 	case 2:
202*7c478bd9Sstevel@tonic-gate 		opts->nsamples = strtol(argv[optind + 1], &endp, 10);
203*7c478bd9Sstevel@tonic-gate 		if (*endp != '\0') {
204*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
205*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid argument \"%s\"\n"),
206*7c478bd9Sstevel@tonic-gate 			    opts->pgmname, argv[optind + 1]);
207*7c478bd9Sstevel@tonic-gate 			errcnt++;
208*7c478bd9Sstevel@tonic-gate 			break;
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
211*7c478bd9Sstevel@tonic-gate 	case 1:
212*7c478bd9Sstevel@tonic-gate 		opts->mseconds = (uint_t)(strtod(argv[optind], &endp) * 1000.0);
213*7c478bd9Sstevel@tonic-gate 		if (*endp != '\0') {
214*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
215*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid argument \"%s\"\n"),
216*7c478bd9Sstevel@tonic-gate 			    opts->pgmname, argv[optind]);
217*7c478bd9Sstevel@tonic-gate 			errcnt++;
218*7c478bd9Sstevel@tonic-gate 		}
219*7c478bd9Sstevel@tonic-gate 		break;
220*7c478bd9Sstevel@tonic-gate 	default:
221*7c478bd9Sstevel@tonic-gate 		errcnt++;
222*7c478bd9Sstevel@tonic-gate 		break;
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	if (opts->nsamples == 0 || opts->mseconds == 0)
226*7c478bd9Sstevel@tonic-gate 		errcnt++;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	if (errcnt != 0 || opts->dohelp ||
229*7c478bd9Sstevel@tonic-gate 	    (opts->nsets = cpc_setgrp_numsets(opts->master)) == 0) {
230*7c478bd9Sstevel@tonic-gate 		(void) fprintf(opts->dohelp ? stdout : stderr, gettext(
231*7c478bd9Sstevel@tonic-gate 		    "Usage:\n\t%s [-c events] [-p period] [-nstD] "
232*7c478bd9Sstevel@tonic-gate 			"[interval [count]]\n\n"
233*7c478bd9Sstevel@tonic-gate 		    "\t-c events specify processor events to be monitored\n"
234*7c478bd9Sstevel@tonic-gate 		    "\t-n\t  suppress titles\n"
235*7c478bd9Sstevel@tonic-gate 		    "\t-p period cycle through event list periodically\n"
236*7c478bd9Sstevel@tonic-gate 		    "\t-s\t  run user soaker thread for system-only events\n"
237*7c478bd9Sstevel@tonic-gate 		    "\t-t\t  include %s register\n"
238*7c478bd9Sstevel@tonic-gate 		    "\t-D\t  enable debug mode\n"
239*7c478bd9Sstevel@tonic-gate 		    "\t-h\t  print extended usage information\n\n"
240*7c478bd9Sstevel@tonic-gate 		    "\tUse cputrack(1) to monitor per-process statistics.\n"),
241*7c478bd9Sstevel@tonic-gate 		    opts->pgmname, CPC_TICKREG_NAME);
242*7c478bd9Sstevel@tonic-gate 		if (opts->dohelp) {
243*7c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
244*7c478bd9Sstevel@tonic-gate 			(void) capabilities(cpc, stdout);
245*7c478bd9Sstevel@tonic-gate 			exit(0);
246*7c478bd9Sstevel@tonic-gate 		}
247*7c478bd9Sstevel@tonic-gate 		exit(2);
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	/*
251*7c478bd9Sstevel@tonic-gate 	 * If the user requested periodic behavior, calculate the rest time
252*7c478bd9Sstevel@tonic-gate 	 * between cycles.
253*7c478bd9Sstevel@tonic-gate 	 */
254*7c478bd9Sstevel@tonic-gate 	if (opts->doperiod) {
255*7c478bd9Sstevel@tonic-gate 		opts->mseconds_rest = (uint_t)((period * 1000.0) -
256*7c478bd9Sstevel@tonic-gate 		    (opts->mseconds * opts->nsets));
257*7c478bd9Sstevel@tonic-gate 		if ((int)opts->mseconds_rest < 0)
258*7c478bd9Sstevel@tonic-gate 			opts->mseconds_rest = 0;
259*7c478bd9Sstevel@tonic-gate 		if (opts->nsamples != UINT_MAX)
260*7c478bd9Sstevel@tonic-gate 			opts->nsamples *= opts->nsets;
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_reset(opts->master);
264*7c478bd9Sstevel@tonic-gate 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	/*
267*7c478bd9Sstevel@tonic-gate 	 * If no system-mode only sets were created, no soaker threads will be
268*7c478bd9Sstevel@tonic-gate 	 * needed.
269*7c478bd9Sstevel@tonic-gate 	 */
270*7c478bd9Sstevel@tonic-gate 	if (opts->dosoaker == 1 && cpc_setgrp_has_sysonly(opts->master) == 0)
271*7c478bd9Sstevel@tonic-gate 		opts->dosoaker = 0;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	ret = cpustat();
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	(void) cpc_close(cpc);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	return (ret);
278*7c478bd9Sstevel@tonic-gate }
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate static void
281*7c478bd9Sstevel@tonic-gate print_title(cpc_setgrp_t *sgrp)
282*7c478bd9Sstevel@tonic-gate {
283*7c478bd9Sstevel@tonic-gate 	(void) printf("%7s %3s %5s ", "time", "cpu", "event");
284*7c478bd9Sstevel@tonic-gate 	if (opts->dotick)
285*7c478bd9Sstevel@tonic-gate 		(void) printf("%9s ", CPC_TICKREG_NAME);
286*7c478bd9Sstevel@tonic-gate 	(void) printf("%s\n", cpc_setgrp_gethdr(sgrp));
287*7c478bd9Sstevel@tonic-gate }
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate static void
290*7c478bd9Sstevel@tonic-gate print_sample(processorid_t cpuid, cpc_buf_t *buf, int nreq, const char *setname,
291*7c478bd9Sstevel@tonic-gate     int sibling)
292*7c478bd9Sstevel@tonic-gate {
293*7c478bd9Sstevel@tonic-gate 	char		line[1024];
294*7c478bd9Sstevel@tonic-gate 	int		ccnt;
295*7c478bd9Sstevel@tonic-gate 	int		i;
296*7c478bd9Sstevel@tonic-gate 	uint64_t	val;
297*7c478bd9Sstevel@tonic-gate 	uint64_t	tick;
298*7c478bd9Sstevel@tonic-gate 	hrtime_t	hrtime;
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	hrtime = cpc_buf_hrtime(cpc, buf);
301*7c478bd9Sstevel@tonic-gate 	tick = cpc_buf_tick(cpc, buf);
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	ccnt = snprintf(line, sizeof (line), "%7.3f %3d %5s ",
304*7c478bd9Sstevel@tonic-gate 	    mstimestamp(hrtime), (int)cpuid, "tick");
305*7c478bd9Sstevel@tonic-gate 	if (opts->dotick)
306*7c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
307*7c478bd9Sstevel@tonic-gate 		    "%9" PRId64 " ", tick);
308*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nreq; i++) {
309*7c478bd9Sstevel@tonic-gate 		(void) cpc_buf_get(cpc, buf, i, &val);
310*7c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
311*7c478bd9Sstevel@tonic-gate 		    "%9" PRId64 " ", val);
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 	if (opts->nsets > 1)
314*7c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
315*7c478bd9Sstevel@tonic-gate 		    " # %s\n", setname);
316*7c478bd9Sstevel@tonic-gate 	else
317*7c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, "\n");
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	if (sibling) {
320*7c478bd9Sstevel@tonic-gate 		/*
321*7c478bd9Sstevel@tonic-gate 		 * This sample is being printed for a "sibling" CPU -- that is,
322*7c478bd9Sstevel@tonic-gate 		 * a CPU which does not have its own CPC set bound. It is being
323*7c478bd9Sstevel@tonic-gate 		 * measured via a set bound to another CPU sharing its physical
324*7c478bd9Sstevel@tonic-gate 		 * processor.
325*7c478bd9Sstevel@tonic-gate 		 */
326*7c478bd9Sstevel@tonic-gate 		int designee = chip_designees[gstate[cpuid].chip_id];
327*7c478bd9Sstevel@tonic-gate 		char *p;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		if ((p = strrchr(line, '#')) == NULL)
330*7c478bd9Sstevel@tonic-gate 			p = strrchr(line, '\n');
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 		if (p != NULL) {
333*7c478bd9Sstevel@tonic-gate 			*p = '\0';
334*7c478bd9Sstevel@tonic-gate 			ccnt = strlen(line);
335*7c478bd9Sstevel@tonic-gate 			ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
336*7c478bd9Sstevel@tonic-gate 			    "# counter shared with CPU %d\n", designee);
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 	if (ccnt > sizeof (line))
341*7c478bd9Sstevel@tonic-gate 		ccnt = sizeof (line);
342*7c478bd9Sstevel@tonic-gate 	if (ccnt > 0)
343*7c478bd9Sstevel@tonic-gate 		(void) write(1, line, ccnt);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	/*
346*7c478bd9Sstevel@tonic-gate 	 * If this CPU is the chip designee for any other CPUs, print a line for
347*7c478bd9Sstevel@tonic-gate 	 * them here.
348*7c478bd9Sstevel@tonic-gate 	 */
349*7c478bd9Sstevel@tonic-gate 	if (smt && (sibling == 0)) {
350*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncpus; i++) {
351*7c478bd9Sstevel@tonic-gate 			if ((i != cpuid) && (gstate[i].cpuid != -1) &&
352*7c478bd9Sstevel@tonic-gate 			    (chip_designees[gstate[i].chip_id] == cpuid))
353*7c478bd9Sstevel@tonic-gate 				print_sample(i, buf, nreq, setname, 1);
354*7c478bd9Sstevel@tonic-gate 		}
355*7c478bd9Sstevel@tonic-gate 	}
356*7c478bd9Sstevel@tonic-gate }
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate static void
359*7c478bd9Sstevel@tonic-gate print_total(int ncpus, cpc_buf_t *buf, int nreq, const char *setname)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	int		i;
362*7c478bd9Sstevel@tonic-gate 	uint64_t	val;
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	(void) printf("%7.3f %3d %5s ", mstimestamp(cpc_buf_hrtime(cpc, buf)),
365*7c478bd9Sstevel@tonic-gate 	    ncpus, "total");
366*7c478bd9Sstevel@tonic-gate 	if (opts->dotick)
367*7c478bd9Sstevel@tonic-gate 		(void) printf("%9" PRId64 " ", cpc_buf_tick(cpc, buf));
368*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nreq; i++) {
369*7c478bd9Sstevel@tonic-gate 		(void) cpc_buf_get(cpc, buf, i, &val);
370*7c478bd9Sstevel@tonic-gate 		(void) printf("%9" PRId64 " ", val);
371*7c478bd9Sstevel@tonic-gate 	}
372*7c478bd9Sstevel@tonic-gate 	if (opts->nsets > 1)
373*7c478bd9Sstevel@tonic-gate 		(void) printf(" # %s", setname);
374*7c478bd9Sstevel@tonic-gate 	(void) fputc('\n', stdout);
375*7c478bd9Sstevel@tonic-gate }
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate #define	NSECS_PER_MSEC	1000000ll
378*7c478bd9Sstevel@tonic-gate #define	NSECS_PER_SEC	1000000000ll
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate static void *
381*7c478bd9Sstevel@tonic-gate gtick(void *arg)
382*7c478bd9Sstevel@tonic-gate {
383*7c478bd9Sstevel@tonic-gate 	struct tstate		*state = arg;
384*7c478bd9Sstevel@tonic-gate 	char			*errstr;
385*7c478bd9Sstevel@tonic-gate 	uint_t			nsamples;
386*7c478bd9Sstevel@tonic-gate 	uint_t			sample_cnt = 1;
387*7c478bd9Sstevel@tonic-gate 	hrtime_t		ht, htdelta, restdelta;
388*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_t		*sgrp = state->sgrp;
389*7c478bd9Sstevel@tonic-gate 	cpc_set_t		*this = cpc_setgrp_getset(sgrp);
390*7c478bd9Sstevel@tonic-gate 	const char		*name = cpc_setgrp_getname(sgrp);
391*7c478bd9Sstevel@tonic-gate 	cpc_buf_t		**data1, **data2, **scratch;
392*7c478bd9Sstevel@tonic-gate 	cpc_buf_t		*tmp;
393*7c478bd9Sstevel@tonic-gate 	int			nreqs;
394*7c478bd9Sstevel@tonic-gate 	thread_t		tid;
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	htdelta = NSECS_PER_MSEC * opts->mseconds;
397*7c478bd9Sstevel@tonic-gate 	restdelta = NSECS_PER_MSEC * opts->mseconds_rest;
398*7c478bd9Sstevel@tonic-gate 	ht = gethrtime();
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	/*
401*7c478bd9Sstevel@tonic-gate 	 * If this CPU is SMT, we run one gtick() thread per _physical_ CPU,
402*7c478bd9Sstevel@tonic-gate 	 * instead of per cpu_t. The following check returns if it detects that
403*7c478bd9Sstevel@tonic-gate 	 * this cpu_t has not been designated to do the counting for this
404*7c478bd9Sstevel@tonic-gate 	 * physical CPU.
405*7c478bd9Sstevel@tonic-gate 	 */
406*7c478bd9Sstevel@tonic-gate 	if (smt && chip_designees[state->chip_id] != state->cpuid)
407*7c478bd9Sstevel@tonic-gate 		return (NULL);
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	/*
410*7c478bd9Sstevel@tonic-gate 	 * If we need to run a soaker thread on this CPU, start it here.
411*7c478bd9Sstevel@tonic-gate 	 */
412*7c478bd9Sstevel@tonic-gate 	if (opts->dosoaker) {
413*7c478bd9Sstevel@tonic-gate 		if (cond_init(&state->soak_cv, USYNC_THREAD, NULL) != 0)
414*7c478bd9Sstevel@tonic-gate 			goto bad;
415*7c478bd9Sstevel@tonic-gate 		if (mutex_init(&state->soak_lock, USYNC_THREAD,
416*7c478bd9Sstevel@tonic-gate 		    NULL) != 0)
417*7c478bd9Sstevel@tonic-gate 			goto bad;
418*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&state->soak_lock);
419*7c478bd9Sstevel@tonic-gate 		state->soak_state = SOAK_PAUSE;
420*7c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, 0, soaker, state, NULL, &tid) != 0)
421*7c478bd9Sstevel@tonic-gate 			goto bad;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 		while (state->soak_state == SOAK_PAUSE)
424*7c478bd9Sstevel@tonic-gate 			(void) cond_wait(&state->soak_cv,
425*7c478bd9Sstevel@tonic-gate 			    &state->soak_lock);
426*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&state->soak_lock);
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 		/*
429*7c478bd9Sstevel@tonic-gate 		 * If the soaker needs to pause for the first set, stop it now.
430*7c478bd9Sstevel@tonic-gate 		 */
431*7c478bd9Sstevel@tonic-gate 		if (cpc_setgrp_sysonly(sgrp) == 0) {
432*7c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&state->soak_lock);
433*7c478bd9Sstevel@tonic-gate 			state->soak_state = SOAK_PAUSE;
434*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&state->soak_lock);
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 	if (cpc_bind_cpu(cpc, state->cpuid, this, 0) == -1)
438*7c478bd9Sstevel@tonic-gate 		goto bad;
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	for (nsamples = opts->nsamples; nsamples; nsamples--, sample_cnt++) {
441*7c478bd9Sstevel@tonic-gate 		hrtime_t htnow;
442*7c478bd9Sstevel@tonic-gate 		struct timespec ts;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		ht += htdelta;
447*7c478bd9Sstevel@tonic-gate 		htnow = gethrtime();
448*7c478bd9Sstevel@tonic-gate 		if (ht <= htnow)
449*7c478bd9Sstevel@tonic-gate 			continue;
450*7c478bd9Sstevel@tonic-gate 		ts.tv_sec = (time_t)((ht - htnow) / NSECS_PER_SEC);
451*7c478bd9Sstevel@tonic-gate 		ts.tv_nsec = (suseconds_t)((ht - htnow) % NSECS_PER_SEC);
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		(void) nanosleep(&ts, NULL);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 		if (opts->nsets == 1) {
456*7c478bd9Sstevel@tonic-gate 			/*
457*7c478bd9Sstevel@tonic-gate 			 * If we're dealing with one set, buffer usage is:
458*7c478bd9Sstevel@tonic-gate 			 *
459*7c478bd9Sstevel@tonic-gate 			 * data1 = most recent data snapshot
460*7c478bd9Sstevel@tonic-gate 			 * data2 = previous data snapshot
461*7c478bd9Sstevel@tonic-gate 			 * scratch = used for diffing data1 and data2
462*7c478bd9Sstevel@tonic-gate 			 *
463*7c478bd9Sstevel@tonic-gate 			 * Save the snapshot from the previous sample in data2
464*7c478bd9Sstevel@tonic-gate 			 * before putting the current sample in data1.
465*7c478bd9Sstevel@tonic-gate 			 */
466*7c478bd9Sstevel@tonic-gate 			tmp = *data1;
467*7c478bd9Sstevel@tonic-gate 			*data1 = *data2;
468*7c478bd9Sstevel@tonic-gate 			*data2 = tmp;
469*7c478bd9Sstevel@tonic-gate 			if (cpc_set_sample(cpc, this, *data1) != 0)
470*7c478bd9Sstevel@tonic-gate 				goto bad;
471*7c478bd9Sstevel@tonic-gate 			cpc_buf_sub(cpc, *scratch, *data1, *data2);
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 			print_sample(state->cpuid, *scratch, nreqs, name, 0);
474*7c478bd9Sstevel@tonic-gate 		} else {
475*7c478bd9Sstevel@tonic-gate 			/*
476*7c478bd9Sstevel@tonic-gate 			 * More than one set is in use (multiple -c options
477*7c478bd9Sstevel@tonic-gate 			 * given). Buffer usage in this case is:
478*7c478bd9Sstevel@tonic-gate 			 *
479*7c478bd9Sstevel@tonic-gate 			 * data1 = total counts for this set since program began
480*7c478bd9Sstevel@tonic-gate 			 * data2 = unused
481*7c478bd9Sstevel@tonic-gate 			 * scratch = most recent data snapshot
482*7c478bd9Sstevel@tonic-gate 			 */
483*7c478bd9Sstevel@tonic-gate 			name = cpc_setgrp_getname(sgrp);
484*7c478bd9Sstevel@tonic-gate 			nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2,
485*7c478bd9Sstevel@tonic-gate 			    &scratch);
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 			if (cpc_set_sample(cpc, this, *scratch) != 0)
488*7c478bd9Sstevel@tonic-gate 				goto bad;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 			cpc_buf_add(cpc, *data1, *data1, *scratch);
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 			if (cpc_unbind(cpc, this) != 0)
493*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: error "
494*7c478bd9Sstevel@tonic-gate 				    "unbinding on cpu %d - %s\n"),
495*7c478bd9Sstevel@tonic-gate 				    opts->pgmname, state->cpuid,
496*7c478bd9Sstevel@tonic-gate 				    strerror(errno));
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 			this = cpc_setgrp_nextset(sgrp);
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 			print_sample(state->cpuid, *scratch, nreqs, name, 0);
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 			/*
503*7c478bd9Sstevel@tonic-gate 			 * If periodic behavior was requested, rest here.
504*7c478bd9Sstevel@tonic-gate 			 */
505*7c478bd9Sstevel@tonic-gate 			if (opts->doperiod && opts->mseconds_rest > 0 &&
506*7c478bd9Sstevel@tonic-gate 				(sample_cnt % opts->nsets) == 0) {
507*7c478bd9Sstevel@tonic-gate 				/*
508*7c478bd9Sstevel@tonic-gate 				 * Stop the soaker while the tool rests.
509*7c478bd9Sstevel@tonic-gate 				 */
510*7c478bd9Sstevel@tonic-gate 				if (opts->dosoaker) {
511*7c478bd9Sstevel@tonic-gate 					(void) mutex_lock(&state->soak_lock);
512*7c478bd9Sstevel@tonic-gate 					if (state->soak_state == SOAK_RUN)
513*7c478bd9Sstevel@tonic-gate 						state->soak_state = SOAK_PAUSE;
514*7c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&state->soak_lock);
515*7c478bd9Sstevel@tonic-gate 				}
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 				htnow = gethrtime();
518*7c478bd9Sstevel@tonic-gate 				ht += restdelta;
519*7c478bd9Sstevel@tonic-gate 				ts.tv_sec = (time_t)((ht - htnow) /
520*7c478bd9Sstevel@tonic-gate 				    NSECS_PER_SEC);
521*7c478bd9Sstevel@tonic-gate 				ts.tv_nsec = (suseconds_t)((ht - htnow) %
522*7c478bd9Sstevel@tonic-gate 				    NSECS_PER_SEC);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 				(void) nanosleep(&ts, NULL);
525*7c478bd9Sstevel@tonic-gate 			}
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 			/*
528*7c478bd9Sstevel@tonic-gate 			 * Start or stop the soaker if needed.
529*7c478bd9Sstevel@tonic-gate 			 */
530*7c478bd9Sstevel@tonic-gate 			if (opts->dosoaker) {
531*7c478bd9Sstevel@tonic-gate 				(void) mutex_lock(&state->soak_lock);
532*7c478bd9Sstevel@tonic-gate 				if (cpc_setgrp_sysonly(sgrp) &&
533*7c478bd9Sstevel@tonic-gate 				    state->soak_state == SOAK_PAUSE) {
534*7c478bd9Sstevel@tonic-gate 					/*
535*7c478bd9Sstevel@tonic-gate 					 * Soaker is paused but the next set is
536*7c478bd9Sstevel@tonic-gate 					 * sysonly: start the soaker.
537*7c478bd9Sstevel@tonic-gate 					 */
538*7c478bd9Sstevel@tonic-gate 					state->soak_state = SOAK_RUN;
539*7c478bd9Sstevel@tonic-gate 					(void) cond_signal(&state->soak_cv);
540*7c478bd9Sstevel@tonic-gate 				} else if (cpc_setgrp_sysonly(sgrp) == 0 &&
541*7c478bd9Sstevel@tonic-gate 				    state->soak_state == SOAK_RUN)
542*7c478bd9Sstevel@tonic-gate 					/*
543*7c478bd9Sstevel@tonic-gate 					 * Soaker is running but the next set
544*7c478bd9Sstevel@tonic-gate 					 * counts user events: stop the soaker.
545*7c478bd9Sstevel@tonic-gate 					 */
546*7c478bd9Sstevel@tonic-gate 					state->soak_state = SOAK_PAUSE;
547*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&state->soak_lock);
548*7c478bd9Sstevel@tonic-gate 			}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 			if (cpc_bind_cpu(cpc, state->cpuid, this, 0) != 0)
551*7c478bd9Sstevel@tonic-gate 				goto bad;
552*7c478bd9Sstevel@tonic-gate 		}
553*7c478bd9Sstevel@tonic-gate 	}
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	if (cpc_unbind(cpc, this) != 0)
556*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: error unbinding on"
557*7c478bd9Sstevel@tonic-gate 		    " cpu %d - %s\n"), opts->pgmname,
558*7c478bd9Sstevel@tonic-gate 		    state->cpuid, strerror(errno));
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	/*
561*7c478bd9Sstevel@tonic-gate 	 * We're done, so stop the soaker if needed.
562*7c478bd9Sstevel@tonic-gate 	 */
563*7c478bd9Sstevel@tonic-gate 	if (opts->dosoaker) {
564*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&state->soak_lock);
565*7c478bd9Sstevel@tonic-gate 		if (state->soak_state == SOAK_RUN)
566*7c478bd9Sstevel@tonic-gate 			state->soak_state = SOAK_PAUSE;
567*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&state->soak_lock);
568*7c478bd9Sstevel@tonic-gate 	}
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	return (NULL);
571*7c478bd9Sstevel@tonic-gate bad:
572*7c478bd9Sstevel@tonic-gate 	state->status = 3;
573*7c478bd9Sstevel@tonic-gate 	errstr = strerror(errno);
574*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: cpu%d - %s\n"),
575*7c478bd9Sstevel@tonic-gate 	    opts->pgmname, state->cpuid, errstr);
576*7c478bd9Sstevel@tonic-gate 	return (NULL);
577*7c478bd9Sstevel@tonic-gate }
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate static int
580*7c478bd9Sstevel@tonic-gate cpustat(void)
581*7c478bd9Sstevel@tonic-gate {
582*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_t	*accum;
583*7c478bd9Sstevel@tonic-gate 	cpc_set_t	*start;
584*7c478bd9Sstevel@tonic-gate 	int		c, i, retval;
585*7c478bd9Sstevel@tonic-gate 	int		lwps = 0;
586*7c478bd9Sstevel@tonic-gate 	psetid_t	mypset, cpupset;
587*7c478bd9Sstevel@tonic-gate 	char		*errstr;
588*7c478bd9Sstevel@tonic-gate 	cpc_buf_t	**data1, **data2, **scratch;
589*7c478bd9Sstevel@tonic-gate 	int		nreqs;
590*7c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kc;
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	ncpus = (int)sysconf(_SC_NPROCESSORS_CONF);
593*7c478bd9Sstevel@tonic-gate 	if ((gstate = calloc(ncpus, sizeof (*gstate))) == NULL) {
594*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
595*7c478bd9Sstevel@tonic-gate 		    "%s: out of heap\n"), opts->pgmname);
596*7c478bd9Sstevel@tonic-gate 		return (1);
597*7c478bd9Sstevel@tonic-gate 	}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	max_chip_id = sysconf(_SC_CPUID_MAX);
600*7c478bd9Sstevel@tonic-gate 	if ((chip_designees = malloc(max_chip_id * sizeof (int))) == NULL) {
601*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
602*7c478bd9Sstevel@tonic-gate 			"%s: out of heap\n"), opts->pgmname);
603*7c478bd9Sstevel@tonic-gate 		return (1);
604*7c478bd9Sstevel@tonic-gate 	}
605*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < max_chip_id; i++)
606*7c478bd9Sstevel@tonic-gate 		chip_designees[i] = -1;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	if (smt) {
609*7c478bd9Sstevel@tonic-gate 		if ((kc = kstat_open()) == NULL) {
610*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
611*7c478bd9Sstevel@tonic-gate 				"%s: kstat_open() failed: %s\n"), opts->pgmname,
612*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
613*7c478bd9Sstevel@tonic-gate 			    return (1);
614*7c478bd9Sstevel@tonic-gate 		}
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	if (opts->dosoaker)
618*7c478bd9Sstevel@tonic-gate 		if (priocntl(0, 0, PC_GETCID, &fxinfo) == -1) {
619*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
620*7c478bd9Sstevel@tonic-gate 				"%s: couldn't get FX scheduler class: %s\n"),
621*7c478bd9Sstevel@tonic-gate 			    opts->pgmname, strerror(errno));
622*7c478bd9Sstevel@tonic-gate 			return (1);
623*7c478bd9Sstevel@tonic-gate 		}
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	/*
626*7c478bd9Sstevel@tonic-gate 	 * Only include processors that are participating in the system
627*7c478bd9Sstevel@tonic-gate 	 */
628*7c478bd9Sstevel@tonic-gate 	for (c = 0, i = 0; i < ncpus; c++) {
629*7c478bd9Sstevel@tonic-gate 		switch (p_online(c, P_STATUS)) {
630*7c478bd9Sstevel@tonic-gate 		case P_ONLINE:
631*7c478bd9Sstevel@tonic-gate 		case P_NOINTR:
632*7c478bd9Sstevel@tonic-gate 			if (smt) {
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 				gstate[i].chip_id = get_chipid(kc, c);
635*7c478bd9Sstevel@tonic-gate 				if (gstate[i].chip_id != -1 &&
636*7c478bd9Sstevel@tonic-gate 				    chip_designees[gstate[i].chip_id] == -1)
637*7c478bd9Sstevel@tonic-gate 					chip_designees[gstate[i].chip_id] = c;
638*7c478bd9Sstevel@tonic-gate 			}
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 			gstate[i++].cpuid = c;
641*7c478bd9Sstevel@tonic-gate 			break;
642*7c478bd9Sstevel@tonic-gate 		case P_OFFLINE:
643*7c478bd9Sstevel@tonic-gate 		case P_POWEROFF:
644*7c478bd9Sstevel@tonic-gate 		case P_FAULTED:
645*7c478bd9Sstevel@tonic-gate 		case P_SPARE:
646*7c478bd9Sstevel@tonic-gate 			gstate[i++].cpuid = -1;
647*7c478bd9Sstevel@tonic-gate 			break;
648*7c478bd9Sstevel@tonic-gate 		default:
649*7c478bd9Sstevel@tonic-gate 			gstate[i++].cpuid = -1;
650*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
651*7c478bd9Sstevel@tonic-gate 			    gettext("%s: cpu%d in unknown state\n"),
652*7c478bd9Sstevel@tonic-gate 			    opts->pgmname, c);
653*7c478bd9Sstevel@tonic-gate 			break;
654*7c478bd9Sstevel@tonic-gate 		case -1:
655*7c478bd9Sstevel@tonic-gate 			break;
656*7c478bd9Sstevel@tonic-gate 		}
657*7c478bd9Sstevel@tonic-gate 	}
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	/*
660*7c478bd9Sstevel@tonic-gate 	 * Examine the processor sets; if we're in one, only attempt
661*7c478bd9Sstevel@tonic-gate 	 * to report on the set we're in.
662*7c478bd9Sstevel@tonic-gate 	 */
663*7c478bd9Sstevel@tonic-gate 	if (pset_bind(PS_QUERY, P_PID, P_MYID, &mypset) == -1) {
664*7c478bd9Sstevel@tonic-gate 		errstr = strerror(errno);
665*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: pset_bind - %s\n"),
666*7c478bd9Sstevel@tonic-gate 		    opts->pgmname, errstr);
667*7c478bd9Sstevel@tonic-gate 	} else {
668*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncpus; i++) {
669*7c478bd9Sstevel@tonic-gate 			struct tstate *this = &gstate[i];
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 			if (this->cpuid == -1)
672*7c478bd9Sstevel@tonic-gate 				continue;
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 			if (pset_assign(PS_QUERY,
675*7c478bd9Sstevel@tonic-gate 			    this->cpuid, &cpupset) == -1) {
676*7c478bd9Sstevel@tonic-gate 				errstr = strerror(errno);
677*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
678*7c478bd9Sstevel@tonic-gate 				    gettext("%s: pset_assign - %s\n"),
679*7c478bd9Sstevel@tonic-gate 				    opts->pgmname, errstr);
680*7c478bd9Sstevel@tonic-gate 				continue;
681*7c478bd9Sstevel@tonic-gate 			}
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 			if (mypset != cpupset)
684*7c478bd9Sstevel@tonic-gate 				this->cpuid = -1;
685*7c478bd9Sstevel@tonic-gate 		}
686*7c478bd9Sstevel@tonic-gate 	}
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	if (opts->dotitle)
689*7c478bd9Sstevel@tonic-gate 		print_title(opts->master);
690*7c478bd9Sstevel@tonic-gate 	zerotime();
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
693*7c478bd9Sstevel@tonic-gate 		struct tstate *this = &gstate[i];
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 		if (this->cpuid == -1)
696*7c478bd9Sstevel@tonic-gate 			continue;
697*7c478bd9Sstevel@tonic-gate 		this->sgrp = cpc_setgrp_clone(opts->master);
698*7c478bd9Sstevel@tonic-gate 		if (this->sgrp == NULL) {
699*7c478bd9Sstevel@tonic-gate 			this->cpuid = -1;
700*7c478bd9Sstevel@tonic-gate 			continue;
701*7c478bd9Sstevel@tonic-gate 		}
702*7c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, 0, gtick, this,
703*7c478bd9Sstevel@tonic-gate 		    THR_BOUND|THR_NEW_LWP, &this->tid) == 0)
704*7c478bd9Sstevel@tonic-gate 			lwps++;
705*7c478bd9Sstevel@tonic-gate 		else {
706*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
707*7c478bd9Sstevel@tonic-gate 			    gettext("%s: cannot create thread for cpu%d\n"),
708*7c478bd9Sstevel@tonic-gate 			    opts->pgmname, this->cpuid);
709*7c478bd9Sstevel@tonic-gate 			this->status = 4;
710*7c478bd9Sstevel@tonic-gate 		}
711*7c478bd9Sstevel@tonic-gate 	}
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	if (lwps != 0)
714*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncpus; i++)
715*7c478bd9Sstevel@tonic-gate 			(void) thr_join(gstate[i].tid, NULL, NULL);
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	if ((accum = cpc_setgrp_clone(opts->master)) == NULL) {
718*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: out of heap\n"),
719*7c478bd9Sstevel@tonic-gate 		    opts->pgmname);
720*7c478bd9Sstevel@tonic-gate 		return (1);
721*7c478bd9Sstevel@tonic-gate 	}
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	retval = 0;
724*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
725*7c478bd9Sstevel@tonic-gate 		struct tstate *this = &gstate[i];
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 		if (this->cpuid == -1)
728*7c478bd9Sstevel@tonic-gate 			continue;
729*7c478bd9Sstevel@tonic-gate 		cpc_setgrp_accum(accum, this->sgrp);
730*7c478bd9Sstevel@tonic-gate 		cpc_setgrp_free(this->sgrp);
731*7c478bd9Sstevel@tonic-gate 		this->sgrp = NULL;
732*7c478bd9Sstevel@tonic-gate 		if (this->status != 0)
733*7c478bd9Sstevel@tonic-gate 			retval = 1;
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_reset(accum);
737*7c478bd9Sstevel@tonic-gate 	start = cpc_setgrp_getset(accum);
738*7c478bd9Sstevel@tonic-gate 	do {
739*7c478bd9Sstevel@tonic-gate 		nreqs = cpc_setgrp_getbufs(accum, &data1, &data2, &scratch);
740*7c478bd9Sstevel@tonic-gate 		print_total(lwps, *data1, nreqs, cpc_setgrp_getname(accum));
741*7c478bd9Sstevel@tonic-gate 	} while (cpc_setgrp_nextset(accum) != start);
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	cpc_setgrp_free(accum);
744*7c478bd9Sstevel@tonic-gate 	accum = NULL;
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	free(gstate);
747*7c478bd9Sstevel@tonic-gate 	return (retval);
748*7c478bd9Sstevel@tonic-gate }
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate static int
751*7c478bd9Sstevel@tonic-gate get_chipid(kstat_ctl_t *kc, processorid_t cpuid)
752*7c478bd9Sstevel@tonic-gate {
753*7c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
754*7c478bd9Sstevel@tonic-gate 	kstat_named_t	*k;
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL)
757*7c478bd9Sstevel@tonic-gate 		return (-1);
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1) {
760*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
761*7c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat_read() failed for cpu %d: %s\n"),
762*7c478bd9Sstevel@tonic-gate 		    opts->pgmname, cpuid, strerror(errno));
763*7c478bd9Sstevel@tonic-gate 		return (-1);
764*7c478bd9Sstevel@tonic-gate 	}
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 	if ((k = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id")) == NULL) {
767*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
768*7c478bd9Sstevel@tonic-gate 		    gettext("%s: chip_id not found for cpu %d: %s\n"),
769*7c478bd9Sstevel@tonic-gate 		    opts->pgmname, cpuid, strerror(errno));
770*7c478bd9Sstevel@tonic-gate 		return (-1);
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	return (k->value.i32);
774*7c478bd9Sstevel@tonic-gate }
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate static void *
777*7c478bd9Sstevel@tonic-gate soaker(void *arg)
778*7c478bd9Sstevel@tonic-gate {
779*7c478bd9Sstevel@tonic-gate 	struct tstate	*state = arg;
780*7c478bd9Sstevel@tonic-gate 	pcparms_t	pcparms;
781*7c478bd9Sstevel@tonic-gate 	fxparms_t	*fx = (fxparms_t *)pcparms.pc_clparms;
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	if (processor_bind(P_LWPID, P_MYID, state->cpuid, NULL) != 0)
784*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: couldn't bind soaker "
785*7c478bd9Sstevel@tonic-gate 		    "thread to cpu%d: %s\n"), opts->pgmname, state->cpuid,
786*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	/*
789*7c478bd9Sstevel@tonic-gate 	 * Put the soaker thread in the fixed priority (FX) class so it runs
790*7c478bd9Sstevel@tonic-gate 	 * at the lowest possible global priority.
791*7c478bd9Sstevel@tonic-gate 	 */
792*7c478bd9Sstevel@tonic-gate 	pcparms.pc_cid = fxinfo.pc_cid;
793*7c478bd9Sstevel@tonic-gate 	fx->fx_upri = 0;
794*7c478bd9Sstevel@tonic-gate 	fx->fx_uprilim = 0;
795*7c478bd9Sstevel@tonic-gate 	fx->fx_tqsecs = fx->fx_tqnsecs = FX_TQDEF;
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, &pcparms) != 0)
798*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: couldn't put soaker "
799*7c478bd9Sstevel@tonic-gate 		    "thread in FX sched class: %s\n"), opts->pgmname,
800*7c478bd9Sstevel@tonic-gate 		    strerror(errno));
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	/*
803*7c478bd9Sstevel@tonic-gate 	 * Let the parent thread know we're ready to roll.
804*7c478bd9Sstevel@tonic-gate 	 */
805*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&state->soak_lock);
806*7c478bd9Sstevel@tonic-gate 	state->soak_state = SOAK_RUN;
807*7c478bd9Sstevel@tonic-gate 	(void) cond_signal(&state->soak_cv);
808*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&state->soak_lock);
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	for (;;) {
811*7c478bd9Sstevel@tonic-gate spin:
812*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&state->soak_lock);
813*7c478bd9Sstevel@tonic-gate 		if (state->soak_state == SOAK_RUN) {
814*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&state->soak_lock);
815*7c478bd9Sstevel@tonic-gate 			goto spin;
816*7c478bd9Sstevel@tonic-gate 		}
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 		while (state->soak_state == SOAK_PAUSE)
819*7c478bd9Sstevel@tonic-gate 			(void) cond_wait(&state->soak_cv,
820*7c478bd9Sstevel@tonic-gate 			    &state->soak_lock);
821*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&state->soak_lock);
822*7c478bd9Sstevel@tonic-gate 	}
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
825*7c478bd9Sstevel@tonic-gate 	return (NULL);
826*7c478bd9Sstevel@tonic-gate }
827