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