17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55d3a5ad8Srab * Common Development and Distribution License (the "License"). 65d3a5ad8Srab * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*e850fb01SKuriakose Kuruvilla * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include <alloca.h> 297c478bd9Sstevel@tonic-gate #include <errno.h> 307c478bd9Sstevel@tonic-gate #include <libintl.h> 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include "libcpc.h" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Takes a string and converts it to a cpc_set_t. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * While processing the string using getsubopt(), we will use an array of 387c478bd9Sstevel@tonic-gate * requests to hold the data, and a proprietary representation of attributes 397c478bd9Sstevel@tonic-gate * which allow us to avoid a realloc()/bcopy() dance every time we come across 407c478bd9Sstevel@tonic-gate * a new attribute. 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * Not until after the string has been processed in its entirety do we 437c478bd9Sstevel@tonic-gate * allocate and specify a request set properly. 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * Leave enough room in token strings for picn, nousern, or sysn where n is 487c478bd9Sstevel@tonic-gate * picnum. 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate #define TOK_SIZE 10 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate typedef struct __tmp_attr { 537c478bd9Sstevel@tonic-gate char *name; 547c478bd9Sstevel@tonic-gate uint64_t val; 557c478bd9Sstevel@tonic-gate struct __tmp_attr *next; 567c478bd9Sstevel@tonic-gate } tmp_attr_t; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate typedef struct __tok_info { 597c478bd9Sstevel@tonic-gate char *name; 607c478bd9Sstevel@tonic-gate int picnum; 617c478bd9Sstevel@tonic-gate } tok_info_t; 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate typedef struct __request_t { 647c478bd9Sstevel@tonic-gate char cr_event[CPC_MAX_EVENT_LEN]; 657c478bd9Sstevel@tonic-gate uint_t cr_flags; 667c478bd9Sstevel@tonic-gate uint_t cr_nattrs; /* # CPU-specific attrs */ 677c478bd9Sstevel@tonic-gate } request_t; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static void strtoset_cleanup(void); 707c478bd9Sstevel@tonic-gate static void smt_special(int picnum); 717c478bd9Sstevel@tonic-gate static void *emalloc(size_t n); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Clients of cpc_strtoset may set this to specify an error handler during 757c478bd9Sstevel@tonic-gate * string parsing. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate cpc_errhndlr_t *strtoset_errfn = NULL; 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate static request_t *reqs; 807c478bd9Sstevel@tonic-gate static int nreqs; 817c478bd9Sstevel@tonic-gate static int ncounters; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate static tmp_attr_t **attrs; 847c478bd9Sstevel@tonic-gate static int ntoks; 857c478bd9Sstevel@tonic-gate static char **toks; 867c478bd9Sstevel@tonic-gate static tok_info_t *tok_info; 877c478bd9Sstevel@tonic-gate static int (*(*tok_funcs))(int, char *); 887c478bd9Sstevel@tonic-gate static char **attrlist; /* array of ptrs to toks in attrlistp */ 897c478bd9Sstevel@tonic-gate static int nattrs; 907c478bd9Sstevel@tonic-gate static cpc_t *cpc; 917c478bd9Sstevel@tonic-gate static int found; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate static void 947c478bd9Sstevel@tonic-gate strtoset_err(const char *fmt, ...) 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate va_list ap; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (strtoset_errfn == NULL) 997c478bd9Sstevel@tonic-gate return; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate va_start(ap, fmt); 1027c478bd9Sstevel@tonic-gate (*strtoset_errfn)("cpc_strtoset", -1, fmt, ap); 1037c478bd9Sstevel@tonic-gate va_end(ap); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1077c478bd9Sstevel@tonic-gate static void 1087c478bd9Sstevel@tonic-gate event_walker(void *arg, uint_t picno, const char *event) 1097c478bd9Sstevel@tonic-gate { 1107c478bd9Sstevel@tonic-gate if (strncmp(arg, event, CPC_MAX_EVENT_LEN) == 0) 1117c478bd9Sstevel@tonic-gate found = 1; 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate static int 1157c478bd9Sstevel@tonic-gate event_valid(int picnum, char *event) 1167c478bd9Sstevel@tonic-gate { 117d0ecda70Svk226950 char *end_event; 118*e850fb01SKuriakose Kuruvilla int err; 1195d3a5ad8Srab 120*e850fb01SKuriakose Kuruvilla found = 0; 121d0ecda70Svk226950 1227c478bd9Sstevel@tonic-gate cpc_walk_events_pic(cpc, picnum, event, event_walker); 1235d3a5ad8Srab 1245d3a5ad8Srab if (found) 1255d3a5ad8Srab return (1); 1265d3a5ad8Srab 127c7a079a8SJonathan Haslam cpc_walk_generic_events_pic(cpc, picnum, event, event_walker); 128c7a079a8SJonathan Haslam 129c7a079a8SJonathan Haslam if (found) 130c7a079a8SJonathan Haslam return (1); 131c7a079a8SJonathan Haslam 1325d3a5ad8Srab /* 1335d3a5ad8Srab * Before assuming this is an invalid event, see if we have been given 134*e850fb01SKuriakose Kuruvilla * a raw event code. 135d0ecda70Svk226950 * Check the second argument of strtol() to ensure invalid events 136d0ecda70Svk226950 * beginning with number do not go through. 1375d3a5ad8Srab */ 138*e850fb01SKuriakose Kuruvilla err = errno; 139*e850fb01SKuriakose Kuruvilla errno = 0; 140*e850fb01SKuriakose Kuruvilla (void) strtol(event, &end_event, 0); 141*e850fb01SKuriakose Kuruvilla if ((errno == 0) && (*end_event == '\0')) { 1425d3a5ad8Srab /* 1435d3a5ad8Srab * Success - this is a valid raw code in hex, decimal, or octal. 1445d3a5ad8Srab */ 145*e850fb01SKuriakose Kuruvilla errno = err; 1465d3a5ad8Srab return (1); 147*e850fb01SKuriakose Kuruvilla } 1485d3a5ad8Srab 149*e850fb01SKuriakose Kuruvilla errno = err; 1505d3a5ad8Srab return (0); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * An unknown token was encountered; check here if it is an implicit event 1557c478bd9Sstevel@tonic-gate * name. We allow users to omit the "picn=" portion of the event spec, and 1567c478bd9Sstevel@tonic-gate * assign such events to available pics in order they are returned from 1577c478bd9Sstevel@tonic-gate * getsubopt(3C). We start our search for an available pic _after_ the highest 1587c478bd9Sstevel@tonic-gate * picnum to be assigned. This ensures that the event spec can never be out of 1597c478bd9Sstevel@tonic-gate * order; i.e. if the event string is "eventa,eventb" we must ensure that the 1607c478bd9Sstevel@tonic-gate * picnum counting eventa is less than the picnum counting eventb. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate static int 1637c478bd9Sstevel@tonic-gate find_event(char *event) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate int i; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /* 1685d3a5ad8Srab * Event names cannot have '=' in them. If present here, it means we 1695d3a5ad8Srab * have encountered an unknown token (foo=bar, for example). 1705d3a5ad8Srab */ 1715d3a5ad8Srab if (strchr(event, '=') != NULL) 1725d3a5ad8Srab return (0); 1735d3a5ad8Srab 1745d3a5ad8Srab /* 1757c478bd9Sstevel@tonic-gate * Find the first unavailable pic, after which we must start our search. 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate for (i = ncounters - 1; i >= 0; i--) { 1787c478bd9Sstevel@tonic-gate if (reqs[i].cr_event[0] != '\0') 1797c478bd9Sstevel@tonic-gate break; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * If the last counter has been assigned, we cannot place this event. 1837c478bd9Sstevel@tonic-gate */ 1847c478bd9Sstevel@tonic-gate if (i == ncounters - 1) 1857c478bd9Sstevel@tonic-gate return (0); 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * If none of the counters have been assigned yet, i is -1 and we will 1897c478bd9Sstevel@tonic-gate * begin our search at 0. Else we begin our search at the counter after 1907c478bd9Sstevel@tonic-gate * the last one currently assigned. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate i++; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate for (; i < ncounters; i++) { 1957c478bd9Sstevel@tonic-gate if (event_valid(i, event) == 0) 1967c478bd9Sstevel@tonic-gate continue; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate nreqs++; 1997c478bd9Sstevel@tonic-gate (void) strncpy(reqs[i].cr_event, event, CPC_MAX_EVENT_LEN); 2007c478bd9Sstevel@tonic-gate return (1); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate return (0); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate static int 2077c478bd9Sstevel@tonic-gate pic(int tok, char *val) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Make sure the each pic only appears in the spec once. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate if (reqs[picnum].cr_event[0] != '\0') { 2147c478bd9Sstevel@tonic-gate strtoset_err(gettext("repeated 'pic%d' token\n"), picnum); 2157c478bd9Sstevel@tonic-gate return (-1); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate if (val == NULL || val[0] == '\0') { 2197c478bd9Sstevel@tonic-gate strtoset_err(gettext("missing 'pic%d' value\n"), picnum); 2207c478bd9Sstevel@tonic-gate return (-1); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate if (event_valid(picnum, val) == 0) { 2247c478bd9Sstevel@tonic-gate strtoset_err(gettext("pic%d cannot measure event '%s' on this " 2257c478bd9Sstevel@tonic-gate "cpu\n"), picnum, val); 2267c478bd9Sstevel@tonic-gate return (-1); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate nreqs++; 2307c478bd9Sstevel@tonic-gate (void) strncpy(reqs[picnum].cr_event, val, CPC_MAX_EVENT_LEN); 2317c478bd9Sstevel@tonic-gate return (0); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * We explicitly ignore any value provided for these tokens, as their 2367c478bd9Sstevel@tonic-gate * mere presence signals us to turn on or off the relevant flags. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2397c478bd9Sstevel@tonic-gate static int 2407c478bd9Sstevel@tonic-gate flag(int tok, char *val) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate int i; 2437c478bd9Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * If picnum is -1, this flag should be applied to all reqs. 2477c478bd9Sstevel@tonic-gate */ 2487c478bd9Sstevel@tonic-gate for (i = (picnum == -1) ? 0 : picnum; i < ncounters; i++) { 2497c478bd9Sstevel@tonic-gate if (strcmp(tok_info[tok].name, "nouser") == 0) 2507c478bd9Sstevel@tonic-gate reqs[i].cr_flags &= ~CPC_COUNT_USER; 2517c478bd9Sstevel@tonic-gate else if (strcmp(tok_info[tok].name, "sys") == 0) 2527c478bd9Sstevel@tonic-gate reqs[i].cr_flags |= CPC_COUNT_SYSTEM; 2537c478bd9Sstevel@tonic-gate else 2547c478bd9Sstevel@tonic-gate return (-1); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (picnum != -1) 2577c478bd9Sstevel@tonic-gate break; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate return (0); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static int 2647c478bd9Sstevel@tonic-gate doattr(int tok, char *val) 2657c478bd9Sstevel@tonic-gate { 2667c478bd9Sstevel@tonic-gate int i; 2677c478bd9Sstevel@tonic-gate int picnum = tok_info[tok].picnum; 2687c478bd9Sstevel@tonic-gate tmp_attr_t *tmp; 2697c478bd9Sstevel@tonic-gate char *endptr; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* 2727c478bd9Sstevel@tonic-gate * If picnum is -1, this attribute should be applied to all reqs. 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate for (i = (picnum == -1) ? 0 : picnum; i < ncounters; i++) { 2757c478bd9Sstevel@tonic-gate tmp = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 2767c478bd9Sstevel@tonic-gate tmp->name = tok_info[tok].name; 2777c478bd9Sstevel@tonic-gate if (val != NULL) { 2787c478bd9Sstevel@tonic-gate tmp->val = strtoll(val, &endptr, 0); 2797c478bd9Sstevel@tonic-gate if (endptr == val) { 2807c478bd9Sstevel@tonic-gate strtoset_err(gettext("invalid value '%s' for " 2817c478bd9Sstevel@tonic-gate "attribute '%s'\n"), val, tmp->name); 2827c478bd9Sstevel@tonic-gate free(tmp); 2837c478bd9Sstevel@tonic-gate return (-1); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate } else 2867c478bd9Sstevel@tonic-gate /* 2877c478bd9Sstevel@tonic-gate * No value was provided for this attribute, 2887c478bd9Sstevel@tonic-gate * so specify a default value of 1. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate tmp->val = 1; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate tmp->next = attrs[i]; 2937c478bd9Sstevel@tonic-gate attrs[i] = tmp; 2947c478bd9Sstevel@tonic-gate reqs[i].cr_nattrs++; 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate if (picnum != -1) 2977c478bd9Sstevel@tonic-gate break; 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate return (0); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3047c478bd9Sstevel@tonic-gate static void 3057c478bd9Sstevel@tonic-gate attr_count_walker(void *arg, const char *attr) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * We don't allow picnum to be specified by the user. 3097c478bd9Sstevel@tonic-gate */ 3107c478bd9Sstevel@tonic-gate if (strncmp(attr, "picnum", 7) == 0) 3117c478bd9Sstevel@tonic-gate return; 3127c478bd9Sstevel@tonic-gate (*(int *)arg)++; 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate static int 3167c478bd9Sstevel@tonic-gate cpc_count_attrs(cpc_t *cpc) 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate int nattrs = 0; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc, &nattrs, attr_count_walker); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate return (nattrs); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate static void 3267c478bd9Sstevel@tonic-gate attr_walker(void *arg, const char *attr) 3277c478bd9Sstevel@tonic-gate { 3287c478bd9Sstevel@tonic-gate int *i = arg; 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (strncmp(attr, "picnum", 7) == 0) 3317c478bd9Sstevel@tonic-gate return; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if ((attrlist[(*i)++] = strdup(attr)) == NULL) { 3347c478bd9Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 3357c478bd9Sstevel@tonic-gate exit(0); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate cpc_set_t * 3407c478bd9Sstevel@tonic-gate cpc_strtoset(cpc_t *cpcin, const char *spec, int smt) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate cpc_set_t *set; 3437c478bd9Sstevel@tonic-gate cpc_attr_t *req_attrs; 3447c478bd9Sstevel@tonic-gate tmp_attr_t *tmp; 3457c478bd9Sstevel@tonic-gate size_t toklen; 3467c478bd9Sstevel@tonic-gate int i; 3477c478bd9Sstevel@tonic-gate int j; 3487c478bd9Sstevel@tonic-gate int x; 3497c478bd9Sstevel@tonic-gate char *opts; 3507c478bd9Sstevel@tonic-gate char *val; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate cpc = cpcin; 3537c478bd9Sstevel@tonic-gate nattrs = 0; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate ncounters = cpc_npic(cpc); 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate reqs = (request_t *)emalloc(ncounters * sizeof (request_t)); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate attrs = (tmp_attr_t **)emalloc(ncounters * sizeof (tmp_attr_t *)); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 3627c478bd9Sstevel@tonic-gate reqs[i].cr_event[0] = '\0'; 3637c478bd9Sstevel@tonic-gate reqs[i].cr_flags = CPC_COUNT_USER; 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * Each pic will have at least one attribute: the physical pic 3667c478bd9Sstevel@tonic-gate * assignment via the "picnum" attribute. Set that up here for 3677c478bd9Sstevel@tonic-gate * each request. 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate reqs[i].cr_nattrs = 1; 3707c478bd9Sstevel@tonic-gate attrs[i] = emalloc(sizeof (tmp_attr_t)); 3717c478bd9Sstevel@tonic-gate attrs[i]->name = "picnum"; 3727c478bd9Sstevel@tonic-gate attrs[i]->val = i; 3737c478bd9Sstevel@tonic-gate attrs[i]->next = NULL; 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * Build up a list of acceptable tokens. 3787c478bd9Sstevel@tonic-gate * 3797c478bd9Sstevel@tonic-gate * Permitted tokens are 3807c478bd9Sstevel@tonic-gate * picn=event 3817c478bd9Sstevel@tonic-gate * nousern 3827c478bd9Sstevel@tonic-gate * sysn 3837c478bd9Sstevel@tonic-gate * attrn=val 3847c478bd9Sstevel@tonic-gate * nouser 3857c478bd9Sstevel@tonic-gate * sys 3867c478bd9Sstevel@tonic-gate * attr=val 3877c478bd9Sstevel@tonic-gate * 3887c478bd9Sstevel@tonic-gate * Where n is a counter number, and attr is any attribute supported by 3897c478bd9Sstevel@tonic-gate * the current processor. 3907c478bd9Sstevel@tonic-gate * 3917c478bd9Sstevel@tonic-gate * If a token appears without a counter number, it applies to all 3927c478bd9Sstevel@tonic-gate * counters in the request set. 3937c478bd9Sstevel@tonic-gate * 3947c478bd9Sstevel@tonic-gate * The number of tokens is: 3957c478bd9Sstevel@tonic-gate * 3967c478bd9Sstevel@tonic-gate * picn: ncounters 3977c478bd9Sstevel@tonic-gate * generic flags: 2 * ncounters (nouser, sys) 3987c478bd9Sstevel@tonic-gate * attrs: nattrs * ncounters 3997c478bd9Sstevel@tonic-gate * attrs with no picnum: nattrs 4007c478bd9Sstevel@tonic-gate * generic flags with no picnum: 2 (nouser, sys) 4017c478bd9Sstevel@tonic-gate * NULL token to signify end of list to getsubopt(3C). 4027c478bd9Sstevel@tonic-gate * 4037c478bd9Sstevel@tonic-gate * Matching each token's index in the token table is a function which 4047c478bd9Sstevel@tonic-gate * process that token; these are in tok_funcs. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * Count the number of valid attributes. 4097c478bd9Sstevel@tonic-gate * Set up the attrlist array to point to the attributes in attrlistp. 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate nattrs = cpc_count_attrs(cpc); 4127c478bd9Sstevel@tonic-gate attrlist = (char **)emalloc(nattrs * sizeof (char *)); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate i = 0; 4157c478bd9Sstevel@tonic-gate cpc_walk_attrs(cpc, &i, attr_walker); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate ntoks = ncounters + (2 * ncounters) + (nattrs * ncounters) + nattrs + 3; 4187c478bd9Sstevel@tonic-gate toks = (char **)emalloc(ntoks * sizeof (char *)); 4197c478bd9Sstevel@tonic-gate tok_info = (tok_info_t *)emalloc(ntoks * sizeof (tok_info_t)); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate tok_funcs = (int (**)(int, char *))emalloc(ntoks * 4227c478bd9Sstevel@tonic-gate sizeof (int (*)(char *))); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate for (i = 0; i < ntoks; i++) { 4257c478bd9Sstevel@tonic-gate toks[i] = NULL; 4267c478bd9Sstevel@tonic-gate tok_funcs[i] = NULL; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate x = 0; 4307c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4317c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 4327c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "pic%d", i); 4337c478bd9Sstevel@tonic-gate tok_info[x].name = "pic"; 4347c478bd9Sstevel@tonic-gate tok_info[i].picnum = i; 4357c478bd9Sstevel@tonic-gate tok_funcs[x] = pic; 4367c478bd9Sstevel@tonic-gate x++; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4407c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 4417c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "nouser%d", i); 4427c478bd9Sstevel@tonic-gate tok_info[x].name = "nouser"; 4437c478bd9Sstevel@tonic-gate tok_info[x].picnum = i; 4447c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 4457c478bd9Sstevel@tonic-gate x++; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4497c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(TOK_SIZE); 4507c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], TOK_SIZE, "sys%d", i); 4517c478bd9Sstevel@tonic-gate tok_info[x].name = "sys"; 4527c478bd9Sstevel@tonic-gate tok_info[x].picnum = i; 4537c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 4547c478bd9Sstevel@tonic-gate x++; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate for (j = 0; j < nattrs; j++) { 4577c478bd9Sstevel@tonic-gate toklen = strlen(attrlist[j]) + 3; 4587c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 4597c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(toklen); 4607c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], toklen, "%s%d", attrlist[j], 4617c478bd9Sstevel@tonic-gate i); 4627c478bd9Sstevel@tonic-gate tok_info[x].name = attrlist[j]; 4637c478bd9Sstevel@tonic-gate tok_info[x].picnum = i; 4647c478bd9Sstevel@tonic-gate tok_funcs[x] = doattr; 4657c478bd9Sstevel@tonic-gate x++; 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Now create a token for this attribute with no picnum; if used 4707c478bd9Sstevel@tonic-gate * it will be applied to all reqs. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate toks[x] = (char *)emalloc(toklen); 4737c478bd9Sstevel@tonic-gate (void) snprintf(toks[x], toklen, "%s", attrlist[j]); 4747c478bd9Sstevel@tonic-gate tok_info[x].name = attrlist[j]; 4757c478bd9Sstevel@tonic-gate tok_info[x].picnum = -1; 4767c478bd9Sstevel@tonic-gate tok_funcs[x] = doattr; 4777c478bd9Sstevel@tonic-gate x++; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate toks[x] = "nouser"; 4817c478bd9Sstevel@tonic-gate tok_info[x].name = "nouser"; 4827c478bd9Sstevel@tonic-gate tok_info[x].picnum = -1; 4837c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 4847c478bd9Sstevel@tonic-gate x++; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate toks[x] = "sys"; 4877c478bd9Sstevel@tonic-gate tok_info[x].name = "sys"; 4887c478bd9Sstevel@tonic-gate tok_info[x].picnum = -1; 4897c478bd9Sstevel@tonic-gate tok_funcs[x] = flag; 4907c478bd9Sstevel@tonic-gate x++; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate toks[x] = NULL; 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate opts = strcpy(alloca(strlen(spec) + 1), spec); 4957c478bd9Sstevel@tonic-gate while (*opts != '\0') { 4967c478bd9Sstevel@tonic-gate int idx = getsubopt(&opts, toks, &val); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate if (idx == -1) { 4997c478bd9Sstevel@tonic-gate if (find_event(val) == 0) { 5007c478bd9Sstevel@tonic-gate strtoset_err(gettext("bad token '%s'\n"), val); 5017c478bd9Sstevel@tonic-gate goto inval; 5027c478bd9Sstevel@tonic-gate } else 5037c478bd9Sstevel@tonic-gate continue; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (tok_funcs[idx](idx, val) == -1) 5077c478bd9Sstevel@tonic-gate goto inval; 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * The string has been processed. Now count how many PICs were used, 5127c478bd9Sstevel@tonic-gate * create a request set, and specify each request properly. 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate if ((set = cpc_set_create(cpc)) == NULL) { 5167c478bd9Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 5177c478bd9Sstevel@tonic-gate exit(0); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 5217c478bd9Sstevel@tonic-gate if (reqs[i].cr_event[0] == '\0') 5227c478bd9Sstevel@tonic-gate continue; 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * If the caller wishes to measure events on the physical CPU, 5267c478bd9Sstevel@tonic-gate * we need to add SMT attributes to each request. 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate if (smt) 5297c478bd9Sstevel@tonic-gate smt_special(i); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate req_attrs = (cpc_attr_t *)emalloc(reqs[i].cr_nattrs * 5327c478bd9Sstevel@tonic-gate sizeof (cpc_attr_t)); 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate j = 0; 5357c478bd9Sstevel@tonic-gate for (tmp = attrs[i]; tmp != NULL; tmp = tmp->next) { 5367c478bd9Sstevel@tonic-gate req_attrs[j].ca_name = tmp->name; 5377c478bd9Sstevel@tonic-gate req_attrs[j].ca_val = tmp->val; 5387c478bd9Sstevel@tonic-gate j++; 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, reqs[i].cr_event, 0, 5427c478bd9Sstevel@tonic-gate reqs[i].cr_flags, reqs[i].cr_nattrs, req_attrs) == -1) { 5437c478bd9Sstevel@tonic-gate free(req_attrs); 5447c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 5457c478bd9Sstevel@tonic-gate strtoset_err( 5467c478bd9Sstevel@tonic-gate gettext("cpc_set_add_request() failed: %s\n"), 5477c478bd9Sstevel@tonic-gate strerror(errno)); 5487c478bd9Sstevel@tonic-gate goto inval; 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate free(req_attrs); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate strtoset_cleanup(); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate return (set); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate inval: 5597c478bd9Sstevel@tonic-gate strtoset_cleanup(); 5607c478bd9Sstevel@tonic-gate errno = EINVAL; 5617c478bd9Sstevel@tonic-gate return (NULL); 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate static void 5657c478bd9Sstevel@tonic-gate strtoset_cleanup(void) 5667c478bd9Sstevel@tonic-gate { 5677c478bd9Sstevel@tonic-gate int i; 5687c478bd9Sstevel@tonic-gate tmp_attr_t *tmp, *p; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate for (i = 0; i < nattrs; i++) 5717c478bd9Sstevel@tonic-gate free(attrlist[i]); 5727c478bd9Sstevel@tonic-gate free(attrlist); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate for (i = 0; i < ncounters; i++) { 5757c478bd9Sstevel@tonic-gate for (tmp = attrs[i]; tmp != NULL; tmp = p) { 5767c478bd9Sstevel@tonic-gate p = tmp->next; 5777c478bd9Sstevel@tonic-gate free(tmp); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate free(attrs); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate for (i = 0; i < ntoks - 3; i++) 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * We free all but the last three tokens: "nouser", "sys", NULL 5857c478bd9Sstevel@tonic-gate */ 5867c478bd9Sstevel@tonic-gate free(toks[i]); 5877c478bd9Sstevel@tonic-gate free(toks); 5887c478bd9Sstevel@tonic-gate free(reqs); 5897c478bd9Sstevel@tonic-gate free(tok_info); 5907c478bd9Sstevel@tonic-gate free(tok_funcs); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * The following is called to modify requests so that they count events on 5957c478bd9Sstevel@tonic-gate * behalf of a physical processor, instead of a logical processor. It duplicates 5967c478bd9Sstevel@tonic-gate * the request flags for the sibling processor (i.e. if the request counts user 5977c478bd9Sstevel@tonic-gate * events, add an attribute to count user events on the sibling processor also). 5987c478bd9Sstevel@tonic-gate */ 5997c478bd9Sstevel@tonic-gate static void 6007c478bd9Sstevel@tonic-gate smt_special(int picnum) 6017c478bd9Sstevel@tonic-gate { 6027c478bd9Sstevel@tonic-gate tmp_attr_t *attr; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (reqs[picnum].cr_flags & CPC_COUNT_USER) { 6057c478bd9Sstevel@tonic-gate attr = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 6067c478bd9Sstevel@tonic-gate attr->name = "count_sibling_usr"; 6077c478bd9Sstevel@tonic-gate attr->val = 1; 6087c478bd9Sstevel@tonic-gate attr->next = attrs[picnum]; 6097c478bd9Sstevel@tonic-gate attrs[picnum] = attr; 6107c478bd9Sstevel@tonic-gate reqs[picnum].cr_nattrs++; 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (reqs[picnum].cr_flags & CPC_COUNT_SYSTEM) { 6147c478bd9Sstevel@tonic-gate attr = (tmp_attr_t *)emalloc(sizeof (tmp_attr_t)); 6157c478bd9Sstevel@tonic-gate attr->name = "count_sibling_sys"; 6167c478bd9Sstevel@tonic-gate attr->val = 1; 6177c478bd9Sstevel@tonic-gate attr->next = attrs[picnum]; 6187c478bd9Sstevel@tonic-gate attrs[picnum] = attr; 6197c478bd9Sstevel@tonic-gate reqs[picnum].cr_nattrs++; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * If we ever fail to get memory, we print an error message and exit. 6257c478bd9Sstevel@tonic-gate */ 6267c478bd9Sstevel@tonic-gate static void * 6277c478bd9Sstevel@tonic-gate emalloc(size_t n) 6287c478bd9Sstevel@tonic-gate { 6297c478bd9Sstevel@tonic-gate void *p = malloc(n); 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate if (p == NULL) { 6327c478bd9Sstevel@tonic-gate strtoset_err(gettext("no memory available\n")); 6337c478bd9Sstevel@tonic-gate exit(0); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate return (p); 6377c478bd9Sstevel@tonic-gate } 638