xref: /illumos-gate/usr/src/cmd/cpc/common/cpustat.c (revision f9d4be10)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
581eba2fdSas  * Common Development and Distribution License (the "License").
681eba2fdSas  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2226fd7700SKrishnendu Sadhukhan - Sun Microsystems  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
2609d80ceaSBryan Cantrill /*
27c3377ee9SJohn Levon  * Copyright 2019 Joyent, Inc.
2809d80ceaSBryan Cantrill  */
2909d80ceaSBryan Cantrill 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/processor.h>
327c478bd9Sstevel@tonic-gate #include <sys/pset.h>
337c478bd9Sstevel@tonic-gate #include <sys/lwp.h>
347c478bd9Sstevel@tonic-gate #include <sys/priocntl.h>
357c478bd9Sstevel@tonic-gate #include <sys/fxpriocntl.h>
367c478bd9Sstevel@tonic-gate #include <time.h>
377c478bd9Sstevel@tonic-gate #include <stdio.h>
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <inttypes.h>
407c478bd9Sstevel@tonic-gate #include <unistd.h>
417c478bd9Sstevel@tonic-gate #include <limits.h>
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <strings.h>
447c478bd9Sstevel@tonic-gate #include <thread.h>
457c478bd9Sstevel@tonic-gate #include <errno.h>
467c478bd9Sstevel@tonic-gate #include <libintl.h>
477c478bd9Sstevel@tonic-gate #include <locale.h>
487c478bd9Sstevel@tonic-gate #include <kstat.h>
497c478bd9Sstevel@tonic-gate #include <synch.h>
507c478bd9Sstevel@tonic-gate #include <libcpc.h>
5181eba2fdSas #include <sys/resource.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include "cpucmds.h"
5426fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h"
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static struct options {
577c478bd9Sstevel@tonic-gate 	int debug;
587c478bd9Sstevel@tonic-gate 	int dotitle;
597c478bd9Sstevel@tonic-gate 	int dohelp;
607c478bd9Sstevel@tonic-gate 	int dotick;
617c478bd9Sstevel@tonic-gate 	int dosoaker;
627c478bd9Sstevel@tonic-gate 	int doperiod;
637c478bd9Sstevel@tonic-gate 	char *pgmname;
647c478bd9Sstevel@tonic-gate 	uint_t mseconds;
657c478bd9Sstevel@tonic-gate 	uint_t nsamples;
667c478bd9Sstevel@tonic-gate 	uint_t nsets;
677c478bd9Sstevel@tonic-gate 	uint_t mseconds_rest;
687c478bd9Sstevel@tonic-gate 	cpc_setgrp_t *master;
697c478bd9Sstevel@tonic-gate } __options;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * States for soaker threads.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #define	SOAK_PAUSE	0
757c478bd9Sstevel@tonic-gate #define	SOAK_RUN	1
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate struct tstate {
787c478bd9Sstevel@tonic-gate 	processorid_t	cpuid;
797c478bd9Sstevel@tonic-gate 	int		chip_id;
807c478bd9Sstevel@tonic-gate 	cpc_setgrp_t	*sgrp;
817c478bd9Sstevel@tonic-gate 	int		status;
827c478bd9Sstevel@tonic-gate 	thread_t	tid;
837c478bd9Sstevel@tonic-gate 	int		soak_state;
847c478bd9Sstevel@tonic-gate 	mutex_t		soak_lock;
857c478bd9Sstevel@tonic-gate 	cond_t		soak_cv;
867c478bd9Sstevel@tonic-gate };
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static const struct options *opts = (const struct options *)&__options;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate static cpc_t *cpc;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate struct tstate	*gstate;
937c478bd9Sstevel@tonic-gate static int	ncpus;
947c478bd9Sstevel@tonic-gate static int	max_chip_id;
957c478bd9Sstevel@tonic-gate static int	*chip_designees;    /* cpuid of CPU which counts for phs chip */
967c478bd9Sstevel@tonic-gate static int	smt = 0;	    /* If set, cpustat needs to be SMT-aware. */
97*f9d4be10SToomas Soome static pcinfo_t	fxinfo = { 0, "FX", 0 }; /* FX scheduler class info */
987c478bd9Sstevel@tonic-gate 
9926fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE;
10026fd7700SKrishnendu Sadhukhan - Sun Microsystems 
1017c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1027c478bd9Sstevel@tonic-gate static void
cpustat_errfn(const char * fn,int subcode,const char * fmt,va_list ap)1037c478bd9Sstevel@tonic-gate cpustat_errfn(const char *fn, int subcode, const char *fmt, va_list ap)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", opts->pgmname);
1067c478bd9Sstevel@tonic-gate 	if (opts->debug)
1077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", fn);
1087c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static int cpustat(void);
1127c478bd9Sstevel@tonic-gate static int get_chipid(kstat_ctl_t *kc, processorid_t cpuid);
1137c478bd9Sstevel@tonic-gate static void *soaker(void *arg);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1177c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
1187c478bd9Sstevel@tonic-gate #endif
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])1217c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	struct options	*opts = &__options;
1247c478bd9Sstevel@tonic-gate 	int		c, errcnt = 0, ret;
1257c478bd9Sstevel@tonic-gate 	cpc_setgrp_t	*sgrp;
1267c478bd9Sstevel@tonic-gate 	char		*errstr;
1277c478bd9Sstevel@tonic-gate 	double		period;
1287c478bd9Sstevel@tonic-gate 	char		*endp;
12981eba2fdSas 	struct rlimit	rl;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1327c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if ((opts->pgmname = strrchr(argv[0], '/')) == NULL)
1357c478bd9Sstevel@tonic-gate 		opts->pgmname = argv[0];
1367c478bd9Sstevel@tonic-gate 	else
1377c478bd9Sstevel@tonic-gate 		opts->pgmname++;
1387c478bd9Sstevel@tonic-gate 
13981eba2fdSas 	/* Make sure we can open enough files */
14081eba2fdSas 	rl.rlim_max = rl.rlim_cur = RLIM_INFINITY;
14181eba2fdSas 	if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
14281eba2fdSas 		errstr = strerror(errno);
14381eba2fdSas 		(void) fprintf(stderr,
14426fd7700SKrishnendu Sadhukhan - Sun Microsystems 		    gettext("%s: setrlimit failed - %s\n"),
14526fd7700SKrishnendu Sadhukhan - Sun Microsystems 		    opts->pgmname, errstr);
14681eba2fdSas 	}
14781eba2fdSas 
1487c478bd9Sstevel@tonic-gate 	if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
1497c478bd9Sstevel@tonic-gate 		errstr = strerror(errno);
1507c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: cannot access performance "
1517c478bd9Sstevel@tonic-gate 		    "counters - %s\n"), opts->pgmname, errstr);
1527c478bd9Sstevel@tonic-gate 		return (1);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	(void) cpc_seterrhndlr(cpc, cpustat_errfn);
1567c478bd9Sstevel@tonic-gate 	strtoset_errfn = cpustat_errfn;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	/*
1597c478bd9Sstevel@tonic-gate 	 * Check to see if cpustat needs to be SMT-aware.
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	smt = smt_limited_cpc_hw(cpc);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	/*
1647c478bd9Sstevel@tonic-gate 	 * Establish some defaults
1657c478bd9Sstevel@tonic-gate 	 */
1667c478bd9Sstevel@tonic-gate 	opts->mseconds = 5000;
1677c478bd9Sstevel@tonic-gate 	opts->nsamples = UINT_MAX;
1687c478bd9Sstevel@tonic-gate 	opts->dotitle = 1;
1697c478bd9Sstevel@tonic-gate 	if ((opts->master = cpc_setgrp_new(cpc, smt)) == NULL) {
1707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: out of heap\n"),
1717c478bd9Sstevel@tonic-gate 		    opts->pgmname);
1727c478bd9Sstevel@tonic-gate 		return (1);
1737c478bd9Sstevel@tonic-gate 	}
1747c478bd9Sstevel@tonic-gate 
17526fd7700SKrishnendu Sadhukhan - Sun Microsystems 	while ((c = getopt(argc, argv, "Dc:hntT:sp:")) != EOF && errcnt == 0)
1767c478bd9Sstevel@tonic-gate 		switch (c) {
1777c478bd9Sstevel@tonic-gate 		case 'D':			/* enable debugging */
1787c478bd9Sstevel@tonic-gate 			opts->debug++;
1797c478bd9Sstevel@tonic-gate 			break;
1807c478bd9Sstevel@tonic-gate 		case 'c':			/* specify statistics */
1817c478bd9Sstevel@tonic-gate 			if ((sgrp = cpc_setgrp_newset(opts->master,
1827c478bd9Sstevel@tonic-gate 			    optarg, &errcnt)) != NULL)
1837c478bd9Sstevel@tonic-gate 				opts->master = sgrp;
1847c478bd9Sstevel@tonic-gate 			break;
1857c478bd9Sstevel@tonic-gate 		case 'n':			/* no titles */
1867c478bd9Sstevel@tonic-gate 			opts->dotitle = 0;
1877c478bd9Sstevel@tonic-gate 			break;
1887c478bd9Sstevel@tonic-gate 		case 'p':			/* periodic behavior */
1897c478bd9Sstevel@tonic-gate 			opts->doperiod = 1;
1907c478bd9Sstevel@tonic-gate 			period = strtod(optarg, &endp);
1917c478bd9Sstevel@tonic-gate 			if (*endp != '\0') {
1927c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: invalid "
1937c478bd9Sstevel@tonic-gate 				    "parameter \"%s\"\n"), opts->pgmname,
1947c478bd9Sstevel@tonic-gate 				    optarg);
1957c478bd9Sstevel@tonic-gate 				errcnt++;
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 			break;
1987c478bd9Sstevel@tonic-gate 		case 's':			/* run soaker thread */
1997c478bd9Sstevel@tonic-gate 			opts->dosoaker = 1;
2007c478bd9Sstevel@tonic-gate 			break;
2017c478bd9Sstevel@tonic-gate 		case 't':			/* print %tick */
2027c478bd9Sstevel@tonic-gate 			opts->dotick = 1;
2037c478bd9Sstevel@tonic-gate 			break;
20426fd7700SKrishnendu Sadhukhan - Sun Microsystems 		case 'T':
20526fd7700SKrishnendu Sadhukhan - Sun Microsystems 			if (optarg) {
20626fd7700SKrishnendu Sadhukhan - Sun Microsystems 				if (*optarg == 'u')
20726fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = UDATE;
20826fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else if (*optarg == 'd')
20926fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = DDATE;
21026fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else
21126fd7700SKrishnendu Sadhukhan - Sun Microsystems 					errcnt++;
21226fd7700SKrishnendu Sadhukhan - Sun Microsystems 			} else {
21326fd7700SKrishnendu Sadhukhan - Sun Microsystems 				errcnt++;
21426fd7700SKrishnendu Sadhukhan - Sun Microsystems 			}
21526fd7700SKrishnendu Sadhukhan - Sun Microsystems 			break;
2167c478bd9Sstevel@tonic-gate 		case 'h':			/* help */
2177c478bd9Sstevel@tonic-gate 			opts->dohelp = 1;
2187c478bd9Sstevel@tonic-gate 			break;
2197c478bd9Sstevel@tonic-gate 		case '?':
2207c478bd9Sstevel@tonic-gate 		default:
2217c478bd9Sstevel@tonic-gate 			errcnt++;
2227c478bd9Sstevel@tonic-gate 			break;
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	switch (argc - optind) {
2267c478bd9Sstevel@tonic-gate 	case 0:
2277c478bd9Sstevel@tonic-gate 		break;
2287c478bd9Sstevel@tonic-gate 	case 2:
2297c478bd9Sstevel@tonic-gate 		opts->nsamples = strtol(argv[optind + 1], &endp, 10);
2307c478bd9Sstevel@tonic-gate 		if (*endp != '\0') {
2317c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2327c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid argument \"%s\"\n"),
2337c478bd9Sstevel@tonic-gate 			    opts->pgmname, argv[optind + 1]);
2347c478bd9Sstevel@tonic-gate 			errcnt++;
2357c478bd9Sstevel@tonic-gate 			break;
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 		/*FALLTHROUGH*/
2387c478bd9Sstevel@tonic-gate 	case 1:
2397c478bd9Sstevel@tonic-gate 		opts->mseconds = (uint_t)(strtod(argv[optind], &endp) * 1000.0);
2407c478bd9Sstevel@tonic-gate 		if (*endp != '\0') {
2417c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2427c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid argument \"%s\"\n"),
2437c478bd9Sstevel@tonic-gate 			    opts->pgmname, argv[optind]);
2447c478bd9Sstevel@tonic-gate 			errcnt++;
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 		break;
2477c478bd9Sstevel@tonic-gate 	default:
2487c478bd9Sstevel@tonic-gate 		errcnt++;
2497c478bd9Sstevel@tonic-gate 		break;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (opts->nsamples == 0 || opts->mseconds == 0)
2537c478bd9Sstevel@tonic-gate 		errcnt++;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	if (errcnt != 0 || opts->dohelp ||
2567c478bd9Sstevel@tonic-gate 	    (opts->nsets = cpc_setgrp_numsets(opts->master)) == 0) {
2577c478bd9Sstevel@tonic-gate 		(void) fprintf(opts->dohelp ? stdout : stderr, gettext(
258bd181d5aSRyan Zezeski 		    "Usage:\n\t%s -c spec [-c spec]... [-p period] [-T u|d]\n"
259bd181d5aSRyan Zezeski 		    "\t\t[-sntD] [interval [count]]\n\n"
260bd181d5aSRyan Zezeski 		    "\t-c spec\t  specify processor events to be monitored\n"
2617c478bd9Sstevel@tonic-gate 		    "\t-n\t  suppress titles\n"
2627c478bd9Sstevel@tonic-gate 		    "\t-p period cycle through event list periodically\n"
2637c478bd9Sstevel@tonic-gate 		    "\t-s\t  run user soaker thread for system-only events\n"
2647c478bd9Sstevel@tonic-gate 		    "\t-t\t  include %s register\n"
26526fd7700SKrishnendu Sadhukhan - Sun Microsystems 		    "\t-T d|u\t  Display a timestamp in date (d) or unix "
26626fd7700SKrishnendu Sadhukhan - Sun Microsystems 		    "time_t (u)\n"
2677c478bd9Sstevel@tonic-gate 		    "\t-D\t  enable debug mode\n"
2687c478bd9Sstevel@tonic-gate 		    "\t-h\t  print extended usage information\n\n"
2697c478bd9Sstevel@tonic-gate 		    "\tUse cputrack(1) to monitor per-process statistics.\n"),
2707c478bd9Sstevel@tonic-gate 		    opts->pgmname, CPC_TICKREG_NAME);
2717c478bd9Sstevel@tonic-gate 		if (opts->dohelp) {
2727c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
2737c478bd9Sstevel@tonic-gate 			(void) capabilities(cpc, stdout);
2747c478bd9Sstevel@tonic-gate 			exit(0);
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 		exit(2);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	/*
2807c478bd9Sstevel@tonic-gate 	 * If the user requested periodic behavior, calculate the rest time
2817c478bd9Sstevel@tonic-gate 	 * between cycles.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	if (opts->doperiod) {
2847c478bd9Sstevel@tonic-gate 		opts->mseconds_rest = (uint_t)((period * 1000.0) -
2857c478bd9Sstevel@tonic-gate 		    (opts->mseconds * opts->nsets));
2867c478bd9Sstevel@tonic-gate 		if ((int)opts->mseconds_rest < 0)
2877c478bd9Sstevel@tonic-gate 			opts->mseconds_rest = 0;
2887c478bd9Sstevel@tonic-gate 		if (opts->nsamples != UINT_MAX)
2897c478bd9Sstevel@tonic-gate 			opts->nsamples *= opts->nsets;
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	cpc_setgrp_reset(opts->master);
2937c478bd9Sstevel@tonic-gate 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
2947c478bd9Sstevel@tonic-gate 
29509d80ceaSBryan Cantrill 	/*
29609d80ceaSBryan Cantrill 	 * By design, cpustat (regrettably) has multiple threads racing in
29709d80ceaSBryan Cantrill 	 * write(2) to generate output.  As there are no guarantees made with
29809d80ceaSBryan Cantrill 	 * respect to the atomicity of concurrent writes on non-O_APPEND file
29909d80ceaSBryan Cantrill 	 * descriptors, we must set O_APPEND on stdout to assure that no output
30009d80ceaSBryan Cantrill 	 * is lost.  If cpustat is rearchitected such that only one thread is
30109d80ceaSBryan Cantrill 	 * generating output (which would also assure that the output is always
30209d80ceaSBryan Cantrill 	 * in a consistent order), this code should be removed.
30309d80ceaSBryan Cantrill 	 */
30409d80ceaSBryan Cantrill 	if (fcntl(1, F_SETFL, fcntl(1, F_GETFL) | O_APPEND) == -1) {
30509d80ceaSBryan Cantrill 		(void) fprintf(stderr, gettext("%s: cannot set output to be "
30609d80ceaSBryan Cantrill 		    "append-only - %s\n"), opts->pgmname, strerror(errno));
30709d80ceaSBryan Cantrill 		return (1);
30809d80ceaSBryan Cantrill 	}
30909d80ceaSBryan Cantrill 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * If no system-mode only sets were created, no soaker threads will be
3127c478bd9Sstevel@tonic-gate 	 * needed.
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 	if (opts->dosoaker == 1 && cpc_setgrp_has_sysonly(opts->master) == 0)
3157c478bd9Sstevel@tonic-gate 		opts->dosoaker = 0;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	ret = cpustat();
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	(void) cpc_close(cpc);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	return (ret);
3227c478bd9Sstevel@tonic-gate }
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate static void
print_title(cpc_setgrp_t * sgrp)3257c478bd9Sstevel@tonic-gate print_title(cpc_setgrp_t *sgrp)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	(void) printf("%7s %3s %5s ", "time", "cpu", "event");
3287c478bd9Sstevel@tonic-gate 	if (opts->dotick)
3297c478bd9Sstevel@tonic-gate 		(void) printf("%9s ", CPC_TICKREG_NAME);
3307c478bd9Sstevel@tonic-gate 	(void) printf("%s\n", cpc_setgrp_gethdr(sgrp));
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate static void
print_sample(processorid_t cpuid,cpc_buf_t * buf,int nreq,const char * setname,int sibling)3347c478bd9Sstevel@tonic-gate print_sample(processorid_t cpuid, cpc_buf_t *buf, int nreq, const char *setname,
3357c478bd9Sstevel@tonic-gate     int sibling)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	char		line[1024];
3387c478bd9Sstevel@tonic-gate 	int		ccnt;
3397c478bd9Sstevel@tonic-gate 	int		i;
3407c478bd9Sstevel@tonic-gate 	uint64_t	val;
3417c478bd9Sstevel@tonic-gate 	uint64_t	tick;
3427c478bd9Sstevel@tonic-gate 	hrtime_t	hrtime;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	hrtime = cpc_buf_hrtime(cpc, buf);
3457c478bd9Sstevel@tonic-gate 	tick = cpc_buf_tick(cpc, buf);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	ccnt = snprintf(line, sizeof (line), "%7.3f %3d %5s ",
3487c478bd9Sstevel@tonic-gate 	    mstimestamp(hrtime), (int)cpuid, "tick");
3497c478bd9Sstevel@tonic-gate 	if (opts->dotick)
3507c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
3517c478bd9Sstevel@tonic-gate 		    "%9" PRId64 " ", tick);
3527c478bd9Sstevel@tonic-gate 	for (i = 0; i < nreq; i++) {
3537c478bd9Sstevel@tonic-gate 		(void) cpc_buf_get(cpc, buf, i, &val);
3547c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
3557c478bd9Sstevel@tonic-gate 		    "%9" PRId64 " ", val);
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 	if (opts->nsets > 1)
3587c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
3597c478bd9Sstevel@tonic-gate 		    " # %s\n", setname);
3607c478bd9Sstevel@tonic-gate 	else
3617c478bd9Sstevel@tonic-gate 		ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, "\n");
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (sibling) {
3647c478bd9Sstevel@tonic-gate 		/*
3657c478bd9Sstevel@tonic-gate 		 * This sample is being printed for a "sibling" CPU -- that is,
3667c478bd9Sstevel@tonic-gate 		 * a CPU which does not have its own CPC set bound. It is being
3677c478bd9Sstevel@tonic-gate 		 * measured via a set bound to another CPU sharing its physical
3687c478bd9Sstevel@tonic-gate 		 * processor.
3697c478bd9Sstevel@tonic-gate 		 */
3707c478bd9Sstevel@tonic-gate 		int designee = chip_designees[gstate[cpuid].chip_id];
3717c478bd9Sstevel@tonic-gate 		char *p;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if ((p = strrchr(line, '#')) == NULL)
3747c478bd9Sstevel@tonic-gate 			p = strrchr(line, '\n');
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		if (p != NULL) {
3777c478bd9Sstevel@tonic-gate 			*p = '\0';
3787c478bd9Sstevel@tonic-gate 			ccnt = strlen(line);
3797c478bd9Sstevel@tonic-gate 			ccnt += snprintf(line + ccnt, sizeof (line) - ccnt,
3807c478bd9Sstevel@tonic-gate 			    "# counter shared with CPU %d\n", designee);
3817c478bd9Sstevel@tonic-gate 		}
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
38426fd7700SKrishnendu Sadhukhan - Sun Microsystems 	if (timestamp_fmt != NODATE)
38526fd7700SKrishnendu Sadhukhan - Sun Microsystems 		print_timestamp(timestamp_fmt);
3867c478bd9Sstevel@tonic-gate 	if (ccnt > sizeof (line))
3877c478bd9Sstevel@tonic-gate 		ccnt = sizeof (line);
3887c478bd9Sstevel@tonic-gate 	if (ccnt > 0)
3897c478bd9Sstevel@tonic-gate 		(void) write(1, line, ccnt);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * If this CPU is the chip designee for any other CPUs, print a line for
3937c478bd9Sstevel@tonic-gate 	 * them here.
3947c478bd9Sstevel@tonic-gate 	 */
3957c478bd9Sstevel@tonic-gate 	if (smt && (sibling == 0)) {
3967c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncpus; i++) {
3977c478bd9Sstevel@tonic-gate 			if ((i != cpuid) && (gstate[i].cpuid != -1) &&
3987c478bd9Sstevel@tonic-gate 			    (chip_designees[gstate[i].chip_id] == cpuid))
3997c478bd9Sstevel@tonic-gate 				print_sample(i, buf, nreq, setname, 1);
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate static void
print_total(int ncpus,cpc_buf_t * buf,int nreq,const char * setname)4057c478bd9Sstevel@tonic-gate print_total(int ncpus, cpc_buf_t *buf, int nreq, const char *setname)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	int		i;
4087c478bd9Sstevel@tonic-gate 	uint64_t	val;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	(void) printf("%7.3f %3d %5s ", mstimestamp(cpc_buf_hrtime(cpc, buf)),
4117c478bd9Sstevel@tonic-gate 	    ncpus, "total");
4127c478bd9Sstevel@tonic-gate 	if (opts->dotick)
4137c478bd9Sstevel@tonic-gate 		(void) printf("%9" PRId64 " ", cpc_buf_tick(cpc, buf));
4147c478bd9Sstevel@tonic-gate 	for (i = 0; i < nreq; i++) {
4157c478bd9Sstevel@tonic-gate 		(void) cpc_buf_get(cpc, buf, i, &val);
4167c478bd9Sstevel@tonic-gate 		(void) printf("%9" PRId64 " ", val);
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 	if (opts->nsets > 1)
4197c478bd9Sstevel@tonic-gate 		(void) printf(" # %s", setname);
4207c478bd9Sstevel@tonic-gate 	(void) fputc('\n', stdout);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate #define	NSECS_PER_MSEC	1000000ll
4247c478bd9Sstevel@tonic-gate #define	NSECS_PER_SEC	1000000000ll
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate static void *
gtick(void * arg)4277c478bd9Sstevel@tonic-gate gtick(void *arg)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	struct tstate		*state = arg;
4307c478bd9Sstevel@tonic-gate 	char			*errstr;
4317c478bd9Sstevel@tonic-gate 	uint_t			nsamples;
4327c478bd9Sstevel@tonic-gate 	uint_t			sample_cnt = 1;
4337c478bd9Sstevel@tonic-gate 	hrtime_t		ht, htdelta, restdelta;
4347c478bd9Sstevel@tonic-gate 	cpc_setgrp_t		*sgrp = state->sgrp;
4357c478bd9Sstevel@tonic-gate 	cpc_set_t		*this = cpc_setgrp_getset(sgrp);
4367c478bd9Sstevel@tonic-gate 	const char		*name = cpc_setgrp_getname(sgrp);
4377c478bd9Sstevel@tonic-gate 	cpc_buf_t		**data1, **data2, **scratch;
4387c478bd9Sstevel@tonic-gate 	cpc_buf_t		*tmp;
4397c478bd9Sstevel@tonic-gate 	int			nreqs;
4407c478bd9Sstevel@tonic-gate 	thread_t		tid;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	htdelta = NSECS_PER_MSEC * opts->mseconds;
4437c478bd9Sstevel@tonic-gate 	restdelta = NSECS_PER_MSEC * opts->mseconds_rest;
4447c478bd9Sstevel@tonic-gate 	ht = gethrtime();
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/*
4477c478bd9Sstevel@tonic-gate 	 * If this CPU is SMT, we run one gtick() thread per _physical_ CPU,
4487c478bd9Sstevel@tonic-gate 	 * instead of per cpu_t. The following check returns if it detects that
4497c478bd9Sstevel@tonic-gate 	 * this cpu_t has not been designated to do the counting for this
4507c478bd9Sstevel@tonic-gate 	 * physical CPU.
4517c478bd9Sstevel@tonic-gate 	 */
4527c478bd9Sstevel@tonic-gate 	if (smt && chip_designees[state->chip_id] != state->cpuid)
4537c478bd9Sstevel@tonic-gate 		return (NULL);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/*
4567c478bd9Sstevel@tonic-gate 	 * If we need to run a soaker thread on this CPU, start it here.
4577c478bd9Sstevel@tonic-gate 	 */
4587c478bd9Sstevel@tonic-gate 	if (opts->dosoaker) {
4597c478bd9Sstevel@tonic-gate 		if (cond_init(&state->soak_cv, USYNC_THREAD, NULL) != 0)
4607c478bd9Sstevel@tonic-gate 			goto bad;
4617c478bd9Sstevel@tonic-gate 		if (mutex_init(&state->soak_lock, USYNC_THREAD,
4627c478bd9Sstevel@tonic-gate 		    NULL) != 0)
4637c478bd9Sstevel@tonic-gate 			goto bad;
4647c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&state->soak_lock);
4657c478bd9Sstevel@tonic-gate 		state->soak_state = SOAK_PAUSE;
466*f9d4be10SToomas Soome 		if (thr_create(NULL, 0, soaker, state, 0, &tid) != 0)
4677c478bd9Sstevel@tonic-gate 			goto bad;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		while (state->soak_state == SOAK_PAUSE)
4707c478bd9Sstevel@tonic-gate 			(void) cond_wait(&state->soak_cv,
4717c478bd9Sstevel@tonic-gate 			    &state->soak_lock);
4727c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&state->soak_lock);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 		/*
4757c478bd9Sstevel@tonic-gate 		 * If the soaker needs to pause for the first set, stop it now.
4767c478bd9Sstevel@tonic-gate 		 */
4777c478bd9Sstevel@tonic-gate 		if (cpc_setgrp_sysonly(sgrp) == 0) {
4787c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&state->soak_lock);
4797c478bd9Sstevel@tonic-gate 			state->soak_state = SOAK_PAUSE;
4807c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&state->soak_lock);
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 	if (cpc_bind_cpu(cpc, state->cpuid, this, 0) == -1)
4847c478bd9Sstevel@tonic-gate 		goto bad;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	for (nsamples = opts->nsamples; nsamples; nsamples--, sample_cnt++) {
4877c478bd9Sstevel@tonic-gate 		hrtime_t htnow;
4887c478bd9Sstevel@tonic-gate 		struct timespec ts;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		ht += htdelta;
4937c478bd9Sstevel@tonic-gate 		htnow = gethrtime();
4947c478bd9Sstevel@tonic-gate 		if (ht <= htnow)
4957c478bd9Sstevel@tonic-gate 			continue;
4967c478bd9Sstevel@tonic-gate 		ts.tv_sec = (time_t)((ht - htnow) / NSECS_PER_SEC);
4977c478bd9Sstevel@tonic-gate 		ts.tv_nsec = (suseconds_t)((ht - htnow) % NSECS_PER_SEC);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 		(void) nanosleep(&ts, NULL);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		if (opts->nsets == 1) {
5027c478bd9Sstevel@tonic-gate 			/*
5037c478bd9Sstevel@tonic-gate 			 * If we're dealing with one set, buffer usage is:
5047c478bd9Sstevel@tonic-gate 			 *
5057c478bd9Sstevel@tonic-gate 			 * data1 = most recent data snapshot
5067c478bd9Sstevel@tonic-gate 			 * data2 = previous data snapshot
5077c478bd9Sstevel@tonic-gate 			 * scratch = used for diffing data1 and data2
5087c478bd9Sstevel@tonic-gate 			 *
5097c478bd9Sstevel@tonic-gate 			 * Save the snapshot from the previous sample in data2
5107c478bd9Sstevel@tonic-gate 			 * before putting the current sample in data1.
5117c478bd9Sstevel@tonic-gate 			 */
5127c478bd9Sstevel@tonic-gate 			tmp = *data1;
5137c478bd9Sstevel@tonic-gate 			*data1 = *data2;
5147c478bd9Sstevel@tonic-gate 			*data2 = tmp;
5157c478bd9Sstevel@tonic-gate 			if (cpc_set_sample(cpc, this, *data1) != 0)
5167c478bd9Sstevel@tonic-gate 				goto bad;
5177c478bd9Sstevel@tonic-gate 			cpc_buf_sub(cpc, *scratch, *data1, *data2);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 			print_sample(state->cpuid, *scratch, nreqs, name, 0);
5207c478bd9Sstevel@tonic-gate 		} else {
5217c478bd9Sstevel@tonic-gate 			/*
5227c478bd9Sstevel@tonic-gate 			 * More than one set is in use (multiple -c options
5237c478bd9Sstevel@tonic-gate 			 * given). Buffer usage in this case is:
5247c478bd9Sstevel@tonic-gate 			 *
5257c478bd9Sstevel@tonic-gate 			 * data1 = total counts for this set since program began
5267c478bd9Sstevel@tonic-gate 			 * data2 = unused
5277c478bd9Sstevel@tonic-gate 			 * scratch = most recent data snapshot
5287c478bd9Sstevel@tonic-gate 			 */
5297c478bd9Sstevel@tonic-gate 			name = cpc_setgrp_getname(sgrp);
5307c478bd9Sstevel@tonic-gate 			nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2,
5317c478bd9Sstevel@tonic-gate 			    &scratch);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 			if (cpc_set_sample(cpc, this, *scratch) != 0)
5347c478bd9Sstevel@tonic-gate 				goto bad;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 			cpc_buf_add(cpc, *data1, *data1, *scratch);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 			if (cpc_unbind(cpc, this) != 0)
5397c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext("%s: error "
5407c478bd9Sstevel@tonic-gate 				    "unbinding on cpu %d - %s\n"),
5417c478bd9Sstevel@tonic-gate 				    opts->pgmname, state->cpuid,
5427c478bd9Sstevel@tonic-gate 				    strerror(errno));
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 			this = cpc_setgrp_nextset(sgrp);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 			print_sample(state->cpuid, *scratch, nreqs, name, 0);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 			/*
5497c478bd9Sstevel@tonic-gate 			 * If periodic behavior was requested, rest here.
5507c478bd9Sstevel@tonic-gate 			 */
5517c478bd9Sstevel@tonic-gate 			if (opts->doperiod && opts->mseconds_rest > 0 &&
55226fd7700SKrishnendu Sadhukhan - Sun Microsystems 			    (sample_cnt % opts->nsets) == 0) {
5537c478bd9Sstevel@tonic-gate 				/*
5547c478bd9Sstevel@tonic-gate 				 * Stop the soaker while the tool rests.
5557c478bd9Sstevel@tonic-gate 				 */
5567c478bd9Sstevel@tonic-gate 				if (opts->dosoaker) {
5577c478bd9Sstevel@tonic-gate 					(void) mutex_lock(&state->soak_lock);
5587c478bd9Sstevel@tonic-gate 					if (state->soak_state == SOAK_RUN)
5597c478bd9Sstevel@tonic-gate 						state->soak_state = SOAK_PAUSE;
5607c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&state->soak_lock);
5617c478bd9Sstevel@tonic-gate 				}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 				htnow = gethrtime();
5647c478bd9Sstevel@tonic-gate 				ht += restdelta;
5657c478bd9Sstevel@tonic-gate 				ts.tv_sec = (time_t)((ht - htnow) /
5667c478bd9Sstevel@tonic-gate 				    NSECS_PER_SEC);
5677c478bd9Sstevel@tonic-gate 				ts.tv_nsec = (suseconds_t)((ht - htnow) %
5687c478bd9Sstevel@tonic-gate 				    NSECS_PER_SEC);
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 				(void) nanosleep(&ts, NULL);
5717c478bd9Sstevel@tonic-gate 			}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 			/*
5747c478bd9Sstevel@tonic-gate 			 * Start or stop the soaker if needed.
5757c478bd9Sstevel@tonic-gate 			 */
5767c478bd9Sstevel@tonic-gate 			if (opts->dosoaker) {
5777c478bd9Sstevel@tonic-gate 				(void) mutex_lock(&state->soak_lock);
5787c478bd9Sstevel@tonic-gate 				if (cpc_setgrp_sysonly(sgrp) &&
5797c478bd9Sstevel@tonic-gate 				    state->soak_state == SOAK_PAUSE) {
5807c478bd9Sstevel@tonic-gate 					/*
5817c478bd9Sstevel@tonic-gate 					 * Soaker is paused but the next set is
5827c478bd9Sstevel@tonic-gate 					 * sysonly: start the soaker.
5837c478bd9Sstevel@tonic-gate 					 */
5847c478bd9Sstevel@tonic-gate 					state->soak_state = SOAK_RUN;
5857c478bd9Sstevel@tonic-gate 					(void) cond_signal(&state->soak_cv);
5867c478bd9Sstevel@tonic-gate 				} else if (cpc_setgrp_sysonly(sgrp) == 0 &&
5877c478bd9Sstevel@tonic-gate 				    state->soak_state == SOAK_RUN)
5887c478bd9Sstevel@tonic-gate 					/*
5897c478bd9Sstevel@tonic-gate 					 * Soaker is running but the next set
5907c478bd9Sstevel@tonic-gate 					 * counts user events: stop the soaker.
5917c478bd9Sstevel@tonic-gate 					 */
5927c478bd9Sstevel@tonic-gate 					state->soak_state = SOAK_PAUSE;
5937c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&state->soak_lock);
5947c478bd9Sstevel@tonic-gate 			}
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 			if (cpc_bind_cpu(cpc, state->cpuid, this, 0) != 0)
5977c478bd9Sstevel@tonic-gate 				goto bad;
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (cpc_unbind(cpc, this) != 0)
6027c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: error unbinding on"
6037c478bd9Sstevel@tonic-gate 		    " cpu %d - %s\n"), opts->pgmname,
6047c478bd9Sstevel@tonic-gate 		    state->cpuid, strerror(errno));
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	/*
6077c478bd9Sstevel@tonic-gate 	 * We're done, so stop the soaker if needed.
6087c478bd9Sstevel@tonic-gate 	 */
6097c478bd9Sstevel@tonic-gate 	if (opts->dosoaker) {
6107c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&state->soak_lock);
6117c478bd9Sstevel@tonic-gate 		if (state->soak_state == SOAK_RUN)
6127c478bd9Sstevel@tonic-gate 			state->soak_state = SOAK_PAUSE;
6137c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&state->soak_lock);
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	return (NULL);
6177c478bd9Sstevel@tonic-gate bad:
6187c478bd9Sstevel@tonic-gate 	state->status = 3;
6197c478bd9Sstevel@tonic-gate 	errstr = strerror(errno);
6207c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: cpu%d - %s\n"),
6217c478bd9Sstevel@tonic-gate 	    opts->pgmname, state->cpuid, errstr);
6227c478bd9Sstevel@tonic-gate 	return (NULL);
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate static int
cpustat(void)6267c478bd9Sstevel@tonic-gate cpustat(void)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	cpc_setgrp_t	*accum;
6297c478bd9Sstevel@tonic-gate 	cpc_set_t	*start;
6307c478bd9Sstevel@tonic-gate 	int		c, i, retval;
6317c478bd9Sstevel@tonic-gate 	int		lwps = 0;
6327c478bd9Sstevel@tonic-gate 	psetid_t	mypset, cpupset;
6337c478bd9Sstevel@tonic-gate 	char		*errstr;
6347c478bd9Sstevel@tonic-gate 	cpc_buf_t	**data1, **data2, **scratch;
6357c478bd9Sstevel@tonic-gate 	int		nreqs;
6367c478bd9Sstevel@tonic-gate 	kstat_ctl_t	*kc;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	ncpus = (int)sysconf(_SC_NPROCESSORS_CONF);
6397c478bd9Sstevel@tonic-gate 	if ((gstate = calloc(ncpus, sizeof (*gstate))) == NULL) {
6407c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
6417c478bd9Sstevel@tonic-gate 		    "%s: out of heap\n"), opts->pgmname);
6427c478bd9Sstevel@tonic-gate 		return (1);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	max_chip_id = sysconf(_SC_CPUID_MAX);
6467c478bd9Sstevel@tonic-gate 	if ((chip_designees = malloc(max_chip_id * sizeof (int))) == NULL) {
6477c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
64826fd7700SKrishnendu Sadhukhan - Sun Microsystems 		    "%s: out of heap\n"), opts->pgmname);
6497c478bd9Sstevel@tonic-gate 		return (1);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	for (i = 0; i < max_chip_id; i++)
6527c478bd9Sstevel@tonic-gate 		chip_designees[i] = -1;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	if (smt) {
6557c478bd9Sstevel@tonic-gate 		if ((kc = kstat_open()) == NULL) {
6567c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
65726fd7700SKrishnendu Sadhukhan - Sun Microsystems 			    "%s: kstat_open() failed: %s\n"), opts->pgmname,
6587c478bd9Sstevel@tonic-gate 			    strerror(errno));
65926fd7700SKrishnendu Sadhukhan - Sun Microsystems 			return (1);
6607c478bd9Sstevel@tonic-gate 		}
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (opts->dosoaker)
6647c478bd9Sstevel@tonic-gate 		if (priocntl(0, 0, PC_GETCID, &fxinfo) == -1) {
6657c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
66626fd7700SKrishnendu Sadhukhan - Sun Microsystems 			    "%s: couldn't get FX scheduler class: %s\n"),
6677c478bd9Sstevel@tonic-gate 			    opts->pgmname, strerror(errno));
6687c478bd9Sstevel@tonic-gate 			return (1);
6697c478bd9Sstevel@tonic-gate 		}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	/*
6727c478bd9Sstevel@tonic-gate 	 * Only include processors that are participating in the system
6737c478bd9Sstevel@tonic-gate 	 */
6747c478bd9Sstevel@tonic-gate 	for (c = 0, i = 0; i < ncpus; c++) {
6757c478bd9Sstevel@tonic-gate 		switch (p_online(c, P_STATUS)) {
6767c478bd9Sstevel@tonic-gate 		case P_ONLINE:
6777c478bd9Sstevel@tonic-gate 		case P_NOINTR:
6787c478bd9Sstevel@tonic-gate 			if (smt) {
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 				gstate[i].chip_id = get_chipid(kc, c);
6817c478bd9Sstevel@tonic-gate 				if (gstate[i].chip_id != -1 &&
6827c478bd9Sstevel@tonic-gate 				    chip_designees[gstate[i].chip_id] == -1)
6837c478bd9Sstevel@tonic-gate 					chip_designees[gstate[i].chip_id] = c;
6847c478bd9Sstevel@tonic-gate 			}
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 			gstate[i++].cpuid = c;
6877c478bd9Sstevel@tonic-gate 			break;
6887c478bd9Sstevel@tonic-gate 		case P_OFFLINE:
6897c478bd9Sstevel@tonic-gate 		case P_POWEROFF:
6907c478bd9Sstevel@tonic-gate 		case P_FAULTED:
6917c478bd9Sstevel@tonic-gate 		case P_SPARE:
692c3377ee9SJohn Levon 		case P_DISABLED:
6937c478bd9Sstevel@tonic-gate 			gstate[i++].cpuid = -1;
6947c478bd9Sstevel@tonic-gate 			break;
6957c478bd9Sstevel@tonic-gate 		default:
6967c478bd9Sstevel@tonic-gate 			gstate[i++].cpuid = -1;
6977c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6987c478bd9Sstevel@tonic-gate 			    gettext("%s: cpu%d in unknown state\n"),
6997c478bd9Sstevel@tonic-gate 			    opts->pgmname, c);
7007c478bd9Sstevel@tonic-gate 			break;
7017c478bd9Sstevel@tonic-gate 		case -1:
7027c478bd9Sstevel@tonic-gate 			break;
7037c478bd9Sstevel@tonic-gate 		}
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * Examine the processor sets; if we're in one, only attempt
7087c478bd9Sstevel@tonic-gate 	 * to report on the set we're in.
7097c478bd9Sstevel@tonic-gate 	 */
7107c478bd9Sstevel@tonic-gate 	if (pset_bind(PS_QUERY, P_PID, P_MYID, &mypset) == -1) {
7117c478bd9Sstevel@tonic-gate 		errstr = strerror(errno);
7127c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: pset_bind - %s\n"),
7137c478bd9Sstevel@tonic-gate 		    opts->pgmname, errstr);
7147c478bd9Sstevel@tonic-gate 	} else {
7157c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncpus; i++) {
7167c478bd9Sstevel@tonic-gate 			struct tstate *this = &gstate[i];
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 			if (this->cpuid == -1)
7197c478bd9Sstevel@tonic-gate 				continue;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 			if (pset_assign(PS_QUERY,
7227c478bd9Sstevel@tonic-gate 			    this->cpuid, &cpupset) == -1) {
7237c478bd9Sstevel@tonic-gate 				errstr = strerror(errno);
7247c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7257c478bd9Sstevel@tonic-gate 				    gettext("%s: pset_assign - %s\n"),
7267c478bd9Sstevel@tonic-gate 				    opts->pgmname, errstr);
7277c478bd9Sstevel@tonic-gate 				continue;
7287c478bd9Sstevel@tonic-gate 			}
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 			if (mypset != cpupset)
7317c478bd9Sstevel@tonic-gate 				this->cpuid = -1;
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	if (opts->dotitle)
7367c478bd9Sstevel@tonic-gate 		print_title(opts->master);
7377c478bd9Sstevel@tonic-gate 	zerotime();
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
7407c478bd9Sstevel@tonic-gate 		struct tstate *this = &gstate[i];
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		if (this->cpuid == -1)
7437c478bd9Sstevel@tonic-gate 			continue;
7447c478bd9Sstevel@tonic-gate 		this->sgrp = cpc_setgrp_clone(opts->master);
7457c478bd9Sstevel@tonic-gate 		if (this->sgrp == NULL) {
7467c478bd9Sstevel@tonic-gate 			this->cpuid = -1;
7477c478bd9Sstevel@tonic-gate 			continue;
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, 0, gtick, this,
7507c478bd9Sstevel@tonic-gate 		    THR_BOUND|THR_NEW_LWP, &this->tid) == 0)
7517c478bd9Sstevel@tonic-gate 			lwps++;
7527c478bd9Sstevel@tonic-gate 		else {
7537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
7547c478bd9Sstevel@tonic-gate 			    gettext("%s: cannot create thread for cpu%d\n"),
7557c478bd9Sstevel@tonic-gate 			    opts->pgmname, this->cpuid);
7567c478bd9Sstevel@tonic-gate 			this->status = 4;
7577c478bd9Sstevel@tonic-gate 		}
7587c478bd9Sstevel@tonic-gate 	}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	if (lwps != 0)
7617c478bd9Sstevel@tonic-gate 		for (i = 0; i < ncpus; i++)
7627c478bd9Sstevel@tonic-gate 			(void) thr_join(gstate[i].tid, NULL, NULL);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	if ((accum = cpc_setgrp_clone(opts->master)) == NULL) {
7657c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: out of heap\n"),
7667c478bd9Sstevel@tonic-gate 		    opts->pgmname);
7677c478bd9Sstevel@tonic-gate 		return (1);
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	retval = 0;
7717c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
7727c478bd9Sstevel@tonic-gate 		struct tstate *this = &gstate[i];
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 		if (this->cpuid == -1)
7757c478bd9Sstevel@tonic-gate 			continue;
7767c478bd9Sstevel@tonic-gate 		cpc_setgrp_accum(accum, this->sgrp);
7777c478bd9Sstevel@tonic-gate 		cpc_setgrp_free(this->sgrp);
7787c478bd9Sstevel@tonic-gate 		this->sgrp = NULL;
7797c478bd9Sstevel@tonic-gate 		if (this->status != 0)
7807c478bd9Sstevel@tonic-gate 			retval = 1;
7817c478bd9Sstevel@tonic-gate 	}
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	cpc_setgrp_reset(accum);
7847c478bd9Sstevel@tonic-gate 	start = cpc_setgrp_getset(accum);
7857c478bd9Sstevel@tonic-gate 	do {
7867c478bd9Sstevel@tonic-gate 		nreqs = cpc_setgrp_getbufs(accum, &data1, &data2, &scratch);
7877c478bd9Sstevel@tonic-gate 		print_total(lwps, *data1, nreqs, cpc_setgrp_getname(accum));
7887c478bd9Sstevel@tonic-gate 	} while (cpc_setgrp_nextset(accum) != start);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	cpc_setgrp_free(accum);
7917c478bd9Sstevel@tonic-gate 	accum = NULL;
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	free(gstate);
7947c478bd9Sstevel@tonic-gate 	return (retval);
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate static int
get_chipid(kstat_ctl_t * kc,processorid_t cpuid)7987c478bd9Sstevel@tonic-gate get_chipid(kstat_ctl_t *kc, processorid_t cpuid)
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
8017c478bd9Sstevel@tonic-gate 	kstat_named_t	*k;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL)
8047c478bd9Sstevel@tonic-gate 		return (-1);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1) {
8077c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
8087c478bd9Sstevel@tonic-gate 		    gettext("%s: kstat_read() failed for cpu %d: %s\n"),
8097c478bd9Sstevel@tonic-gate 		    opts->pgmname, cpuid, strerror(errno));
8107c478bd9Sstevel@tonic-gate 		return (-1);
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if ((k = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id")) == NULL) {
8147c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
8157c478bd9Sstevel@tonic-gate 		    gettext("%s: chip_id not found for cpu %d: %s\n"),
8167c478bd9Sstevel@tonic-gate 		    opts->pgmname, cpuid, strerror(errno));
8177c478bd9Sstevel@tonic-gate 		return (-1);
8187c478bd9Sstevel@tonic-gate 	}
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	return (k->value.i32);
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static void *
soaker(void * arg)8247c478bd9Sstevel@tonic-gate soaker(void *arg)
8257c478bd9Sstevel@tonic-gate {
8267c478bd9Sstevel@tonic-gate 	struct tstate	*state = arg;
8277c478bd9Sstevel@tonic-gate 	pcparms_t	pcparms;
8287c478bd9Sstevel@tonic-gate 	fxparms_t	*fx = (fxparms_t *)pcparms.pc_clparms;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	if (processor_bind(P_LWPID, P_MYID, state->cpuid, NULL) != 0)
8317c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: couldn't bind soaker "
8327c478bd9Sstevel@tonic-gate 		    "thread to cpu%d: %s\n"), opts->pgmname, state->cpuid,
8337c478bd9Sstevel@tonic-gate 		    strerror(errno));
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	/*
8367c478bd9Sstevel@tonic-gate 	 * Put the soaker thread in the fixed priority (FX) class so it runs
8377c478bd9Sstevel@tonic-gate 	 * at the lowest possible global priority.
8387c478bd9Sstevel@tonic-gate 	 */
8397c478bd9Sstevel@tonic-gate 	pcparms.pc_cid = fxinfo.pc_cid;
8407c478bd9Sstevel@tonic-gate 	fx->fx_upri = 0;
8417c478bd9Sstevel@tonic-gate 	fx->fx_uprilim = 0;
8427c478bd9Sstevel@tonic-gate 	fx->fx_tqsecs = fx->fx_tqnsecs = FX_TQDEF;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, &pcparms) != 0)
8457c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: couldn't put soaker "
8467c478bd9Sstevel@tonic-gate 		    "thread in FX sched class: %s\n"), opts->pgmname,
8477c478bd9Sstevel@tonic-gate 		    strerror(errno));
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	/*
8507c478bd9Sstevel@tonic-gate 	 * Let the parent thread know we're ready to roll.
8517c478bd9Sstevel@tonic-gate 	 */
8527c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&state->soak_lock);
8537c478bd9Sstevel@tonic-gate 	state->soak_state = SOAK_RUN;
8547c478bd9Sstevel@tonic-gate 	(void) cond_signal(&state->soak_cv);
8557c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&state->soak_lock);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	for (;;) {
8587c478bd9Sstevel@tonic-gate spin:
8597c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&state->soak_lock);
8607c478bd9Sstevel@tonic-gate 		if (state->soak_state == SOAK_RUN) {
8617c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&state->soak_lock);
8627c478bd9Sstevel@tonic-gate 			goto spin;
8637c478bd9Sstevel@tonic-gate 		}
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 		while (state->soak_state == SOAK_PAUSE)
8667c478bd9Sstevel@tonic-gate 			(void) cond_wait(&state->soak_cv,
8677c478bd9Sstevel@tonic-gate 			    &state->soak_lock);
8687c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&state->soak_lock);
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
8727c478bd9Sstevel@tonic-gate 	return (NULL);
8737c478bd9Sstevel@tonic-gate }
874