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