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 2004 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 <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 31*7c478bd9Sstevel@tonic-gate #include <alloca.h> 32*7c478bd9Sstevel@tonic-gate #include <errno.h> 33*7c478bd9Sstevel@tonic-gate #include <libintl.h> 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include "libcpc.h" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate /* 38*7c478bd9Sstevel@tonic-gate * Takes a string and converts it to a cpc_set_t. 39*7c478bd9Sstevel@tonic-gate * 40*7c478bd9Sstevel@tonic-gate * While processing the string using getsubopt(), we will use an array of 41*7c478bd9Sstevel@tonic-gate * requests to hold the data, and a proprietary representation of attributes 42*7c478bd9Sstevel@tonic-gate * which allow us to avoid a realloc()/bcopy() dance every time we come across 43*7c478bd9Sstevel@tonic-gate * a new attribute. 44*7c478bd9Sstevel@tonic-gate * 45*7c478bd9Sstevel@tonic-gate * Not until after the string has been processed in its entirety do we 46*7c478bd9Sstevel@tonic-gate * allocate and specify a request set properly. 47*7c478bd9Sstevel@tonic-gate */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * Leave enough room in token strings for picn, nousern, or sysn where n is 51*7c478bd9Sstevel@tonic-gate * picnum. 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate #define TOK_SIZE 10 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate typedef struct __tmp_attr { 56*7c478bd9Sstevel@tonic-gate char *name; 57*7c478bd9Sstevel@tonic-gate uint64_t val; 58*7c478bd9Sstevel@tonic-gate struct __tmp_attr *next; 59*7c478bd9Sstevel@tonic-gate } tmp_attr_t; 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate typedef struct __tok_info { 62*7c478bd9Sstevel@tonic-gate char *name; 63*7c478bd9Sstevel@tonic-gate int picnum; 64*7c478bd9Sstevel@tonic-gate } tok_info_t; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate typedef struct __request_t { 67*7c478bd9Sstevel@tonic-gate char cr_event[CPC_MAX_EVENT_LEN]; 68*7c478bd9Sstevel@tonic-gate uint_t cr_flags; 69*7c478bd9Sstevel@tonic-gate uint_t cr_nattrs; /* # CPU-specific attrs */ 70*7c478bd9Sstevel@tonic-gate } request_t; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate static void strtoset_cleanup(void); 73*7c478bd9Sstevel@tonic-gate static void smt_special(int picnum); 74*7c478bd9Sstevel@tonic-gate static void *emalloc(size_t n); 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate /* 77*7c478bd9Sstevel@tonic-gate * Clients of cpc_strtoset may set this to specify an error handler during 78*7c478bd9Sstevel@tonic-gate * string parsing. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate cpc_errhndlr_t *strtoset_errfn = NULL; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate static request_t *reqs; 83*7c478bd9Sstevel@tonic-gate static int nreqs; 84*7c478bd9Sstevel@tonic-gate static int ncounters; 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate static tmp_attr_t **attrs; 87*7c478bd9Sstevel@tonic-gate static int ntoks; 88*7c478bd9Sstevel@tonic-gate static char **toks; 89*7c478bd9Sstevel@tonic-gate static tok_info_t *tok_info; 90*7c478bd9Sstevel@tonic-gate static int (*(*tok_funcs))(int, char *); 91*7c478bd9Sstevel@tonic-gate static char **attrlist; /* array of ptrs to toks in attrlistp */ 92*7c478bd9Sstevel@tonic-gate static int nattrs; 93*7c478bd9Sstevel@tonic-gate static cpc_t *cpc; 94*7c478bd9Sstevel@tonic-gate static int found; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate static void 97*7c478bd9Sstevel@tonic-gate strtoset_err(const char *fmt, ...) 98*7c478bd9Sstevel@tonic-gate { 99*7c478bd9Sstevel@tonic-gate va_list ap; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate if (strtoset_errfn == NULL) 102*7c478bd9Sstevel@tonic-gate return; 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 105*7c478bd9Sstevel@tonic-gate (*strtoset_errfn)("cpc_strtoset", -1, fmt, ap); 106*7c478bd9Sstevel@tonic-gate va_end(ap); 107*7c478bd9Sstevel@tonic-gate } 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 110*7c478bd9Sstevel@tonic-gate static void 111*7c478bd9Sstevel@tonic-gate event_walker(void *arg, uint_t picno, const char *event) 112*7c478bd9Sstevel@tonic-gate { 113*7c478bd9Sstevel@tonic-gate if (strncmp(arg, event, CPC_MAX_EVENT_LEN) == 0) 114*7c478bd9Sstevel@tonic-gate found = 1; 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate static int 118*7c478bd9Sstevel@tonic-gate event_valid(int picnum, char *event) 119*7c478bd9Sstevel@tonic-gate { 120*7c478bd9Sstevel@tonic-gate found = 0; 121*7c478bd9Sstevel@tonic-gate cpc_walk_events_pic(cpc, picnum, event, event_walker); 122*7c478bd9Sstevel@tonic-gate return (found); 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate * An unknown token was encountered; check here if it is an implicit event 127*7c478bd9Sstevel@tonic-gate * name. We allow users to omit the "picn=" portion of the event spec, and 128*7c478bd9Sstevel@tonic-gate * assign such events to available pics in order they are returned from 129*7c478bd9Sstevel@tonic-gate * getsubopt(3C). We start our search for an available pic _after_ the highest 130*7c478bd9Sstevel@tonic-gate * picnum to be assigned. This ensures that the event spec can never be out of 131*7c478bd9Sstevel@tonic-gate * order; i.e. if the event string is "eventa,eventb" we must ensure that the 132*7c478bd9Sstevel@tonic-gate * picnum counting eventa is less than the picnum counting eventb. 133*7c478bd9Sstevel@tonic-gate */ 134*7c478bd9Sstevel@tonic-gate static int 135*7c478bd9Sstevel@tonic-gate find_event(char *event) 136*7c478bd9Sstevel@tonic-gate { 137*7c478bd9Sstevel@tonic-gate int i; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* 140*7c478bd9Sstevel@tonic-gate * Find the first unavailable pic, after which we must start our search. 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate for (i = ncounters - 1; i >= 0; i--) { 143*7c478bd9Sstevel@tonic-gate if (reqs[i].cr_event[0] != '\0') 144*7c478bd9Sstevel@tonic-gate break; 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate /* 147*7c478bd9Sstevel@tonic-gate * If the last counter has been assigned, we cannot place this event. 148*7c478bd9Sstevel@tonic-gate */ 149*7c478bd9Sstevel@tonic-gate if (i == ncounters - 1) 150*7c478bd9Sstevel@tonic-gate return (0); 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* 153*7c478bd9Sstevel@tonic-gate * If none of the counters have been assigned yet, i is -1 and we will 154*7c478bd9Sstevel@tonic-gate * begin our search at 0. Else we begin our search at the counter after 155*7c478bd9Sstevel@tonic-gate * the last one currently assigned. 156*7c478bd9Sstevel@tonic-gate */ 157*7c478bd9Sstevel@tonic-gate i++; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate for (; i < ncounters; i++) { 160*7c478bd9Sstevel@tonic-gate if (event_valid(i, event) == 0) 161*7c478bd9Sstevel@tonic-gate continue; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate nreqs++; 164*7c478bd9Sstevel@tonic-gate (void) strncpy(reqs[i].cr_event, event, CPC_MAX_EVENT_LEN); 165*7c478bd9Sstevel@tonic-gate return (1); 166*7c478bd9Sstevel@tonic-gate } 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate return (0); 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate static int 172*7c478bd9Sstevel@tonic-gate pic(int tok, char *val) 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 175*7c478bd9Sstevel@tonic-gate /* 176*7c478bd9Sstevel@tonic-gate * Make sure the each pic only appears in the spec once. 177*7c478bd9Sstevel@tonic-gate */ 178*7c478bd9Sstevel@tonic-gate if (reqs[picnum].cr_event[0] != '\0') { 179*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("repeated 'pic%d' token\n"), picnum); 180*7c478bd9Sstevel@tonic-gate return (-1); 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate if (val == NULL || val[0] == '\0') { 184*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("missing 'pic%d' value\n"), picnum); 185*7c478bd9Sstevel@tonic-gate return (-1); 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate if (event_valid(picnum, val) == 0) { 189*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("pic%d cannot measure event '%s' on this " 190*7c478bd9Sstevel@tonic-gate "cpu\n"), picnum, val); 191*7c478bd9Sstevel@tonic-gate return (-1); 192*7c478bd9Sstevel@tonic-gate } 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate nreqs++; 195*7c478bd9Sstevel@tonic-gate (void) strncpy(reqs[picnum].cr_event, val, CPC_MAX_EVENT_LEN); 196*7c478bd9Sstevel@tonic-gate return (0); 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate /* 200*7c478bd9Sstevel@tonic-gate * We explicitly ignore any value provided for these tokens, as their 201*7c478bd9Sstevel@tonic-gate * mere presence signals us to turn on or off the relevant flags. 202*7c478bd9Sstevel@tonic-gate */ 203*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 204*7c478bd9Sstevel@tonic-gate static int 205*7c478bd9Sstevel@tonic-gate flag(int tok, char *val) 206*7c478bd9Sstevel@tonic-gate { 207*7c478bd9Sstevel@tonic-gate int i; 208*7c478bd9Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* 211*7c478bd9Sstevel@tonic-gate * If picnum is -1, this flag should be applied to all reqs. 212*7c478bd9Sstevel@tonic-gate */ 213*7c478bd9Sstevel@tonic-gate for (i = (picnum == -1) ? 0 : picnum; i < ncounters; i++) { 214*7c478bd9Sstevel@tonic-gate if (strcmp(tok_info[tok].name, "nouser") == 0) 215*7c478bd9Sstevel@tonic-gate reqs[i].cr_flags &= ~CPC_COUNT_USER; 216*7c478bd9Sstevel@tonic-gate else if (strcmp(tok_info[tok].name, "sys") == 0) 217*7c478bd9Sstevel@tonic-gate reqs[i].cr_flags |= CPC_COUNT_SYSTEM; 218*7c478bd9Sstevel@tonic-gate else 219*7c478bd9Sstevel@tonic-gate return (-1); 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate if (picnum != -1) 222*7c478bd9Sstevel@tonic-gate break; 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate return (0); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate static int 229*7c478bd9Sstevel@tonic-gate doattr(int tok, char *val) 230*7c478bd9Sstevel@tonic-gate { 231*7c478bd9Sstevel@tonic-gate int i; 232*7c478bd9Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 233*7c478bd9Sstevel@tonic-gate tmp_attr_t *tmp; 234*7c478bd9Sstevel@tonic-gate char *endptr; 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * If picnum is -1, this attribute should be applied to all reqs. 238*7c478bd9Sstevel@tonic-gate */ 239*7c478bd9Sstevel@tonic-gate for (i = (picnum == -1) ? 0 : picnum; i < ncounters; i++) { 240*7c478bd9Sstevel@tonic-gate tmp = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 241*7c478bd9Sstevel@tonic-gate tmp->name = tok_info[tok].name; 242*7c478bd9Sstevel@tonic-gate if (val != NULL) { 243*7c478bd9Sstevel@tonic-gate tmp->val = strtoll(val, &endptr, 0); 244*7c478bd9Sstevel@tonic-gate if (endptr == val) { 245*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("invalid value '%s' for " 246*7c478bd9Sstevel@tonic-gate "attribute '%s'\n"), val, tmp->name); 247*7c478bd9Sstevel@tonic-gate free(tmp); 248*7c478bd9Sstevel@tonic-gate return (-1); 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate } else 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * No value was provided for this attribute, 253*7c478bd9Sstevel@tonic-gate * so specify a default value of 1. 254*7c478bd9Sstevel@tonic-gate */ 255*7c478bd9Sstevel@tonic-gate tmp->val = 1; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate tmp->next = attrs[i]; 258*7c478bd9Sstevel@tonic-gate attrs[i] = tmp; 259*7c478bd9Sstevel@tonic-gate reqs[i].cr_nattrs++; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate if (picnum != -1) 262*7c478bd9Sstevel@tonic-gate break; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate return (0); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 269*7c478bd9Sstevel@tonic-gate static void 270*7c478bd9Sstevel@tonic-gate attr_count_walker(void *arg, const char *attr) 271*7c478bd9Sstevel@tonic-gate { 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * We don't allow picnum to be specified by the user. 274*7c478bd9Sstevel@tonic-gate */ 275*7c478bd9Sstevel@tonic-gate if (strncmp(attr, "picnum", 7) == 0) 276*7c478bd9Sstevel@tonic-gate return; 277*7c478bd9Sstevel@tonic-gate (*(int *)arg)++; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate static int 281*7c478bd9Sstevel@tonic-gate cpc_count_attrs(cpc_t *cpc) 282*7c478bd9Sstevel@tonic-gate { 283*7c478bd9Sstevel@tonic-gate int nattrs = 0; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc, &nattrs, attr_count_walker); 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate return (nattrs); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate static void 291*7c478bd9Sstevel@tonic-gate attr_walker(void *arg, const char *attr) 292*7c478bd9Sstevel@tonic-gate { 293*7c478bd9Sstevel@tonic-gate int *i = arg; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate if (strncmp(attr, "picnum", 7) == 0) 296*7c478bd9Sstevel@tonic-gate return; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate if ((attrlist[(*i)++] = strdup(attr)) == NULL) { 299*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 300*7c478bd9Sstevel@tonic-gate exit(0); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate cpc_set_t * 305*7c478bd9Sstevel@tonic-gate cpc_strtoset(cpc_t *cpcin, const char *spec, int smt) 306*7c478bd9Sstevel@tonic-gate { 307*7c478bd9Sstevel@tonic-gate cpc_set_t *set; 308*7c478bd9Sstevel@tonic-gate cpc_attr_t *req_attrs; 309*7c478bd9Sstevel@tonic-gate tmp_attr_t *tmp; 310*7c478bd9Sstevel@tonic-gate size_t toklen; 311*7c478bd9Sstevel@tonic-gate int i; 312*7c478bd9Sstevel@tonic-gate int j; 313*7c478bd9Sstevel@tonic-gate int x; 314*7c478bd9Sstevel@tonic-gate char *opts; 315*7c478bd9Sstevel@tonic-gate char *val; 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate cpc = cpcin; 318*7c478bd9Sstevel@tonic-gate nattrs = 0; 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate ncounters = cpc_npic(cpc); 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate reqs = (request_t *)emalloc(ncounters * sizeof (request_t)); 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate attrs = (tmp_attr_t **)emalloc(ncounters * sizeof (tmp_attr_t *)); 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 327*7c478bd9Sstevel@tonic-gate reqs[i].cr_event[0] = '\0'; 328*7c478bd9Sstevel@tonic-gate reqs[i].cr_flags = CPC_COUNT_USER; 329*7c478bd9Sstevel@tonic-gate /* 330*7c478bd9Sstevel@tonic-gate * Each pic will have at least one attribute: the physical pic 331*7c478bd9Sstevel@tonic-gate * assignment via the "picnum" attribute. Set that up here for 332*7c478bd9Sstevel@tonic-gate * each request. 333*7c478bd9Sstevel@tonic-gate */ 334*7c478bd9Sstevel@tonic-gate reqs[i].cr_nattrs = 1; 335*7c478bd9Sstevel@tonic-gate attrs[i] = emalloc(sizeof (tmp_attr_t)); 336*7c478bd9Sstevel@tonic-gate attrs[i]->name = "picnum"; 337*7c478bd9Sstevel@tonic-gate attrs[i]->val = i; 338*7c478bd9Sstevel@tonic-gate attrs[i]->next = NULL; 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * Build up a list of acceptable tokens. 343*7c478bd9Sstevel@tonic-gate * 344*7c478bd9Sstevel@tonic-gate * Permitted tokens are 345*7c478bd9Sstevel@tonic-gate * picn=event 346*7c478bd9Sstevel@tonic-gate * nousern 347*7c478bd9Sstevel@tonic-gate * sysn 348*7c478bd9Sstevel@tonic-gate * attrn=val 349*7c478bd9Sstevel@tonic-gate * nouser 350*7c478bd9Sstevel@tonic-gate * sys 351*7c478bd9Sstevel@tonic-gate * attr=val 352*7c478bd9Sstevel@tonic-gate * 353*7c478bd9Sstevel@tonic-gate * Where n is a counter number, and attr is any attribute supported by 354*7c478bd9Sstevel@tonic-gate * the current processor. 355*7c478bd9Sstevel@tonic-gate * 356*7c478bd9Sstevel@tonic-gate * If a token appears without a counter number, it applies to all 357*7c478bd9Sstevel@tonic-gate * counters in the request set. 358*7c478bd9Sstevel@tonic-gate * 359*7c478bd9Sstevel@tonic-gate * The number of tokens is: 360*7c478bd9Sstevel@tonic-gate * 361*7c478bd9Sstevel@tonic-gate * picn: ncounters 362*7c478bd9Sstevel@tonic-gate * generic flags: 2 * ncounters (nouser, sys) 363*7c478bd9Sstevel@tonic-gate * attrs: nattrs * ncounters 364*7c478bd9Sstevel@tonic-gate * attrs with no picnum: nattrs 365*7c478bd9Sstevel@tonic-gate * generic flags with no picnum: 2 (nouser, sys) 366*7c478bd9Sstevel@tonic-gate * NULL token to signify end of list to getsubopt(3C). 367*7c478bd9Sstevel@tonic-gate * 368*7c478bd9Sstevel@tonic-gate * Matching each token's index in the token table is a function which 369*7c478bd9Sstevel@tonic-gate * process that token; these are in tok_funcs. 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate /* 373*7c478bd9Sstevel@tonic-gate * Count the number of valid attributes. 374*7c478bd9Sstevel@tonic-gate * Set up the attrlist array to point to the attributes in attrlistp. 375*7c478bd9Sstevel@tonic-gate */ 376*7c478bd9Sstevel@tonic-gate nattrs = cpc_count_attrs(cpc); 377*7c478bd9Sstevel@tonic-gate attrlist = (char **)emalloc(nattrs * sizeof (char *)); 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate i = 0; 380*7c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc, &i, attr_walker); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate ntoks = ncounters + (2 * ncounters) + (nattrs * ncounters) + nattrs + 3; 383*7c478bd9Sstevel@tonic-gate toks = (char **)emalloc(ntoks * sizeof (char *)); 384*7c478bd9Sstevel@tonic-gate tok_info = (tok_info_t *)emalloc(ntoks * sizeof (tok_info_t)); 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate tok_funcs = (int (**)(int, char *))emalloc(ntoks * 387*7c478bd9Sstevel@tonic-gate sizeof (int (*)(char *))); 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate for (i = 0; i < ntoks; i++) { 390*7c478bd9Sstevel@tonic-gate toks[i] = NULL; 391*7c478bd9Sstevel@tonic-gate tok_funcs[i] = NULL; 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate x = 0; 395*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 396*7c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 397*7c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "pic%d", i); 398*7c478bd9Sstevel@tonic-gate tok_info[x].name = "pic"; 399*7c478bd9Sstevel@tonic-gate tok_info[i].picnum = i; 400*7c478bd9Sstevel@tonic-gate tok_funcs[x] = pic; 401*7c478bd9Sstevel@tonic-gate x++; 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 405*7c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 406*7c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "nouser%d", i); 407*7c478bd9Sstevel@tonic-gate tok_info[x].name = "nouser"; 408*7c478bd9Sstevel@tonic-gate tok_info[x].picnum = i; 409*7c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 410*7c478bd9Sstevel@tonic-gate x++; 411*7c478bd9Sstevel@tonic-gate } 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 414*7c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 415*7c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "sys%d", i); 416*7c478bd9Sstevel@tonic-gate tok_info[x].name = "sys"; 417*7c478bd9Sstevel@tonic-gate tok_info[x].picnum = i; 418*7c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 419*7c478bd9Sstevel@tonic-gate x++; 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate for (j = 0; j < nattrs; j++) { 422*7c478bd9Sstevel@tonic-gate toklen = strlen(attrlist[j]) + 3; 423*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 424*7c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(toklen); 425*7c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], toklen, "%s%d", attrlist[j], 426*7c478bd9Sstevel@tonic-gate i); 427*7c478bd9Sstevel@tonic-gate tok_info[x].name = attrlist[j]; 428*7c478bd9Sstevel@tonic-gate tok_info[x].picnum = i; 429*7c478bd9Sstevel@tonic-gate tok_funcs[x] = doattr; 430*7c478bd9Sstevel@tonic-gate x++; 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* 434*7c478bd9Sstevel@tonic-gate * Now create a token for this attribute with no picnum; if used 435*7c478bd9Sstevel@tonic-gate * it will be applied to all reqs. 436*7c478bd9Sstevel@tonic-gate */ 437*7c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(toklen); 438*7c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], toklen, "%s", attrlist[j]); 439*7c478bd9Sstevel@tonic-gate tok_info[x].name = attrlist[j]; 440*7c478bd9Sstevel@tonic-gate tok_info[x].picnum = -1; 441*7c478bd9Sstevel@tonic-gate tok_funcs[x] = doattr; 442*7c478bd9Sstevel@tonic-gate x++; 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate toks[x] = "nouser"; 446*7c478bd9Sstevel@tonic-gate tok_info[x].name = "nouser"; 447*7c478bd9Sstevel@tonic-gate tok_info[x].picnum = -1; 448*7c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 449*7c478bd9Sstevel@tonic-gate x++; 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate toks[x] = "sys"; 452*7c478bd9Sstevel@tonic-gate tok_info[x].name = "sys"; 453*7c478bd9Sstevel@tonic-gate tok_info[x].picnum = -1; 454*7c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 455*7c478bd9Sstevel@tonic-gate x++; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate toks[x] = NULL; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate opts = strcpy(alloca(strlen(spec) + 1), spec); 460*7c478bd9Sstevel@tonic-gate while (*opts != '\0') { 461*7c478bd9Sstevel@tonic-gate int idx = getsubopt(&opts, toks, &val); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate if (idx == -1) { 464*7c478bd9Sstevel@tonic-gate if (find_event(val) == 0) { 465*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("bad token '%s'\n"), val); 466*7c478bd9Sstevel@tonic-gate goto inval; 467*7c478bd9Sstevel@tonic-gate } else 468*7c478bd9Sstevel@tonic-gate continue; 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (tok_funcs[idx](idx, val) == -1) 472*7c478bd9Sstevel@tonic-gate goto inval; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate /* 476*7c478bd9Sstevel@tonic-gate * The string has been processed. Now count how many PICs were used, 477*7c478bd9Sstevel@tonic-gate * create a request set, and specify each request properly. 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate if ((set = cpc_set_create(cpc)) == NULL) { 481*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 482*7c478bd9Sstevel@tonic-gate exit(0); 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 486*7c478bd9Sstevel@tonic-gate if (reqs[i].cr_event[0] == '\0') 487*7c478bd9Sstevel@tonic-gate continue; 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate /* 490*7c478bd9Sstevel@tonic-gate * If the caller wishes to measure events on the physical CPU, 491*7c478bd9Sstevel@tonic-gate * we need to add SMT attributes to each request. 492*7c478bd9Sstevel@tonic-gate */ 493*7c478bd9Sstevel@tonic-gate if (smt) 494*7c478bd9Sstevel@tonic-gate smt_special(i); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate req_attrs = (cpc_attr_t *)emalloc(reqs[i].cr_nattrs * 497*7c478bd9Sstevel@tonic-gate sizeof (cpc_attr_t)); 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate j = 0; 500*7c478bd9Sstevel@tonic-gate for (tmp = attrs[i]; tmp != NULL; tmp = tmp->next) { 501*7c478bd9Sstevel@tonic-gate req_attrs[j].ca_name = tmp->name; 502*7c478bd9Sstevel@tonic-gate req_attrs[j].ca_val = tmp->val; 503*7c478bd9Sstevel@tonic-gate j++; 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, reqs[i].cr_event, 0, 507*7c478bd9Sstevel@tonic-gate reqs[i].cr_flags, reqs[i].cr_nattrs, req_attrs) == -1) { 508*7c478bd9Sstevel@tonic-gate free(req_attrs); 509*7c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 510*7c478bd9Sstevel@tonic-gate strtoset_err( 511*7c478bd9Sstevel@tonic-gate gettext("cpc_set_add_request() failed: %s\n"), 512*7c478bd9Sstevel@tonic-gate strerror(errno)); 513*7c478bd9Sstevel@tonic-gate goto inval; 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate free(req_attrs); 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate strtoset_cleanup(); 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate return (set); 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate inval: 524*7c478bd9Sstevel@tonic-gate strtoset_cleanup(); 525*7c478bd9Sstevel@tonic-gate errno = EINVAL; 526*7c478bd9Sstevel@tonic-gate return (NULL); 527*7c478bd9Sstevel@tonic-gate } 528*7c478bd9Sstevel@tonic-gate 529*7c478bd9Sstevel@tonic-gate static void 530*7c478bd9Sstevel@tonic-gate strtoset_cleanup(void) 531*7c478bd9Sstevel@tonic-gate { 532*7c478bd9Sstevel@tonic-gate int i; 533*7c478bd9Sstevel@tonic-gate tmp_attr_t *tmp, *p; 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) 536*7c478bd9Sstevel@tonic-gate free(attrlist[i]); 537*7c478bd9Sstevel@tonic-gate free(attrlist); 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 540*7c478bd9Sstevel@tonic-gate for (tmp = attrs[i]; tmp != NULL; tmp = p) { 541*7c478bd9Sstevel@tonic-gate p = tmp->next; 542*7c478bd9Sstevel@tonic-gate free(tmp); 543*7c478bd9Sstevel@tonic-gate } 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate free(attrs); 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate for (i = 0; i < ntoks - 3; i++) 548*7c478bd9Sstevel@tonic-gate /* 549*7c478bd9Sstevel@tonic-gate * We free all but the last three tokens: "nouser", "sys", NULL 550*7c478bd9Sstevel@tonic-gate */ 551*7c478bd9Sstevel@tonic-gate free(toks[i]); 552*7c478bd9Sstevel@tonic-gate free(toks); 553*7c478bd9Sstevel@tonic-gate free(reqs); 554*7c478bd9Sstevel@tonic-gate free(tok_info); 555*7c478bd9Sstevel@tonic-gate free(tok_funcs); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* 559*7c478bd9Sstevel@tonic-gate * The following is called to modify requests so that they count events on 560*7c478bd9Sstevel@tonic-gate * behalf of a physical processor, instead of a logical processor. It duplicates 561*7c478bd9Sstevel@tonic-gate * the request flags for the sibling processor (i.e. if the request counts user 562*7c478bd9Sstevel@tonic-gate * events, add an attribute to count user events on the sibling processor also). 563*7c478bd9Sstevel@tonic-gate */ 564*7c478bd9Sstevel@tonic-gate static void 565*7c478bd9Sstevel@tonic-gate smt_special(int picnum) 566*7c478bd9Sstevel@tonic-gate { 567*7c478bd9Sstevel@tonic-gate tmp_attr_t *attr; 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate if (reqs[picnum].cr_flags & CPC_COUNT_USER) { 570*7c478bd9Sstevel@tonic-gate attr = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 571*7c478bd9Sstevel@tonic-gate attr->name = "count_sibling_usr"; 572*7c478bd9Sstevel@tonic-gate attr->val = 1; 573*7c478bd9Sstevel@tonic-gate attr->next = attrs[picnum]; 574*7c478bd9Sstevel@tonic-gate attrs[picnum] = attr; 575*7c478bd9Sstevel@tonic-gate reqs[picnum].cr_nattrs++; 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (reqs[picnum].cr_flags & CPC_COUNT_SYSTEM) { 579*7c478bd9Sstevel@tonic-gate attr = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 580*7c478bd9Sstevel@tonic-gate attr->name = "count_sibling_sys"; 581*7c478bd9Sstevel@tonic-gate attr->val = 1; 582*7c478bd9Sstevel@tonic-gate attr->next = attrs[picnum]; 583*7c478bd9Sstevel@tonic-gate attrs[picnum] = attr; 584*7c478bd9Sstevel@tonic-gate reqs[picnum].cr_nattrs++; 585*7c478bd9Sstevel@tonic-gate } 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate /* 589*7c478bd9Sstevel@tonic-gate * If we ever fail to get memory, we print an error message and exit. 590*7c478bd9Sstevel@tonic-gate */ 591*7c478bd9Sstevel@tonic-gate static void * 592*7c478bd9Sstevel@tonic-gate emalloc(size_t n) 593*7c478bd9Sstevel@tonic-gate { 594*7c478bd9Sstevel@tonic-gate void *p = malloc(n); 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate if (p == NULL) { 597*7c478bd9Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 598*7c478bd9Sstevel@tonic-gate exit(0); 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate return (p); 602*7c478bd9Sstevel@tonic-gate } 603