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 52791Srab * Common Development and Distribution License (the "License"). 62791Srab * 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*9460SKuriakose.Kuruvilla@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 <stdio.h> 270Sstevel@tonic-gate #include <stdlib.h> 280Sstevel@tonic-gate #include <alloca.h> 290Sstevel@tonic-gate #include <errno.h> 300Sstevel@tonic-gate #include <libintl.h> 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include "libcpc.h" 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 350Sstevel@tonic-gate * Takes a string and converts it to a cpc_set_t. 360Sstevel@tonic-gate * 370Sstevel@tonic-gate * While processing the string using getsubopt(), we will use an array of 380Sstevel@tonic-gate * requests to hold the data, and a proprietary representation of attributes 390Sstevel@tonic-gate * which allow us to avoid a realloc()/bcopy() dance every time we come across 400Sstevel@tonic-gate * a new attribute. 410Sstevel@tonic-gate * 420Sstevel@tonic-gate * Not until after the string has been processed in its entirety do we 430Sstevel@tonic-gate * allocate and specify a request set properly. 440Sstevel@tonic-gate */ 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * Leave enough room in token strings for picn, nousern, or sysn where n is 480Sstevel@tonic-gate * picnum. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate #define TOK_SIZE 10 510Sstevel@tonic-gate 520Sstevel@tonic-gate typedef struct __tmp_attr { 530Sstevel@tonic-gate char *name; 540Sstevel@tonic-gate uint64_t val; 550Sstevel@tonic-gate struct __tmp_attr *next; 560Sstevel@tonic-gate } tmp_attr_t; 570Sstevel@tonic-gate 580Sstevel@tonic-gate typedef struct __tok_info { 590Sstevel@tonic-gate char *name; 600Sstevel@tonic-gate int picnum; 610Sstevel@tonic-gate } tok_info_t; 620Sstevel@tonic-gate 630Sstevel@tonic-gate typedef struct __request_t { 640Sstevel@tonic-gate char cr_event[CPC_MAX_EVENT_LEN]; 650Sstevel@tonic-gate uint_t cr_flags; 660Sstevel@tonic-gate uint_t cr_nattrs; /* # CPU-specific attrs */ 670Sstevel@tonic-gate } request_t; 680Sstevel@tonic-gate 690Sstevel@tonic-gate static void strtoset_cleanup(void); 700Sstevel@tonic-gate static void smt_special(int picnum); 710Sstevel@tonic-gate static void *emalloc(size_t n); 720Sstevel@tonic-gate 730Sstevel@tonic-gate /* 740Sstevel@tonic-gate * Clients of cpc_strtoset may set this to specify an error handler during 750Sstevel@tonic-gate * string parsing. 760Sstevel@tonic-gate */ 770Sstevel@tonic-gate cpc_errhndlr_t *strtoset_errfn = NULL; 780Sstevel@tonic-gate 790Sstevel@tonic-gate static request_t *reqs; 800Sstevel@tonic-gate static int nreqs; 810Sstevel@tonic-gate static int ncounters; 820Sstevel@tonic-gate 830Sstevel@tonic-gate static tmp_attr_t **attrs; 840Sstevel@tonic-gate static int ntoks; 850Sstevel@tonic-gate static char **toks; 860Sstevel@tonic-gate static tok_info_t *tok_info; 870Sstevel@tonic-gate static int (*(*tok_funcs))(int, char *); 880Sstevel@tonic-gate static char **attrlist; /* array of ptrs to toks in attrlistp */ 890Sstevel@tonic-gate static int nattrs; 900Sstevel@tonic-gate static cpc_t *cpc; 910Sstevel@tonic-gate static int found; 920Sstevel@tonic-gate 930Sstevel@tonic-gate static void 940Sstevel@tonic-gate strtoset_err(const char *fmt, ...) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate va_list ap; 970Sstevel@tonic-gate 980Sstevel@tonic-gate if (strtoset_errfn == NULL) 990Sstevel@tonic-gate return; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate va_start(ap, fmt); 1020Sstevel@tonic-gate (*strtoset_errfn)("cpc_strtoset", -1, fmt, ap); 1030Sstevel@tonic-gate va_end(ap); 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /*ARGSUSED*/ 1070Sstevel@tonic-gate static void 1080Sstevel@tonic-gate event_walker(void *arg, uint_t picno, const char *event) 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate if (strncmp(arg, event, CPC_MAX_EVENT_LEN) == 0) 1110Sstevel@tonic-gate found = 1; 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate static int 1150Sstevel@tonic-gate event_valid(int picnum, char *event) 1160Sstevel@tonic-gate { 1177120Svk226950 char *end_event; 118*9460SKuriakose.Kuruvilla@Sun.COM int err; 119*9460SKuriakose.Kuruvilla@Sun.COM 1200Sstevel@tonic-gate found = 0; 1212791Srab 1220Sstevel@tonic-gate cpc_walk_events_pic(cpc, picnum, event, event_walker); 1232791Srab 1242791Srab if (found) 1252791Srab return (1); 1262791Srab 1277640SJonathan.Haslam@Sun.COM cpc_walk_generic_events_pic(cpc, picnum, event, event_walker); 1287640SJonathan.Haslam@Sun.COM 1297640SJonathan.Haslam@Sun.COM if (found) 1307640SJonathan.Haslam@Sun.COM return (1); 1317640SJonathan.Haslam@Sun.COM 1322791Srab /* 1332791Srab * Before assuming this is an invalid event, see if we have been given 134*9460SKuriakose.Kuruvilla@Sun.COM * a raw event code. 1357120Svk226950 * Check the second argument of strtol() to ensure invalid events 1367120Svk226950 * beginning with number do not go through. 1372791Srab */ 138*9460SKuriakose.Kuruvilla@Sun.COM err = errno; 139*9460SKuriakose.Kuruvilla@Sun.COM errno = 0; 140*9460SKuriakose.Kuruvilla@Sun.COM (void) strtol(event, &end_event, 0); 141*9460SKuriakose.Kuruvilla@Sun.COM if ((errno == 0) && (*end_event == '\0')) { 1422791Srab /* 1432791Srab * Success - this is a valid raw code in hex, decimal, or octal. 1442791Srab */ 145*9460SKuriakose.Kuruvilla@Sun.COM errno = err; 1462791Srab return (1); 147*9460SKuriakose.Kuruvilla@Sun.COM } 1482791Srab 149*9460SKuriakose.Kuruvilla@Sun.COM errno = err; 1502791Srab return (0); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate /* 1540Sstevel@tonic-gate * An unknown token was encountered; check here if it is an implicit event 1550Sstevel@tonic-gate * name. We allow users to omit the "picn=" portion of the event spec, and 1560Sstevel@tonic-gate * assign such events to available pics in order they are returned from 1570Sstevel@tonic-gate * getsubopt(3C). We start our search for an available pic _after_ the highest 1580Sstevel@tonic-gate * picnum to be assigned. This ensures that the event spec can never be out of 1590Sstevel@tonic-gate * order; i.e. if the event string is "eventa,eventb" we must ensure that the 1600Sstevel@tonic-gate * picnum counting eventa is less than the picnum counting eventb. 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate static int 1630Sstevel@tonic-gate find_event(char *event) 1640Sstevel@tonic-gate { 1650Sstevel@tonic-gate int i; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* 1682791Srab * Event names cannot have '=' in them. If present here, it means we 1692791Srab * have encountered an unknown token (foo=bar, for example). 1702791Srab */ 1712791Srab if (strchr(event, '=') != NULL) 1722791Srab return (0); 1732791Srab 1742791Srab /* 1750Sstevel@tonic-gate * Find the first unavailable pic, after which we must start our search. 1760Sstevel@tonic-gate */ 1770Sstevel@tonic-gate for (i = ncounters - 1; i >= 0; i--) { 1780Sstevel@tonic-gate if (reqs[i].cr_event[0] != '\0') 1790Sstevel@tonic-gate break; 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * If the last counter has been assigned, we cannot place this event. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate if (i == ncounters - 1) 1850Sstevel@tonic-gate return (0); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * If none of the counters have been assigned yet, i is -1 and we will 1890Sstevel@tonic-gate * begin our search at 0. Else we begin our search at the counter after 1900Sstevel@tonic-gate * the last one currently assigned. 1910Sstevel@tonic-gate */ 1920Sstevel@tonic-gate i++; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate for (; i < ncounters; i++) { 1950Sstevel@tonic-gate if (event_valid(i, event) == 0) 1960Sstevel@tonic-gate continue; 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate nreqs++; 1990Sstevel@tonic-gate (void) strncpy(reqs[i].cr_event, event, CPC_MAX_EVENT_LEN); 2000Sstevel@tonic-gate return (1); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate return (0); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate static int 2070Sstevel@tonic-gate pic(int tok, char *val) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Make sure the each pic only appears in the spec once. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate if (reqs[picnum].cr_event[0] != '\0') { 2140Sstevel@tonic-gate strtoset_err(gettext("repeated 'pic%d' token\n"), picnum); 2150Sstevel@tonic-gate return (-1); 2160Sstevel@tonic-gate } 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate if (val == NULL || val[0] == '\0') { 2190Sstevel@tonic-gate strtoset_err(gettext("missing 'pic%d' value\n"), picnum); 2200Sstevel@tonic-gate return (-1); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate if (event_valid(picnum, val) == 0) { 2240Sstevel@tonic-gate strtoset_err(gettext("pic%d cannot measure event '%s' on this " 2250Sstevel@tonic-gate "cpu\n"), picnum, val); 2260Sstevel@tonic-gate return (-1); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate nreqs++; 2300Sstevel@tonic-gate (void) strncpy(reqs[picnum].cr_event, val, CPC_MAX_EVENT_LEN); 2310Sstevel@tonic-gate return (0); 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* 2350Sstevel@tonic-gate * We explicitly ignore any value provided for these tokens, as their 2360Sstevel@tonic-gate * mere presence signals us to turn on or off the relevant flags. 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate /*ARGSUSED*/ 2390Sstevel@tonic-gate static int 2400Sstevel@tonic-gate flag(int tok, char *val) 2410Sstevel@tonic-gate { 2420Sstevel@tonic-gate int i; 2430Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate /* 2460Sstevel@tonic-gate * If picnum is -1, this flag should be applied to all reqs. 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate for (i = (picnum == -1) ? 0 : picnum; i < ncounters; i++) { 2490Sstevel@tonic-gate if (strcmp(tok_info[tok].name, "nouser") == 0) 2500Sstevel@tonic-gate reqs[i].cr_flags &= ~CPC_COUNT_USER; 2510Sstevel@tonic-gate else if (strcmp(tok_info[tok].name, "sys") == 0) 2520Sstevel@tonic-gate reqs[i].cr_flags |= CPC_COUNT_SYSTEM; 2530Sstevel@tonic-gate else 2540Sstevel@tonic-gate return (-1); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate if (picnum != -1) 2570Sstevel@tonic-gate break; 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate return (0); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate static int 2640Sstevel@tonic-gate doattr(int tok, char *val) 2650Sstevel@tonic-gate { 2660Sstevel@tonic-gate int i; 2670Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 2680Sstevel@tonic-gate tmp_attr_t *tmp; 2690Sstevel@tonic-gate char *endptr; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * If picnum is -1, this attribute should be applied to all reqs. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate for (i = (picnum == -1) ? 0 : picnum; i < ncounters; i++) { 2750Sstevel@tonic-gate tmp = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 2760Sstevel@tonic-gate tmp->name = tok_info[tok].name; 2770Sstevel@tonic-gate if (val != NULL) { 2780Sstevel@tonic-gate tmp->val = strtoll(val, &endptr, 0); 2790Sstevel@tonic-gate if (endptr == val) { 2800Sstevel@tonic-gate strtoset_err(gettext("invalid value '%s' for " 2810Sstevel@tonic-gate "attribute '%s'\n"), val, tmp->name); 2820Sstevel@tonic-gate free(tmp); 2830Sstevel@tonic-gate return (-1); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate } else 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * No value was provided for this attribute, 2880Sstevel@tonic-gate * so specify a default value of 1. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate tmp->val = 1; 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate tmp->next = attrs[i]; 2930Sstevel@tonic-gate attrs[i] = tmp; 2940Sstevel@tonic-gate reqs[i].cr_nattrs++; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate if (picnum != -1) 2970Sstevel@tonic-gate break; 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate return (0); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /*ARGSUSED*/ 3040Sstevel@tonic-gate static void 3050Sstevel@tonic-gate attr_count_walker(void *arg, const char *attr) 3060Sstevel@tonic-gate { 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * We don't allow picnum to be specified by the user. 3090Sstevel@tonic-gate */ 3100Sstevel@tonic-gate if (strncmp(attr, "picnum", 7) == 0) 3110Sstevel@tonic-gate return; 3120Sstevel@tonic-gate (*(int *)arg)++; 3130Sstevel@tonic-gate } 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate static int 3160Sstevel@tonic-gate cpc_count_attrs(cpc_t *cpc) 3170Sstevel@tonic-gate { 3180Sstevel@tonic-gate int nattrs = 0; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate cpc_walk_attrs(cpc, &nattrs, attr_count_walker); 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate return (nattrs); 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate static void 3260Sstevel@tonic-gate attr_walker(void *arg, const char *attr) 3270Sstevel@tonic-gate { 3280Sstevel@tonic-gate int *i = arg; 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (strncmp(attr, "picnum", 7) == 0) 3310Sstevel@tonic-gate return; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if ((attrlist[(*i)++] = strdup(attr)) == NULL) { 3340Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 3350Sstevel@tonic-gate exit(0); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate cpc_set_t * 3400Sstevel@tonic-gate cpc_strtoset(cpc_t *cpcin, const char *spec, int smt) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate cpc_set_t *set; 3430Sstevel@tonic-gate cpc_attr_t *req_attrs; 3440Sstevel@tonic-gate tmp_attr_t *tmp; 3450Sstevel@tonic-gate size_t toklen; 3460Sstevel@tonic-gate int i; 3470Sstevel@tonic-gate int j; 3480Sstevel@tonic-gate int x; 3490Sstevel@tonic-gate char *opts; 3500Sstevel@tonic-gate char *val; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate cpc = cpcin; 3530Sstevel@tonic-gate nattrs = 0; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate ncounters = cpc_npic(cpc); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate reqs = (request_t *)emalloc(ncounters * sizeof (request_t)); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate attrs = (tmp_attr_t **)emalloc(ncounters * sizeof (tmp_attr_t *)); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 3620Sstevel@tonic-gate reqs[i].cr_event[0] = '\0'; 3630Sstevel@tonic-gate reqs[i].cr_flags = CPC_COUNT_USER; 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Each pic will have at least one attribute: the physical pic 3660Sstevel@tonic-gate * assignment via the "picnum" attribute. Set that up here for 3670Sstevel@tonic-gate * each request. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate reqs[i].cr_nattrs = 1; 3700Sstevel@tonic-gate attrs[i] = emalloc(sizeof (tmp_attr_t)); 3710Sstevel@tonic-gate attrs[i]->name = "picnum"; 3720Sstevel@tonic-gate attrs[i]->val = i; 3730Sstevel@tonic-gate attrs[i]->next = NULL; 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate /* 3770Sstevel@tonic-gate * Build up a list of acceptable tokens. 3780Sstevel@tonic-gate * 3790Sstevel@tonic-gate * Permitted tokens are 3800Sstevel@tonic-gate * picn=event 3810Sstevel@tonic-gate * nousern 3820Sstevel@tonic-gate * sysn 3830Sstevel@tonic-gate * attrn=val 3840Sstevel@tonic-gate * nouser 3850Sstevel@tonic-gate * sys 3860Sstevel@tonic-gate * attr=val 3870Sstevel@tonic-gate * 3880Sstevel@tonic-gate * Where n is a counter number, and attr is any attribute supported by 3890Sstevel@tonic-gate * the current processor. 3900Sstevel@tonic-gate * 3910Sstevel@tonic-gate * If a token appears without a counter number, it applies to all 3920Sstevel@tonic-gate * counters in the request set. 3930Sstevel@tonic-gate * 3940Sstevel@tonic-gate * The number of tokens is: 3950Sstevel@tonic-gate * 3960Sstevel@tonic-gate * picn: ncounters 3970Sstevel@tonic-gate * generic flags: 2 * ncounters (nouser, sys) 3980Sstevel@tonic-gate * attrs: nattrs * ncounters 3990Sstevel@tonic-gate * attrs with no picnum: nattrs 4000Sstevel@tonic-gate * generic flags with no picnum: 2 (nouser, sys) 4010Sstevel@tonic-gate * NULL token to signify end of list to getsubopt(3C). 4020Sstevel@tonic-gate * 4030Sstevel@tonic-gate * Matching each token's index in the token table is a function which 4040Sstevel@tonic-gate * process that token; these are in tok_funcs. 4050Sstevel@tonic-gate */ 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* 4080Sstevel@tonic-gate * Count the number of valid attributes. 4090Sstevel@tonic-gate * Set up the attrlist array to point to the attributes in attrlistp. 4100Sstevel@tonic-gate */ 4110Sstevel@tonic-gate nattrs = cpc_count_attrs(cpc); 4120Sstevel@tonic-gate attrlist = (char **)emalloc(nattrs * sizeof (char *)); 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate i = 0; 4150Sstevel@tonic-gate cpc_walk_attrs(cpc, &i, attr_walker); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate ntoks = ncounters + (2 * ncounters) + (nattrs * ncounters) + nattrs + 3; 4180Sstevel@tonic-gate toks = (char **)emalloc(ntoks * sizeof (char *)); 4190Sstevel@tonic-gate tok_info = (tok_info_t *)emalloc(ntoks * sizeof (tok_info_t)); 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate tok_funcs = (int (**)(int, char *))emalloc(ntoks * 4220Sstevel@tonic-gate sizeof (int (*)(char *))); 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate for (i = 0; i < ntoks; i++) { 4250Sstevel@tonic-gate toks[i] = NULL; 4260Sstevel@tonic-gate tok_funcs[i] = NULL; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate x = 0; 4300Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4310Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 4320Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "pic%d", i); 4330Sstevel@tonic-gate tok_info[x].name = "pic"; 4340Sstevel@tonic-gate tok_info[i].picnum = i; 4350Sstevel@tonic-gate tok_funcs[x] = pic; 4360Sstevel@tonic-gate x++; 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4400Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 4410Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "nouser%d", i); 4420Sstevel@tonic-gate tok_info[x].name = "nouser"; 4430Sstevel@tonic-gate tok_info[x].picnum = i; 4440Sstevel@tonic-gate tok_funcs[x] = flag; 4450Sstevel@tonic-gate x++; 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4490Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 4500Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "sys%d", i); 4510Sstevel@tonic-gate tok_info[x].name = "sys"; 4520Sstevel@tonic-gate tok_info[x].picnum = i; 4530Sstevel@tonic-gate tok_funcs[x] = flag; 4540Sstevel@tonic-gate x++; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate for (j = 0; j < nattrs; j++) { 4570Sstevel@tonic-gate toklen = strlen(attrlist[j]) + 3; 4580Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4590Sstevel@tonic-gate toks[x] = (char *)emalloc(toklen); 4600Sstevel@tonic-gate (void) snprintf(toks[x], toklen, "%s%d", attrlist[j], 4610Sstevel@tonic-gate i); 4620Sstevel@tonic-gate tok_info[x].name = attrlist[j]; 4630Sstevel@tonic-gate tok_info[x].picnum = i; 4640Sstevel@tonic-gate tok_funcs[x] = doattr; 4650Sstevel@tonic-gate x++; 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * Now create a token for this attribute with no picnum; if used 4700Sstevel@tonic-gate * it will be applied to all reqs. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate toks[x] = (char *)emalloc(toklen); 4730Sstevel@tonic-gate (void) snprintf(toks[x], toklen, "%s", attrlist[j]); 4740Sstevel@tonic-gate tok_info[x].name = attrlist[j]; 4750Sstevel@tonic-gate tok_info[x].picnum = -1; 4760Sstevel@tonic-gate tok_funcs[x] = doattr; 4770Sstevel@tonic-gate x++; 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate toks[x] = "nouser"; 4810Sstevel@tonic-gate tok_info[x].name = "nouser"; 4820Sstevel@tonic-gate tok_info[x].picnum = -1; 4830Sstevel@tonic-gate tok_funcs[x] = flag; 4840Sstevel@tonic-gate x++; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate toks[x] = "sys"; 4870Sstevel@tonic-gate tok_info[x].name = "sys"; 4880Sstevel@tonic-gate tok_info[x].picnum = -1; 4890Sstevel@tonic-gate tok_funcs[x] = flag; 4900Sstevel@tonic-gate x++; 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate toks[x] = NULL; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate opts = strcpy(alloca(strlen(spec) + 1), spec); 4950Sstevel@tonic-gate while (*opts != '\0') { 4960Sstevel@tonic-gate int idx = getsubopt(&opts, toks, &val); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate if (idx == -1) { 4990Sstevel@tonic-gate if (find_event(val) == 0) { 5000Sstevel@tonic-gate strtoset_err(gettext("bad token '%s'\n"), val); 5010Sstevel@tonic-gate goto inval; 5020Sstevel@tonic-gate } else 5030Sstevel@tonic-gate continue; 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (tok_funcs[idx](idx, val) == -1) 5070Sstevel@tonic-gate goto inval; 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * The string has been processed. Now count how many PICs were used, 5120Sstevel@tonic-gate * create a request set, and specify each request properly. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate if ((set = cpc_set_create(cpc)) == NULL) { 5160Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 5170Sstevel@tonic-gate exit(0); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 5210Sstevel@tonic-gate if (reqs[i].cr_event[0] == '\0') 5220Sstevel@tonic-gate continue; 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * If the caller wishes to measure events on the physical CPU, 5260Sstevel@tonic-gate * we need to add SMT attributes to each request. 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate if (smt) 5290Sstevel@tonic-gate smt_special(i); 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate req_attrs = (cpc_attr_t *)emalloc(reqs[i].cr_nattrs * 5320Sstevel@tonic-gate sizeof (cpc_attr_t)); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate j = 0; 5350Sstevel@tonic-gate for (tmp = attrs[i]; tmp != NULL; tmp = tmp->next) { 5360Sstevel@tonic-gate req_attrs[j].ca_name = tmp->name; 5370Sstevel@tonic-gate req_attrs[j].ca_val = tmp->val; 5380Sstevel@tonic-gate j++; 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, reqs[i].cr_event, 0, 5420Sstevel@tonic-gate reqs[i].cr_flags, reqs[i].cr_nattrs, req_attrs) == -1) { 5430Sstevel@tonic-gate free(req_attrs); 5440Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 5450Sstevel@tonic-gate strtoset_err( 5467120Svk226950 gettext("cpc_set_add_request() failed: %s\n"), 5477120Svk226950 strerror(errno)); 5480Sstevel@tonic-gate goto inval; 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate free(req_attrs); 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate strtoset_cleanup(); 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate return (set); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate inval: 5590Sstevel@tonic-gate strtoset_cleanup(); 5600Sstevel@tonic-gate errno = EINVAL; 5610Sstevel@tonic-gate return (NULL); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate static void 5650Sstevel@tonic-gate strtoset_cleanup(void) 5660Sstevel@tonic-gate { 5670Sstevel@tonic-gate int i; 5680Sstevel@tonic-gate tmp_attr_t *tmp, *p; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate for (i = 0; i < nattrs; i++) 5710Sstevel@tonic-gate free(attrlist[i]); 5720Sstevel@tonic-gate free(attrlist); 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 5750Sstevel@tonic-gate for (tmp = attrs[i]; tmp != NULL; tmp = p) { 5760Sstevel@tonic-gate p = tmp->next; 5770Sstevel@tonic-gate free(tmp); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate free(attrs); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate for (i = 0; i < ntoks - 3; i++) 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * We free all but the last three tokens: "nouser", "sys", NULL 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate free(toks[i]); 5870Sstevel@tonic-gate free(toks); 5880Sstevel@tonic-gate free(reqs); 5890Sstevel@tonic-gate free(tok_info); 5900Sstevel@tonic-gate free(tok_funcs); 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate /* 5940Sstevel@tonic-gate * The following is called to modify requests so that they count events on 5950Sstevel@tonic-gate * behalf of a physical processor, instead of a logical processor. It duplicates 5960Sstevel@tonic-gate * the request flags for the sibling processor (i.e. if the request counts user 5970Sstevel@tonic-gate * events, add an attribute to count user events on the sibling processor also). 5980Sstevel@tonic-gate */ 5990Sstevel@tonic-gate static void 6000Sstevel@tonic-gate smt_special(int picnum) 6010Sstevel@tonic-gate { 6020Sstevel@tonic-gate tmp_attr_t *attr; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate if (reqs[picnum].cr_flags & CPC_COUNT_USER) { 6050Sstevel@tonic-gate attr = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 6060Sstevel@tonic-gate attr->name = "count_sibling_usr"; 6070Sstevel@tonic-gate attr->val = 1; 6080Sstevel@tonic-gate attr->next = attrs[picnum]; 6090Sstevel@tonic-gate attrs[picnum] = attr; 6100Sstevel@tonic-gate reqs[picnum].cr_nattrs++; 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate if (reqs[picnum].cr_flags & CPC_COUNT_SYSTEM) { 6140Sstevel@tonic-gate attr = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 6150Sstevel@tonic-gate attr->name = "count_sibling_sys"; 6160Sstevel@tonic-gate attr->val = 1; 6170Sstevel@tonic-gate attr->next = attrs[picnum]; 6180Sstevel@tonic-gate attrs[picnum] = attr; 6190Sstevel@tonic-gate reqs[picnum].cr_nattrs++; 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * If we ever fail to get memory, we print an error message and exit. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate static void * 6270Sstevel@tonic-gate emalloc(size_t n) 6280Sstevel@tonic-gate { 6290Sstevel@tonic-gate void *p = malloc(n); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (p == NULL) { 6320Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 6330Sstevel@tonic-gate exit(0); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate return (p); 6370Sstevel@tonic-gate } 638