10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53438Sas198278 * Common Development and Distribution License (the "License"). 63438Sas198278 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*10265SKrishnendu.Sadhukhan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/types.h> 270Sstevel@tonic-gate #include <sys/processor.h> 280Sstevel@tonic-gate #include <sys/pset.h> 290Sstevel@tonic-gate #include <sys/lwp.h> 300Sstevel@tonic-gate #include <sys/priocntl.h> 310Sstevel@tonic-gate #include <sys/fxpriocntl.h> 320Sstevel@tonic-gate #include <time.h> 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <stdlib.h> 350Sstevel@tonic-gate #include <inttypes.h> 360Sstevel@tonic-gate #include <unistd.h> 370Sstevel@tonic-gate #include <limits.h> 380Sstevel@tonic-gate #include <string.h> 390Sstevel@tonic-gate #include <strings.h> 400Sstevel@tonic-gate #include <thread.h> 410Sstevel@tonic-gate #include <errno.h> 420Sstevel@tonic-gate #include <libintl.h> 430Sstevel@tonic-gate #include <locale.h> 440Sstevel@tonic-gate #include <kstat.h> 450Sstevel@tonic-gate #include <synch.h> 460Sstevel@tonic-gate #include <libcpc.h> 473438Sas198278 #include <sys/resource.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate #include "cpucmds.h" 50*10265SKrishnendu.Sadhukhan@Sun.COM #include "statcommon.h" 510Sstevel@tonic-gate 520Sstevel@tonic-gate static struct options { 530Sstevel@tonic-gate int debug; 540Sstevel@tonic-gate int dotitle; 550Sstevel@tonic-gate int dohelp; 560Sstevel@tonic-gate int dotick; 570Sstevel@tonic-gate int dosoaker; 580Sstevel@tonic-gate int doperiod; 590Sstevel@tonic-gate char *pgmname; 600Sstevel@tonic-gate uint_t mseconds; 610Sstevel@tonic-gate uint_t nsamples; 620Sstevel@tonic-gate uint_t nsets; 630Sstevel@tonic-gate uint_t mseconds_rest; 640Sstevel@tonic-gate cpc_setgrp_t *master; 650Sstevel@tonic-gate } __options; 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * States for soaker threads. 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate #define SOAK_PAUSE 0 710Sstevel@tonic-gate #define SOAK_RUN 1 720Sstevel@tonic-gate 730Sstevel@tonic-gate struct tstate { 740Sstevel@tonic-gate processorid_t cpuid; 750Sstevel@tonic-gate int chip_id; 760Sstevel@tonic-gate cpc_setgrp_t *sgrp; 770Sstevel@tonic-gate int status; 780Sstevel@tonic-gate thread_t tid; 790Sstevel@tonic-gate int soak_state; 800Sstevel@tonic-gate mutex_t soak_lock; 810Sstevel@tonic-gate cond_t soak_cv; 820Sstevel@tonic-gate }; 830Sstevel@tonic-gate 840Sstevel@tonic-gate static const struct options *opts = (const struct options *)&__options; 850Sstevel@tonic-gate 860Sstevel@tonic-gate static cpc_t *cpc; 870Sstevel@tonic-gate 880Sstevel@tonic-gate struct tstate *gstate; 890Sstevel@tonic-gate static int ncpus; 900Sstevel@tonic-gate static int max_chip_id; 910Sstevel@tonic-gate static int *chip_designees; /* cpuid of CPU which counts for phs chip */ 920Sstevel@tonic-gate static int smt = 0; /* If set, cpustat needs to be SMT-aware. */ 930Sstevel@tonic-gate static pcinfo_t fxinfo = { 0, "FX", NULL }; /* FX scheduler class info */ 940Sstevel@tonic-gate 95*10265SKrishnendu.Sadhukhan@Sun.COM static uint_t timestamp_fmt = NODATE; 96*10265SKrishnendu.Sadhukhan@Sun.COM 970Sstevel@tonic-gate /*ARGSUSED*/ 980Sstevel@tonic-gate static void 990Sstevel@tonic-gate cpustat_errfn(const char *fn, int subcode, const char *fmt, va_list ap) 1000Sstevel@tonic-gate { 1010Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", opts->pgmname); 1020Sstevel@tonic-gate if (opts->debug) 1030Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", fn); 1040Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static int cpustat(void); 1080Sstevel@tonic-gate static int get_chipid(kstat_ctl_t *kc, processorid_t cpuid); 1090Sstevel@tonic-gate static void *soaker(void *arg); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 1130Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 1140Sstevel@tonic-gate #endif 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate int 1170Sstevel@tonic-gate main(int argc, char *argv[]) 1180Sstevel@tonic-gate { 1190Sstevel@tonic-gate struct options *opts = &__options; 1200Sstevel@tonic-gate int c, errcnt = 0, ret; 1210Sstevel@tonic-gate cpc_setgrp_t *sgrp; 1220Sstevel@tonic-gate char *errstr; 1230Sstevel@tonic-gate double period; 1240Sstevel@tonic-gate char *endp; 1253438Sas198278 struct rlimit rl; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1280Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate if ((opts->pgmname = strrchr(argv[0], '/')) == NULL) 1310Sstevel@tonic-gate opts->pgmname = argv[0]; 1320Sstevel@tonic-gate else 1330Sstevel@tonic-gate opts->pgmname++; 1340Sstevel@tonic-gate 1353438Sas198278 /* Make sure we can open enough files */ 1363438Sas198278 rl.rlim_max = rl.rlim_cur = RLIM_INFINITY; 1373438Sas198278 if (setrlimit(RLIMIT_NOFILE, &rl) != 0) { 1383438Sas198278 errstr = strerror(errno); 1393438Sas198278 (void) fprintf(stderr, 140*10265SKrishnendu.Sadhukhan@Sun.COM gettext("%s: setrlimit failed - %s\n"), 141*10265SKrishnendu.Sadhukhan@Sun.COM opts->pgmname, errstr); 1423438Sas198278 } 1433438Sas198278 1440Sstevel@tonic-gate if ((cpc = cpc_open(CPC_VER_CURRENT)) == NULL) { 1450Sstevel@tonic-gate errstr = strerror(errno); 1460Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cannot access performance " 1470Sstevel@tonic-gate "counters - %s\n"), opts->pgmname, errstr); 1480Sstevel@tonic-gate return (1); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate (void) cpc_seterrhndlr(cpc, cpustat_errfn); 1520Sstevel@tonic-gate strtoset_errfn = cpustat_errfn; 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * Check to see if cpustat needs to be SMT-aware. 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate smt = smt_limited_cpc_hw(cpc); 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate /* 1600Sstevel@tonic-gate * Establish some defaults 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate opts->mseconds = 5000; 1630Sstevel@tonic-gate opts->nsamples = UINT_MAX; 1640Sstevel@tonic-gate opts->dotitle = 1; 1650Sstevel@tonic-gate if ((opts->master = cpc_setgrp_new(cpc, smt)) == NULL) { 1660Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: out of heap\n"), 1670Sstevel@tonic-gate opts->pgmname); 1680Sstevel@tonic-gate return (1); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 171*10265SKrishnendu.Sadhukhan@Sun.COM while ((c = getopt(argc, argv, "Dc:hntT:sp:")) != EOF && errcnt == 0) 1720Sstevel@tonic-gate switch (c) { 1730Sstevel@tonic-gate case 'D': /* enable debugging */ 1740Sstevel@tonic-gate opts->debug++; 1750Sstevel@tonic-gate break; 1760Sstevel@tonic-gate case 'c': /* specify statistics */ 1770Sstevel@tonic-gate if ((sgrp = cpc_setgrp_newset(opts->master, 1780Sstevel@tonic-gate optarg, &errcnt)) != NULL) 1790Sstevel@tonic-gate opts->master = sgrp; 1800Sstevel@tonic-gate break; 1810Sstevel@tonic-gate case 'n': /* no titles */ 1820Sstevel@tonic-gate opts->dotitle = 0; 1830Sstevel@tonic-gate break; 1840Sstevel@tonic-gate case 'p': /* periodic behavior */ 1850Sstevel@tonic-gate opts->doperiod = 1; 1860Sstevel@tonic-gate period = strtod(optarg, &endp); 1870Sstevel@tonic-gate if (*endp != '\0') { 1880Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: invalid " 1890Sstevel@tonic-gate "parameter \"%s\"\n"), opts->pgmname, 1900Sstevel@tonic-gate optarg); 1910Sstevel@tonic-gate errcnt++; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate break; 1940Sstevel@tonic-gate case 's': /* run soaker thread */ 1950Sstevel@tonic-gate opts->dosoaker = 1; 1960Sstevel@tonic-gate break; 1970Sstevel@tonic-gate case 't': /* print %tick */ 1980Sstevel@tonic-gate opts->dotick = 1; 1990Sstevel@tonic-gate break; 200*10265SKrishnendu.Sadhukhan@Sun.COM case 'T': 201*10265SKrishnendu.Sadhukhan@Sun.COM if (optarg) { 202*10265SKrishnendu.Sadhukhan@Sun.COM if (*optarg == 'u') 203*10265SKrishnendu.Sadhukhan@Sun.COM timestamp_fmt = UDATE; 204*10265SKrishnendu.Sadhukhan@Sun.COM else if (*optarg == 'd') 205*10265SKrishnendu.Sadhukhan@Sun.COM timestamp_fmt = DDATE; 206*10265SKrishnendu.Sadhukhan@Sun.COM else 207*10265SKrishnendu.Sadhukhan@Sun.COM errcnt++; 208*10265SKrishnendu.Sadhukhan@Sun.COM } else { 209*10265SKrishnendu.Sadhukhan@Sun.COM errcnt++; 210*10265SKrishnendu.Sadhukhan@Sun.COM } 211*10265SKrishnendu.Sadhukhan@Sun.COM break; 2120Sstevel@tonic-gate case 'h': /* help */ 2130Sstevel@tonic-gate opts->dohelp = 1; 2140Sstevel@tonic-gate break; 2150Sstevel@tonic-gate case '?': 2160Sstevel@tonic-gate default: 2170Sstevel@tonic-gate errcnt++; 2180Sstevel@tonic-gate break; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate switch (argc - optind) { 2220Sstevel@tonic-gate case 0: 2230Sstevel@tonic-gate break; 2240Sstevel@tonic-gate case 2: 2250Sstevel@tonic-gate opts->nsamples = strtol(argv[optind + 1], &endp, 10); 2260Sstevel@tonic-gate if (*endp != '\0') { 2270Sstevel@tonic-gate (void) fprintf(stderr, 2280Sstevel@tonic-gate gettext("%s: invalid argument \"%s\"\n"), 2290Sstevel@tonic-gate opts->pgmname, argv[optind + 1]); 2300Sstevel@tonic-gate errcnt++; 2310Sstevel@tonic-gate break; 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate /*FALLTHROUGH*/ 2340Sstevel@tonic-gate case 1: 2350Sstevel@tonic-gate opts->mseconds = (uint_t)(strtod(argv[optind], &endp) * 1000.0); 2360Sstevel@tonic-gate if (*endp != '\0') { 2370Sstevel@tonic-gate (void) fprintf(stderr, 2380Sstevel@tonic-gate gettext("%s: invalid argument \"%s\"\n"), 2390Sstevel@tonic-gate opts->pgmname, argv[optind]); 2400Sstevel@tonic-gate errcnt++; 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate break; 2430Sstevel@tonic-gate default: 2440Sstevel@tonic-gate errcnt++; 2450Sstevel@tonic-gate break; 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate if (opts->nsamples == 0 || opts->mseconds == 0) 2490Sstevel@tonic-gate errcnt++; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate if (errcnt != 0 || opts->dohelp || 2520Sstevel@tonic-gate (opts->nsets = cpc_setgrp_numsets(opts->master)) == 0) { 2530Sstevel@tonic-gate (void) fprintf(opts->dohelp ? stdout : stderr, gettext( 2540Sstevel@tonic-gate "Usage:\n\t%s [-c events] [-p period] [-nstD] " 255*10265SKrishnendu.Sadhukhan@Sun.COM "[-T d|u] [interval [count]]\n\n" 2560Sstevel@tonic-gate "\t-c events specify processor events to be monitored\n" 2570Sstevel@tonic-gate "\t-n\t suppress titles\n" 2580Sstevel@tonic-gate "\t-p period cycle through event list periodically\n" 2590Sstevel@tonic-gate "\t-s\t run user soaker thread for system-only events\n" 2600Sstevel@tonic-gate "\t-t\t include %s register\n" 261*10265SKrishnendu.Sadhukhan@Sun.COM "\t-T d|u\t Display a timestamp in date (d) or unix " 262*10265SKrishnendu.Sadhukhan@Sun.COM "time_t (u)\n" 2630Sstevel@tonic-gate "\t-D\t enable debug mode\n" 2640Sstevel@tonic-gate "\t-h\t print extended usage information\n\n" 2650Sstevel@tonic-gate "\tUse cputrack(1) to monitor per-process statistics.\n"), 2660Sstevel@tonic-gate opts->pgmname, CPC_TICKREG_NAME); 2670Sstevel@tonic-gate if (opts->dohelp) { 2680Sstevel@tonic-gate (void) putchar('\n'); 2690Sstevel@tonic-gate (void) capabilities(cpc, stdout); 2700Sstevel@tonic-gate exit(0); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate exit(2); 2730Sstevel@tonic-gate } 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate /* 2760Sstevel@tonic-gate * If the user requested periodic behavior, calculate the rest time 2770Sstevel@tonic-gate * between cycles. 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate if (opts->doperiod) { 2800Sstevel@tonic-gate opts->mseconds_rest = (uint_t)((period * 1000.0) - 2810Sstevel@tonic-gate (opts->mseconds * opts->nsets)); 2820Sstevel@tonic-gate if ((int)opts->mseconds_rest < 0) 2830Sstevel@tonic-gate opts->mseconds_rest = 0; 2840Sstevel@tonic-gate if (opts->nsamples != UINT_MAX) 2850Sstevel@tonic-gate opts->nsamples *= opts->nsets; 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate cpc_setgrp_reset(opts->master); 2890Sstevel@tonic-gate (void) setvbuf(stdout, NULL, _IOLBF, 0); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * If no system-mode only sets were created, no soaker threads will be 2930Sstevel@tonic-gate * needed. 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate if (opts->dosoaker == 1 && cpc_setgrp_has_sysonly(opts->master) == 0) 2960Sstevel@tonic-gate opts->dosoaker = 0; 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate ret = cpustat(); 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate (void) cpc_close(cpc); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate return (ret); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate static void 3060Sstevel@tonic-gate print_title(cpc_setgrp_t *sgrp) 3070Sstevel@tonic-gate { 3080Sstevel@tonic-gate (void) printf("%7s %3s %5s ", "time", "cpu", "event"); 3090Sstevel@tonic-gate if (opts->dotick) 3100Sstevel@tonic-gate (void) printf("%9s ", CPC_TICKREG_NAME); 3110Sstevel@tonic-gate (void) printf("%s\n", cpc_setgrp_gethdr(sgrp)); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate static void 3150Sstevel@tonic-gate print_sample(processorid_t cpuid, cpc_buf_t *buf, int nreq, const char *setname, 3160Sstevel@tonic-gate int sibling) 3170Sstevel@tonic-gate { 3180Sstevel@tonic-gate char line[1024]; 3190Sstevel@tonic-gate int ccnt; 3200Sstevel@tonic-gate int i; 3210Sstevel@tonic-gate uint64_t val; 3220Sstevel@tonic-gate uint64_t tick; 3230Sstevel@tonic-gate hrtime_t hrtime; 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate hrtime = cpc_buf_hrtime(cpc, buf); 3260Sstevel@tonic-gate tick = cpc_buf_tick(cpc, buf); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate ccnt = snprintf(line, sizeof (line), "%7.3f %3d %5s ", 3290Sstevel@tonic-gate mstimestamp(hrtime), (int)cpuid, "tick"); 3300Sstevel@tonic-gate if (opts->dotick) 3310Sstevel@tonic-gate ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, 3320Sstevel@tonic-gate "%9" PRId64 " ", tick); 3330Sstevel@tonic-gate for (i = 0; i < nreq; i++) { 3340Sstevel@tonic-gate (void) cpc_buf_get(cpc, buf, i, &val); 3350Sstevel@tonic-gate ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, 3360Sstevel@tonic-gate "%9" PRId64 " ", val); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate if (opts->nsets > 1) 3390Sstevel@tonic-gate ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, 3400Sstevel@tonic-gate " # %s\n", setname); 3410Sstevel@tonic-gate else 3420Sstevel@tonic-gate ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, "\n"); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if (sibling) { 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * This sample is being printed for a "sibling" CPU -- that is, 3470Sstevel@tonic-gate * a CPU which does not have its own CPC set bound. It is being 3480Sstevel@tonic-gate * measured via a set bound to another CPU sharing its physical 3490Sstevel@tonic-gate * processor. 3500Sstevel@tonic-gate */ 3510Sstevel@tonic-gate int designee = chip_designees[gstate[cpuid].chip_id]; 3520Sstevel@tonic-gate char *p; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if ((p = strrchr(line, '#')) == NULL) 3550Sstevel@tonic-gate p = strrchr(line, '\n'); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate if (p != NULL) { 3580Sstevel@tonic-gate *p = '\0'; 3590Sstevel@tonic-gate ccnt = strlen(line); 3600Sstevel@tonic-gate ccnt += snprintf(line + ccnt, sizeof (line) - ccnt, 3610Sstevel@tonic-gate "# counter shared with CPU %d\n", designee); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 365*10265SKrishnendu.Sadhukhan@Sun.COM if (timestamp_fmt != NODATE) 366*10265SKrishnendu.Sadhukhan@Sun.COM print_timestamp(timestamp_fmt); 3670Sstevel@tonic-gate if (ccnt > sizeof (line)) 3680Sstevel@tonic-gate ccnt = sizeof (line); 3690Sstevel@tonic-gate if (ccnt > 0) 3700Sstevel@tonic-gate (void) write(1, line, ccnt); 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * If this CPU is the chip designee for any other CPUs, print a line for 3740Sstevel@tonic-gate * them here. 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate if (smt && (sibling == 0)) { 3770Sstevel@tonic-gate for (i = 0; i < ncpus; i++) { 3780Sstevel@tonic-gate if ((i != cpuid) && (gstate[i].cpuid != -1) && 3790Sstevel@tonic-gate (chip_designees[gstate[i].chip_id] == cpuid)) 3800Sstevel@tonic-gate print_sample(i, buf, nreq, setname, 1); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate static void 3860Sstevel@tonic-gate print_total(int ncpus, cpc_buf_t *buf, int nreq, const char *setname) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate int i; 3890Sstevel@tonic-gate uint64_t val; 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate (void) printf("%7.3f %3d %5s ", mstimestamp(cpc_buf_hrtime(cpc, buf)), 3920Sstevel@tonic-gate ncpus, "total"); 3930Sstevel@tonic-gate if (opts->dotick) 3940Sstevel@tonic-gate (void) printf("%9" PRId64 " ", cpc_buf_tick(cpc, buf)); 3950Sstevel@tonic-gate for (i = 0; i < nreq; i++) { 3960Sstevel@tonic-gate (void) cpc_buf_get(cpc, buf, i, &val); 3970Sstevel@tonic-gate (void) printf("%9" PRId64 " ", val); 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate if (opts->nsets > 1) 4000Sstevel@tonic-gate (void) printf(" # %s", setname); 4010Sstevel@tonic-gate (void) fputc('\n', stdout); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate #define NSECS_PER_MSEC 1000000ll 4050Sstevel@tonic-gate #define NSECS_PER_SEC 1000000000ll 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate static void * 4080Sstevel@tonic-gate gtick(void *arg) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate struct tstate *state = arg; 4110Sstevel@tonic-gate char *errstr; 4120Sstevel@tonic-gate uint_t nsamples; 4130Sstevel@tonic-gate uint_t sample_cnt = 1; 4140Sstevel@tonic-gate hrtime_t ht, htdelta, restdelta; 4150Sstevel@tonic-gate cpc_setgrp_t *sgrp = state->sgrp; 4160Sstevel@tonic-gate cpc_set_t *this = cpc_setgrp_getset(sgrp); 4170Sstevel@tonic-gate const char *name = cpc_setgrp_getname(sgrp); 4180Sstevel@tonic-gate cpc_buf_t **data1, **data2, **scratch; 4190Sstevel@tonic-gate cpc_buf_t *tmp; 4200Sstevel@tonic-gate int nreqs; 4210Sstevel@tonic-gate thread_t tid; 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate htdelta = NSECS_PER_MSEC * opts->mseconds; 4240Sstevel@tonic-gate restdelta = NSECS_PER_MSEC * opts->mseconds_rest; 4250Sstevel@tonic-gate ht = gethrtime(); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate /* 4280Sstevel@tonic-gate * If this CPU is SMT, we run one gtick() thread per _physical_ CPU, 4290Sstevel@tonic-gate * instead of per cpu_t. The following check returns if it detects that 4300Sstevel@tonic-gate * this cpu_t has not been designated to do the counting for this 4310Sstevel@tonic-gate * physical CPU. 4320Sstevel@tonic-gate */ 4330Sstevel@tonic-gate if (smt && chip_designees[state->chip_id] != state->cpuid) 4340Sstevel@tonic-gate return (NULL); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * If we need to run a soaker thread on this CPU, start it here. 4380Sstevel@tonic-gate */ 4390Sstevel@tonic-gate if (opts->dosoaker) { 4400Sstevel@tonic-gate if (cond_init(&state->soak_cv, USYNC_THREAD, NULL) != 0) 4410Sstevel@tonic-gate goto bad; 4420Sstevel@tonic-gate if (mutex_init(&state->soak_lock, USYNC_THREAD, 4430Sstevel@tonic-gate NULL) != 0) 4440Sstevel@tonic-gate goto bad; 4450Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 4460Sstevel@tonic-gate state->soak_state = SOAK_PAUSE; 4470Sstevel@tonic-gate if (thr_create(NULL, 0, soaker, state, NULL, &tid) != 0) 4480Sstevel@tonic-gate goto bad; 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate while (state->soak_state == SOAK_PAUSE) 4510Sstevel@tonic-gate (void) cond_wait(&state->soak_cv, 4520Sstevel@tonic-gate &state->soak_lock); 4530Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * If the soaker needs to pause for the first set, stop it now. 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate if (cpc_setgrp_sysonly(sgrp) == 0) { 4590Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 4600Sstevel@tonic-gate state->soak_state = SOAK_PAUSE; 4610Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate if (cpc_bind_cpu(cpc, state->cpuid, this, 0) == -1) 4650Sstevel@tonic-gate goto bad; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate for (nsamples = opts->nsamples; nsamples; nsamples--, sample_cnt++) { 4680Sstevel@tonic-gate hrtime_t htnow; 4690Sstevel@tonic-gate struct timespec ts; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2, &scratch); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate ht += htdelta; 4740Sstevel@tonic-gate htnow = gethrtime(); 4750Sstevel@tonic-gate if (ht <= htnow) 4760Sstevel@tonic-gate continue; 4770Sstevel@tonic-gate ts.tv_sec = (time_t)((ht - htnow) / NSECS_PER_SEC); 4780Sstevel@tonic-gate ts.tv_nsec = (suseconds_t)((ht - htnow) % NSECS_PER_SEC); 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate (void) nanosleep(&ts, NULL); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if (opts->nsets == 1) { 4830Sstevel@tonic-gate /* 4840Sstevel@tonic-gate * If we're dealing with one set, buffer usage is: 4850Sstevel@tonic-gate * 4860Sstevel@tonic-gate * data1 = most recent data snapshot 4870Sstevel@tonic-gate * data2 = previous data snapshot 4880Sstevel@tonic-gate * scratch = used for diffing data1 and data2 4890Sstevel@tonic-gate * 4900Sstevel@tonic-gate * Save the snapshot from the previous sample in data2 4910Sstevel@tonic-gate * before putting the current sample in data1. 4920Sstevel@tonic-gate */ 4930Sstevel@tonic-gate tmp = *data1; 4940Sstevel@tonic-gate *data1 = *data2; 4950Sstevel@tonic-gate *data2 = tmp; 4960Sstevel@tonic-gate if (cpc_set_sample(cpc, this, *data1) != 0) 4970Sstevel@tonic-gate goto bad; 4980Sstevel@tonic-gate cpc_buf_sub(cpc, *scratch, *data1, *data2); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate print_sample(state->cpuid, *scratch, nreqs, name, 0); 5010Sstevel@tonic-gate } else { 5020Sstevel@tonic-gate /* 5030Sstevel@tonic-gate * More than one set is in use (multiple -c options 5040Sstevel@tonic-gate * given). Buffer usage in this case is: 5050Sstevel@tonic-gate * 5060Sstevel@tonic-gate * data1 = total counts for this set since program began 5070Sstevel@tonic-gate * data2 = unused 5080Sstevel@tonic-gate * scratch = most recent data snapshot 5090Sstevel@tonic-gate */ 5100Sstevel@tonic-gate name = cpc_setgrp_getname(sgrp); 5110Sstevel@tonic-gate nreqs = cpc_setgrp_getbufs(sgrp, &data1, &data2, 5120Sstevel@tonic-gate &scratch); 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate if (cpc_set_sample(cpc, this, *scratch) != 0) 5150Sstevel@tonic-gate goto bad; 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate cpc_buf_add(cpc, *data1, *data1, *scratch); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate if (cpc_unbind(cpc, this) != 0) 5200Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: error " 5210Sstevel@tonic-gate "unbinding on cpu %d - %s\n"), 5220Sstevel@tonic-gate opts->pgmname, state->cpuid, 5230Sstevel@tonic-gate strerror(errno)); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate this = cpc_setgrp_nextset(sgrp); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate print_sample(state->cpuid, *scratch, nreqs, name, 0); 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /* 5300Sstevel@tonic-gate * If periodic behavior was requested, rest here. 5310Sstevel@tonic-gate */ 5320Sstevel@tonic-gate if (opts->doperiod && opts->mseconds_rest > 0 && 533*10265SKrishnendu.Sadhukhan@Sun.COM (sample_cnt % opts->nsets) == 0) { 5340Sstevel@tonic-gate /* 5350Sstevel@tonic-gate * Stop the soaker while the tool rests. 5360Sstevel@tonic-gate */ 5370Sstevel@tonic-gate if (opts->dosoaker) { 5380Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 5390Sstevel@tonic-gate if (state->soak_state == SOAK_RUN) 5400Sstevel@tonic-gate state->soak_state = SOAK_PAUSE; 5410Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate htnow = gethrtime(); 5450Sstevel@tonic-gate ht += restdelta; 5460Sstevel@tonic-gate ts.tv_sec = (time_t)((ht - htnow) / 5470Sstevel@tonic-gate NSECS_PER_SEC); 5480Sstevel@tonic-gate ts.tv_nsec = (suseconds_t)((ht - htnow) % 5490Sstevel@tonic-gate NSECS_PER_SEC); 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate (void) nanosleep(&ts, NULL); 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * Start or stop the soaker if needed. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate if (opts->dosoaker) { 5580Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 5590Sstevel@tonic-gate if (cpc_setgrp_sysonly(sgrp) && 5600Sstevel@tonic-gate state->soak_state == SOAK_PAUSE) { 5610Sstevel@tonic-gate /* 5620Sstevel@tonic-gate * Soaker is paused but the next set is 5630Sstevel@tonic-gate * sysonly: start the soaker. 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate state->soak_state = SOAK_RUN; 5660Sstevel@tonic-gate (void) cond_signal(&state->soak_cv); 5670Sstevel@tonic-gate } else if (cpc_setgrp_sysonly(sgrp) == 0 && 5680Sstevel@tonic-gate state->soak_state == SOAK_RUN) 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * Soaker is running but the next set 5710Sstevel@tonic-gate * counts user events: stop the soaker. 5720Sstevel@tonic-gate */ 5730Sstevel@tonic-gate state->soak_state = SOAK_PAUSE; 5740Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate if (cpc_bind_cpu(cpc, state->cpuid, this, 0) != 0) 5780Sstevel@tonic-gate goto bad; 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate if (cpc_unbind(cpc, this) != 0) 5830Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: error unbinding on" 5840Sstevel@tonic-gate " cpu %d - %s\n"), opts->pgmname, 5850Sstevel@tonic-gate state->cpuid, strerror(errno)); 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate /* 5880Sstevel@tonic-gate * We're done, so stop the soaker if needed. 5890Sstevel@tonic-gate */ 5900Sstevel@tonic-gate if (opts->dosoaker) { 5910Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 5920Sstevel@tonic-gate if (state->soak_state == SOAK_RUN) 5930Sstevel@tonic-gate state->soak_state = SOAK_PAUSE; 5940Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate return (NULL); 5980Sstevel@tonic-gate bad: 5990Sstevel@tonic-gate state->status = 3; 6000Sstevel@tonic-gate errstr = strerror(errno); 6010Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cpu%d - %s\n"), 6020Sstevel@tonic-gate opts->pgmname, state->cpuid, errstr); 6030Sstevel@tonic-gate return (NULL); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate static int 6070Sstevel@tonic-gate cpustat(void) 6080Sstevel@tonic-gate { 6090Sstevel@tonic-gate cpc_setgrp_t *accum; 6100Sstevel@tonic-gate cpc_set_t *start; 6110Sstevel@tonic-gate int c, i, retval; 6120Sstevel@tonic-gate int lwps = 0; 6130Sstevel@tonic-gate psetid_t mypset, cpupset; 6140Sstevel@tonic-gate char *errstr; 6150Sstevel@tonic-gate cpc_buf_t **data1, **data2, **scratch; 6160Sstevel@tonic-gate int nreqs; 6170Sstevel@tonic-gate kstat_ctl_t *kc; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate ncpus = (int)sysconf(_SC_NPROCESSORS_CONF); 6200Sstevel@tonic-gate if ((gstate = calloc(ncpus, sizeof (*gstate))) == NULL) { 6210Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6220Sstevel@tonic-gate "%s: out of heap\n"), opts->pgmname); 6230Sstevel@tonic-gate return (1); 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate max_chip_id = sysconf(_SC_CPUID_MAX); 6270Sstevel@tonic-gate if ((chip_designees = malloc(max_chip_id * sizeof (int))) == NULL) { 6280Sstevel@tonic-gate (void) fprintf(stderr, gettext( 629*10265SKrishnendu.Sadhukhan@Sun.COM "%s: out of heap\n"), opts->pgmname); 6300Sstevel@tonic-gate return (1); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate for (i = 0; i < max_chip_id; i++) 6330Sstevel@tonic-gate chip_designees[i] = -1; 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate if (smt) { 6360Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) { 6370Sstevel@tonic-gate (void) fprintf(stderr, gettext( 638*10265SKrishnendu.Sadhukhan@Sun.COM "%s: kstat_open() failed: %s\n"), opts->pgmname, 6390Sstevel@tonic-gate strerror(errno)); 640*10265SKrishnendu.Sadhukhan@Sun.COM return (1); 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate if (opts->dosoaker) 6450Sstevel@tonic-gate if (priocntl(0, 0, PC_GETCID, &fxinfo) == -1) { 6460Sstevel@tonic-gate (void) fprintf(stderr, gettext( 647*10265SKrishnendu.Sadhukhan@Sun.COM "%s: couldn't get FX scheduler class: %s\n"), 6480Sstevel@tonic-gate opts->pgmname, strerror(errno)); 6490Sstevel@tonic-gate return (1); 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate /* 6530Sstevel@tonic-gate * Only include processors that are participating in the system 6540Sstevel@tonic-gate */ 6550Sstevel@tonic-gate for (c = 0, i = 0; i < ncpus; c++) { 6560Sstevel@tonic-gate switch (p_online(c, P_STATUS)) { 6570Sstevel@tonic-gate case P_ONLINE: 6580Sstevel@tonic-gate case P_NOINTR: 6590Sstevel@tonic-gate if (smt) { 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate gstate[i].chip_id = get_chipid(kc, c); 6620Sstevel@tonic-gate if (gstate[i].chip_id != -1 && 6630Sstevel@tonic-gate chip_designees[gstate[i].chip_id] == -1) 6640Sstevel@tonic-gate chip_designees[gstate[i].chip_id] = c; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate gstate[i++].cpuid = c; 6680Sstevel@tonic-gate break; 6690Sstevel@tonic-gate case P_OFFLINE: 6700Sstevel@tonic-gate case P_POWEROFF: 6710Sstevel@tonic-gate case P_FAULTED: 6720Sstevel@tonic-gate case P_SPARE: 6730Sstevel@tonic-gate gstate[i++].cpuid = -1; 6740Sstevel@tonic-gate break; 6750Sstevel@tonic-gate default: 6760Sstevel@tonic-gate gstate[i++].cpuid = -1; 6770Sstevel@tonic-gate (void) fprintf(stderr, 6780Sstevel@tonic-gate gettext("%s: cpu%d in unknown state\n"), 6790Sstevel@tonic-gate opts->pgmname, c); 6800Sstevel@tonic-gate break; 6810Sstevel@tonic-gate case -1: 6820Sstevel@tonic-gate break; 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate /* 6870Sstevel@tonic-gate * Examine the processor sets; if we're in one, only attempt 6880Sstevel@tonic-gate * to report on the set we're in. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate if (pset_bind(PS_QUERY, P_PID, P_MYID, &mypset) == -1) { 6910Sstevel@tonic-gate errstr = strerror(errno); 6920Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: pset_bind - %s\n"), 6930Sstevel@tonic-gate opts->pgmname, errstr); 6940Sstevel@tonic-gate } else { 6950Sstevel@tonic-gate for (i = 0; i < ncpus; i++) { 6960Sstevel@tonic-gate struct tstate *this = &gstate[i]; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate if (this->cpuid == -1) 6990Sstevel@tonic-gate continue; 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate if (pset_assign(PS_QUERY, 7020Sstevel@tonic-gate this->cpuid, &cpupset) == -1) { 7030Sstevel@tonic-gate errstr = strerror(errno); 7040Sstevel@tonic-gate (void) fprintf(stderr, 7050Sstevel@tonic-gate gettext("%s: pset_assign - %s\n"), 7060Sstevel@tonic-gate opts->pgmname, errstr); 7070Sstevel@tonic-gate continue; 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate if (mypset != cpupset) 7110Sstevel@tonic-gate this->cpuid = -1; 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate if (opts->dotitle) 7160Sstevel@tonic-gate print_title(opts->master); 7170Sstevel@tonic-gate zerotime(); 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate for (i = 0; i < ncpus; i++) { 7200Sstevel@tonic-gate struct tstate *this = &gstate[i]; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate if (this->cpuid == -1) 7230Sstevel@tonic-gate continue; 7240Sstevel@tonic-gate this->sgrp = cpc_setgrp_clone(opts->master); 7250Sstevel@tonic-gate if (this->sgrp == NULL) { 7260Sstevel@tonic-gate this->cpuid = -1; 7270Sstevel@tonic-gate continue; 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate if (thr_create(NULL, 0, gtick, this, 7300Sstevel@tonic-gate THR_BOUND|THR_NEW_LWP, &this->tid) == 0) 7310Sstevel@tonic-gate lwps++; 7320Sstevel@tonic-gate else { 7330Sstevel@tonic-gate (void) fprintf(stderr, 7340Sstevel@tonic-gate gettext("%s: cannot create thread for cpu%d\n"), 7350Sstevel@tonic-gate opts->pgmname, this->cpuid); 7360Sstevel@tonic-gate this->status = 4; 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate if (lwps != 0) 7410Sstevel@tonic-gate for (i = 0; i < ncpus; i++) 7420Sstevel@tonic-gate (void) thr_join(gstate[i].tid, NULL, NULL); 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate if ((accum = cpc_setgrp_clone(opts->master)) == NULL) { 7450Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: out of heap\n"), 7460Sstevel@tonic-gate opts->pgmname); 7470Sstevel@tonic-gate return (1); 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate retval = 0; 7510Sstevel@tonic-gate for (i = 0; i < ncpus; i++) { 7520Sstevel@tonic-gate struct tstate *this = &gstate[i]; 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate if (this->cpuid == -1) 7550Sstevel@tonic-gate continue; 7560Sstevel@tonic-gate cpc_setgrp_accum(accum, this->sgrp); 7570Sstevel@tonic-gate cpc_setgrp_free(this->sgrp); 7580Sstevel@tonic-gate this->sgrp = NULL; 7590Sstevel@tonic-gate if (this->status != 0) 7600Sstevel@tonic-gate retval = 1; 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate cpc_setgrp_reset(accum); 7640Sstevel@tonic-gate start = cpc_setgrp_getset(accum); 7650Sstevel@tonic-gate do { 7660Sstevel@tonic-gate nreqs = cpc_setgrp_getbufs(accum, &data1, &data2, &scratch); 7670Sstevel@tonic-gate print_total(lwps, *data1, nreqs, cpc_setgrp_getname(accum)); 7680Sstevel@tonic-gate } while (cpc_setgrp_nextset(accum) != start); 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate cpc_setgrp_free(accum); 7710Sstevel@tonic-gate accum = NULL; 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate free(gstate); 7740Sstevel@tonic-gate return (retval); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate static int 7780Sstevel@tonic-gate get_chipid(kstat_ctl_t *kc, processorid_t cpuid) 7790Sstevel@tonic-gate { 7800Sstevel@tonic-gate kstat_t *ksp; 7810Sstevel@tonic-gate kstat_named_t *k; 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate if ((ksp = kstat_lookup(kc, "cpu_info", cpuid, NULL)) == NULL) 7840Sstevel@tonic-gate return (-1); 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate if (kstat_read(kc, ksp, NULL) == -1) { 7870Sstevel@tonic-gate (void) fprintf(stderr, 7880Sstevel@tonic-gate gettext("%s: kstat_read() failed for cpu %d: %s\n"), 7890Sstevel@tonic-gate opts->pgmname, cpuid, strerror(errno)); 7900Sstevel@tonic-gate return (-1); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate if ((k = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id")) == NULL) { 7940Sstevel@tonic-gate (void) fprintf(stderr, 7950Sstevel@tonic-gate gettext("%s: chip_id not found for cpu %d: %s\n"), 7960Sstevel@tonic-gate opts->pgmname, cpuid, strerror(errno)); 7970Sstevel@tonic-gate return (-1); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate return (k->value.i32); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate static void * 8040Sstevel@tonic-gate soaker(void *arg) 8050Sstevel@tonic-gate { 8060Sstevel@tonic-gate struct tstate *state = arg; 8070Sstevel@tonic-gate pcparms_t pcparms; 8080Sstevel@tonic-gate fxparms_t *fx = (fxparms_t *)pcparms.pc_clparms; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate if (processor_bind(P_LWPID, P_MYID, state->cpuid, NULL) != 0) 8110Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: couldn't bind soaker " 8120Sstevel@tonic-gate "thread to cpu%d: %s\n"), opts->pgmname, state->cpuid, 8130Sstevel@tonic-gate strerror(errno)); 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate /* 8160Sstevel@tonic-gate * Put the soaker thread in the fixed priority (FX) class so it runs 8170Sstevel@tonic-gate * at the lowest possible global priority. 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate pcparms.pc_cid = fxinfo.pc_cid; 8200Sstevel@tonic-gate fx->fx_upri = 0; 8210Sstevel@tonic-gate fx->fx_uprilim = 0; 8220Sstevel@tonic-gate fx->fx_tqsecs = fx->fx_tqnsecs = FX_TQDEF; 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, &pcparms) != 0) 8250Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: couldn't put soaker " 8260Sstevel@tonic-gate "thread in FX sched class: %s\n"), opts->pgmname, 8270Sstevel@tonic-gate strerror(errno)); 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /* 8300Sstevel@tonic-gate * Let the parent thread know we're ready to roll. 8310Sstevel@tonic-gate */ 8320Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 8330Sstevel@tonic-gate state->soak_state = SOAK_RUN; 8340Sstevel@tonic-gate (void) cond_signal(&state->soak_cv); 8350Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate for (;;) { 8380Sstevel@tonic-gate spin: 8390Sstevel@tonic-gate (void) mutex_lock(&state->soak_lock); 8400Sstevel@tonic-gate if (state->soak_state == SOAK_RUN) { 8410Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 8420Sstevel@tonic-gate goto spin; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate while (state->soak_state == SOAK_PAUSE) 8460Sstevel@tonic-gate (void) cond_wait(&state->soak_cv, 8470Sstevel@tonic-gate &state->soak_lock); 8480Sstevel@tonic-gate (void) mutex_unlock(&state->soak_lock); 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate /*NOTREACHED*/ 8520Sstevel@tonic-gate return (NULL); 8530Sstevel@tonic-gate } 854