1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <libintl.h> 32 #include <sys/types.h> 33 34 35 #include <libcpc.h> 36 #include "cpucmds.h" 37 38 #define CHARS_PER_REQ 11 /* space required for printing column headers */ 39 40 /* 41 * These routines are solely used to manage a list of request sets. 42 */ 43 44 struct __cpc_setgrp { 45 struct setgrp_elem { 46 cpc_set_t *set; 47 uint8_t sysonly; /* All reqs sys-mode only ? */ 48 int nreqs; 49 int *picnums; /* picnum used per req */ 50 cpc_buf_t *data1; 51 cpc_buf_t *data2; 52 cpc_buf_t *scratch; 53 char *name; 54 char *hdr; 55 } *sets; /* array of events and names */ 56 int nelem; /* size of array */ 57 int current; /* currently bound event in eventset */ 58 int smt; /* Measures physical events on SMT CPU */ 59 int has_sysonly_set; /* Does this group have a system-only set? */ 60 cpc_t *cpc; /* library handle */ 61 }; 62 63 static void *emalloc(size_t n); 64 65 cpc_setgrp_t * 66 cpc_setgrp_new(cpc_t *cpc, int smt) 67 { 68 cpc_setgrp_t *sgrp; 69 70 sgrp = emalloc(sizeof (*sgrp)); 71 sgrp->current = -1; 72 sgrp->cpc = cpc; 73 sgrp->smt = smt; 74 sgrp->has_sysonly_set = 0; 75 return (sgrp); 76 } 77 78 /* 79 * Walker to count the number of requests in a set, and check if any requests 80 * count user-mode events. 81 */ 82 /*ARGSUSED*/ 83 static void 84 cpc_setgrp_walker(void *arg, int index, const char *event, uint64_t preset, 85 uint_t flags, int nattrs, const cpc_attr_t *attrs) 86 { 87 struct setgrp_elem *se = arg; 88 89 se->nreqs++; 90 if (flags & CPC_COUNT_USER) 91 se->sysonly = 0; 92 } 93 94 /* 95 * Walker to discover the picnums used by the requests in a set. 96 */ 97 /*ARGSUSED*/ 98 static void 99 cpc_setgrp_picwalker(void *arg, int index, const char *event, uint64_t preset, 100 uint_t flags, int nattrs, const cpc_attr_t *attrs) 101 { 102 int *picnums = arg; 103 int i; 104 105 for (i = 0; i < nattrs; i++) { 106 if (strncmp(attrs[i].ca_name, "picnum", 7) == 0) 107 break; 108 } 109 if (i == nattrs) 110 picnums[index] = -1; 111 112 picnums[index] = (int)attrs[i].ca_val; 113 } 114 115 cpc_setgrp_t * 116 cpc_setgrp_newset(cpc_setgrp_t *sgrp, const char *spec, int *errcnt) 117 { 118 cpc_set_t *set; 119 struct setgrp_elem *new; 120 char hdr[CHARS_PER_REQ+1]; 121 int i; 122 123 if ((set = cpc_strtoset(sgrp->cpc, spec, sgrp->smt)) == NULL) { 124 *errcnt += 1; 125 return (NULL); 126 } 127 128 if ((new = realloc(sgrp->sets, (1 + sgrp->nelem) * sizeof (*new))) 129 == NULL) { 130 (void) fprintf(stderr, 131 gettext("cpc_setgrp: no re memory available\n")); 132 exit(0); 133 } 134 135 sgrp->sets = new; 136 sgrp->sets[sgrp->nelem].set = set; 137 /* 138 * Count the number of requests in the set we just made. If any requests 139 * in the set have CPC_COUNT_USER in the flags, the sysonly flag will 140 * be cleared. 141 */ 142 sgrp->sets[sgrp->nelem].nreqs = 0; 143 sgrp->sets[sgrp->nelem].sysonly = 1; 144 cpc_walk_requests(sgrp->cpc, set, &(sgrp->sets[sgrp->nelem]), 145 cpc_setgrp_walker); 146 147 if (sgrp->sets[sgrp->nelem].sysonly == 1) 148 sgrp->has_sysonly_set = 1; 149 150 sgrp->sets[sgrp->nelem].picnums = emalloc(sgrp->sets[sgrp->nelem].nreqs 151 * sizeof (int)); 152 153 sgrp->sets[sgrp->nelem].hdr = emalloc((sgrp->sets[sgrp->nelem].nreqs * 154 CHARS_PER_REQ) + 1); 155 156 /* 157 * Find out which picnums the requests are using. 158 */ 159 cpc_walk_requests(sgrp->cpc, set, sgrp->sets[sgrp->nelem].picnums, 160 cpc_setgrp_picwalker); 161 /* 162 * Use the picnums we discovered to build a printable header for this 163 * set. 164 */ 165 sgrp->sets[sgrp->nelem].hdr[0] = '\0'; 166 for (i = 0; i < sgrp->sets[sgrp->nelem].nreqs; i++) { 167 (void) snprintf(hdr, CHARS_PER_REQ, "%8s%-2d ", "pic", 168 sgrp->sets[sgrp->nelem].picnums[i]); 169 (void) strncat(sgrp->sets[sgrp->nelem].hdr, hdr, 170 sgrp->sets[sgrp->nelem].nreqs * CHARS_PER_REQ); 171 } 172 sgrp->sets[sgrp->nelem].hdr[strlen(sgrp->sets[sgrp->nelem].hdr)] = '\0'; 173 174 if ((sgrp->sets[sgrp->nelem].name = strdup(spec)) == NULL) { 175 (void) fprintf(stderr, 176 gettext("cpc_setgrp: no memory available\n")); 177 exit(0); 178 } 179 180 if ((sgrp->sets[sgrp->nelem].data1 = cpc_buf_create(sgrp->cpc, set)) 181 == NULL || 182 (sgrp->sets[sgrp->nelem].data2 = cpc_buf_create(sgrp->cpc, set)) 183 == NULL || 184 (sgrp->sets[sgrp->nelem].scratch = cpc_buf_create(sgrp->cpc, set)) 185 == NULL) { 186 (void) fprintf(stderr, 187 gettext("cpc_setgrp: no memory available\n")); 188 exit(0); 189 } 190 191 if (sgrp->current < 0) 192 sgrp->current = 0; 193 sgrp->nelem++; 194 return (sgrp); 195 } 196 197 int 198 cpc_setgrp_getbufs(cpc_setgrp_t *sgrp, cpc_buf_t ***data1, cpc_buf_t ***data2, 199 cpc_buf_t ***scratch) 200 { 201 if ((uint_t)sgrp->current >= sgrp->nelem) 202 return (-1); 203 204 *data1 = &(sgrp->sets[sgrp->current].data1); 205 *data2 = &(sgrp->sets[sgrp->current].data2); 206 *scratch = &(sgrp->sets[sgrp->current].scratch); 207 208 return (sgrp->sets[sgrp->current].nreqs); 209 } 210 211 cpc_setgrp_t * 212 cpc_setgrp_clone(cpc_setgrp_t *old) 213 { 214 int i; 215 cpc_setgrp_t *new; 216 struct setgrp_elem *newa; 217 218 new = emalloc(sizeof (*new)); 219 newa = emalloc(old->nelem * sizeof (*newa)); 220 221 new->nelem = old->nelem; 222 new->current = old->current; 223 new->cpc = old->cpc; 224 new->sets = newa; 225 new->smt = old->smt; 226 new->has_sysonly_set = old->has_sysonly_set; 227 for (i = 0; i < old->nelem; i++) { 228 if ((newa[i].set = cpc_strtoset(old->cpc, old->sets[i].name, 229 old->smt)) == NULL) { 230 (void) fprintf(stderr, 231 gettext("cpc_setgrp: cpc_strtoset() failed\n")); 232 exit(0); 233 } 234 if ((newa[i].name = strdup(old->sets[i].name)) == NULL) { 235 (void) fprintf(stderr, 236 gettext("cpc_setgrp: no memory available\n")); 237 exit(0); 238 } 239 newa[i].sysonly = old->sets[i].sysonly; 240 newa[i].nreqs = old->sets[i].nreqs; 241 newa[i].data1 = cpc_buf_create(old->cpc, newa[i].set); 242 newa[i].data2 = cpc_buf_create(old->cpc, newa[i].set); 243 newa[i].scratch = cpc_buf_create(old->cpc, newa[i].set); 244 if (newa[i].data1 == NULL || newa[i].data2 == NULL || 245 newa[i].scratch == NULL) { 246 (void) fprintf(stderr, 247 gettext("cpc_setgrp: no memory available\n")); 248 exit(0); 249 } 250 cpc_buf_copy(old->cpc, newa[i].data1, old->sets[i].data1); 251 cpc_buf_copy(old->cpc, newa[i].data2, old->sets[i].data2); 252 cpc_buf_copy(old->cpc, newa[i].scratch, old->sets[i].scratch); 253 } 254 return (new); 255 } 256 257 static void 258 cpc_setgrp_delset(cpc_setgrp_t *sgrp) 259 { 260 int l; 261 262 if ((uint_t)sgrp->current >= sgrp->nelem) 263 sgrp->current = sgrp->nelem - 1; 264 if (sgrp->current < 0) 265 return; 266 free(sgrp->sets[sgrp->current].name); 267 free(sgrp->sets[sgrp->current].hdr); 268 free(sgrp->sets[sgrp->current].picnums); 269 (void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].data1); 270 (void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].data2); 271 (void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].scratch); 272 for (l = sgrp->current; l < sgrp->nelem - 1; l++) 273 sgrp->sets[l] = sgrp->sets[l + 1]; 274 sgrp->nelem--; 275 } 276 277 void 278 cpc_setgrp_free(cpc_setgrp_t *sgrp) 279 { 280 if (sgrp->sets) { 281 while (sgrp->nelem) 282 cpc_setgrp_delset(sgrp); 283 free(sgrp->sets); 284 } 285 free(sgrp); 286 } 287 288 cpc_set_t * 289 cpc_setgrp_getset(cpc_setgrp_t *sgrp) 290 { 291 if ((uint_t)sgrp->current >= sgrp->nelem) 292 return (NULL); 293 return (sgrp->sets[sgrp->current].set); 294 } 295 296 const char * 297 cpc_setgrp_getname(cpc_setgrp_t *sgrp) 298 { 299 if ((uint_t)sgrp->current >= sgrp->nelem) 300 return (NULL); 301 return (sgrp->sets[sgrp->current].name); 302 } 303 304 const char * 305 cpc_setgrp_gethdr(cpc_setgrp_t *sgrp) 306 { 307 if ((uint_t)sgrp->current >= sgrp->nelem) 308 return (NULL); 309 return (sgrp->sets[sgrp->current].hdr); 310 } 311 312 int 313 cpc_setgrp_numsets(cpc_setgrp_t *sgrp) 314 { 315 return (sgrp->nelem); 316 } 317 318 cpc_set_t * 319 cpc_setgrp_nextset(cpc_setgrp_t *sgrp) 320 { 321 if (sgrp->current < 0) 322 return (NULL); 323 324 if (++sgrp->current >= sgrp->nelem) 325 sgrp->current = 0; 326 327 return (cpc_setgrp_getset(sgrp)); 328 } 329 330 /* 331 * Put the setgrp pointer back to the beginning of the set 332 */ 333 void 334 cpc_setgrp_reset(cpc_setgrp_t *sgrp) 335 { 336 if (sgrp->current > 0) 337 sgrp->current = 0; 338 } 339 340 /* 341 * Adds the data from the 'data1' buf into the accum setgrp. 342 */ 343 void 344 cpc_setgrp_accum(cpc_setgrp_t *accum, cpc_setgrp_t *sgrp) 345 { 346 int i; 347 348 cpc_setgrp_reset(accum); 349 cpc_setgrp_reset(sgrp); 350 if (accum->nelem != sgrp->nelem) 351 return; 352 353 for (i = 0; i < sgrp->nelem; i++) { 354 if (accum->sets[i].nreqs != sgrp->sets[i].nreqs) 355 return; 356 cpc_buf_add(sgrp->cpc, accum->sets[i].data1, 357 accum->sets[i].data1, sgrp->sets[i].data1); 358 } 359 } 360 361 /* 362 * Returns 1 if all requests in the current set count only system-mode events. 363 */ 364 int 365 cpc_setgrp_sysonly(cpc_setgrp_t *sgrp) 366 { 367 return ((int)sgrp->sets[sgrp->current].sysonly); 368 } 369 370 /* 371 * Returns 1 if any set in the group is a system-mode-only set. 372 */ 373 int 374 cpc_setgrp_has_sysonly(cpc_setgrp_t *sgrp) 375 { 376 return (sgrp->has_sysonly_set); 377 } 378 379 /* 380 * If we ever fail to get memory, we print an error message and exit. 381 */ 382 static void * 383 emalloc(size_t n) 384 { 385 /* 386 * Several callers of this routine need zero-filled buffers. 387 */ 388 void *p = calloc(1, n); 389 390 if (p == NULL) { 391 (void) fprintf(stderr, 392 gettext("cpc_setgrp: no memory available\n")); 393 exit(0); 394 } 395 396 return (p); 397 } 398