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 /* 30 * Routines to capture processor-dependencies in event specification. 31 */ 32 33 #include <sys/types.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <alloca.h> 37 #include <stdlib.h> 38 #include <stdio.h> 39 #include <libintl.h> 40 #include <assert.h> 41 42 #include "libcpc.h" 43 #include "libcpc_impl.h" 44 45 /* 46 * Event specifications for UltraSPARC performance counters are based 47 * on the content of a getsubopt-like string. 48 * The string should contain something that looks like this: 49 * 50 * pic0=<eventspec>,pic1=<eventspec> 51 * [,nouser][,sys] 52 * 53 * For example: 54 * pic1=0x4,pic0=Instr_cnt 55 * or 56 * pic0=Instr_cnt,pic1=Cycle_cnt,nouser,sys 57 * 58 * The two events must be named. The names can be ascii or 59 * a decimal, octal or hexadecimal number as parsed by strtol(3C). 60 * 61 * By default, user event counting is enabled, system event counting 62 * is disabled. 63 * 64 * The routine counts the number of errors encountered while parsing 65 * the string, if no errors are encountered, the event handle is 66 * returned. 67 */ 68 69 const char * 70 cpc_getusage(int cpuver) 71 { 72 switch (cpuver) { 73 case CPC_ULTRA1: 74 case CPC_ULTRA2: 75 case CPC_ULTRA3: 76 case CPC_ULTRA3_PLUS: 77 case CPC_ULTRA3_I: 78 return ("pic0=<event0>,pic1=<event1> " 79 "[,sys] " 80 "[,nouser]"); 81 default: 82 return (NULL); 83 } 84 } 85 86 /* 87 * This private structure is used to build tables that correspond 88 * to the bit patterns in the control registers of the processor. 89 */ 90 struct keyval { 91 char *kv_token; 92 int (*kv_action)(const char *, 93 const struct keyval *, int, char *, uint64_t *); 94 uint64_t kv_mask; 95 int kv_shift; 96 }; 97 98 static int 99 picbits(const char *fn, 100 const struct keyval *kv, int cpuver, char *value, uint64_t *bits) 101 { 102 uint8_t val8; 103 uint_t regno; 104 105 regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1; 106 107 if (value == NULL) { 108 __cpc_error(fn, gettext("missing '%s' value\n"), 109 kv->kv_token); 110 return (-1); 111 } 112 if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) { 113 __cpc_error(fn, gettext("%%pic%d cannot measure " 114 "event '%s' on this cpu\n"), regno, value); 115 return (-1); 116 } 117 *bits |= (((uint64_t)val8 & kv->kv_mask) << kv->kv_shift); 118 return (0); 119 } 120 121 /*ARGSUSED*/ 122 static int 123 bitclr(const char *fn, 124 const struct keyval *kv, int cpuver, char *value, uint64_t *bits) 125 { 126 if (value != NULL) { 127 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 128 return (-1); 129 } 130 *bits &= ~(kv->kv_mask << kv->kv_shift); 131 return (0); 132 } 133 134 /*ARGSUSED*/ 135 static int 136 bitset(const char *fn, 137 const struct keyval *kv, int cpuver, char *value, uint64_t *bits) 138 { 139 if (value != NULL) { 140 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 141 return (-1); 142 } 143 *bits |= (kv->kv_mask << kv->kv_shift); 144 return (0); 145 } 146 147 /* 148 * This token table must match the keyval tables below. 149 */ 150 151 static char * const tokens[] = { 152 #define D_pic0 0 153 "pic0", /* takes a valid event name */ 154 #define D_pic1 1 155 "pic1", /* takes a valid event name */ 156 #define D_nouser 2 157 "nouser", /* disables user counts */ 158 #define D_sys 3 159 "sys", /* enables system counts */ 160 NULL 161 }; 162 163 static const struct keyval us2_keyvals[] = { 164 { "pic0", picbits, 165 CPC_ULTRA2_PCR_PIC0_MASK, CPC_ULTRA_PCR_PIC0_SHIFT }, 166 { "pic1", picbits, 167 CPC_ULTRA2_PCR_PIC1_MASK, CPC_ULTRA_PCR_PIC1_SHIFT }, 168 { "nouser", bitclr, 169 UINT64_C(1), CPC_ULTRA_PCR_USR }, 170 { "sys", bitset, 171 UINT64_C(1), CPC_ULTRA_PCR_SYS }, 172 }; 173 174 static const struct keyval us3_keyvals[] = { 175 { "pic0", picbits, 176 CPC_ULTRA3_PCR_PIC0_MASK, CPC_ULTRA_PCR_PIC0_SHIFT }, 177 { "pic1", picbits, 178 CPC_ULTRA3_PCR_PIC1_MASK, CPC_ULTRA_PCR_PIC1_SHIFT }, 179 { "nouser", bitclr, 180 UINT64_C(1), CPC_ULTRA_PCR_USR }, 181 { "sys", bitset, 182 UINT64_C(1), CPC_ULTRA_PCR_SYS }, 183 }; 184 185 #if !defined(NDEBUG) 186 #pragma init(__tablecheck) 187 188 static void 189 __tablecheck(void) 190 { 191 uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1; 192 uint_t us3_nkeys = sizeof (us3_keyvals) / sizeof (us3_keyvals[0]); 193 uint_t us2_nkeys = sizeof (us2_keyvals) / sizeof (us2_keyvals[0]); 194 uint_t n; 195 196 assert(ntokens == us3_nkeys); 197 for (n = 0; n < ntokens; n++) 198 assert(strcmp(tokens[n], us3_keyvals[n].kv_token) == 0); 199 assert(us3_nkeys >= us2_nkeys); 200 for (n = 0; n < us2_nkeys; n++) 201 assert(strcmp(tokens[n], us2_keyvals[n].kv_token) == 0); 202 } 203 204 #endif /* !NDEBUG */ 205 206 int 207 cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event) 208 { 209 static const char fn[] = "strtoevent"; 210 char *value; 211 char *pic[2]; 212 char *opts; 213 int errcnt = 0; 214 uint_t ntokens; 215 const struct keyval *keyvals; 216 uint64_t *bits; 217 218 if (spec == NULL) 219 return (errcnt = 1); 220 221 bzero(event, sizeof (*event)); 222 switch (event->ce_cpuver = cpuver) { 223 case CPC_ULTRA1: 224 case CPC_ULTRA2: 225 keyvals = us2_keyvals; 226 ntokens = sizeof (us2_keyvals) / sizeof (us2_keyvals[0]); 227 bits = &event->ce_pcr; 228 *bits = UINT64_C(1) << CPC_ULTRA_PCR_USR; 229 break; 230 case CPC_ULTRA3: 231 case CPC_ULTRA3_PLUS: 232 case CPC_ULTRA3_I: 233 keyvals = us3_keyvals; 234 ntokens = sizeof (us3_keyvals) / sizeof (us3_keyvals[0]); 235 bits = &event->ce_pcr; 236 *bits = UINT64_C(1) << CPC_ULTRA_PCR_USR; 237 break; 238 default: 239 return (errcnt = 1); 240 } 241 242 pic[0] = pic[1] = NULL; 243 244 opts = strcpy(alloca(strlen(spec) + 1), spec); 245 while (*opts != '\0') { 246 const struct keyval *kv; 247 int idx = getsubopt(&opts, tokens, &value); 248 249 if (idx >= 0 && idx < ntokens) { 250 kv = &keyvals[idx]; 251 if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) { 252 errcnt++; 253 break; 254 } 255 256 if (idx == D_pic0) { 257 if (pic[0] != NULL) { 258 __cpc_error(fn, 259 "repeated '%s' token\n", 260 tokens[idx]); 261 errcnt++; 262 break; 263 } 264 pic[0] = value; 265 } else if (idx == D_pic1) { 266 if (pic[1] != NULL) { 267 __cpc_error(fn, 268 "repeated '%s' token\n", 269 tokens[idx]); 270 errcnt++; 271 break; 272 } 273 pic[1] = value; 274 } 275 } else if (idx == -1) { 276 /* 277 * The token given wasn't recognized. 278 * See if it was an implicit pic specification.. 279 */ 280 if (pic[0] == NULL) { 281 kv = &keyvals[D_pic0]; 282 if (kv->kv_action(fn, 283 kv, cpuver, value, bits) != 0) { 284 errcnt++; 285 break; 286 } 287 pic[0] = value; 288 } else if (pic[1] == NULL) { 289 kv = &keyvals[D_pic1]; 290 if (kv->kv_action(fn, 291 kv, cpuver, value, bits) != 0) { 292 errcnt++; 293 break; 294 } 295 pic[1] = value; 296 } else { 297 __cpc_error(fn, 298 gettext("bad token '%s'\n"), value); 299 errcnt++; 300 break; 301 } 302 } else { 303 if (idx >= 0 && 304 idx < sizeof (tokens) / sizeof (tokens[0])) 305 __cpc_error(fn, 306 gettext("bad token '%s'\n"), tokens[idx]); 307 else 308 __cpc_error(fn, gettext("bad token\n")); 309 errcnt++; 310 break; 311 } 312 } 313 314 if (pic[0] == NULL || pic[1] == NULL) { 315 __cpc_error(fn, gettext("two events must be specified\n")); 316 errcnt++; 317 } 318 319 return (errcnt); 320 } 321 322 /* 323 * Return a printable description of the control registers. 324 * 325 * This routine should always succeed (notwithstanding heap problems), 326 * but may not be able to correctly decode the registers, if, for 327 * example, a new processor is under test. 328 * 329 * The caller is responsible for free(3c)ing the string returned. 330 */ 331 332 static char * 333 val8tostr(uint8_t bits) 334 { 335 char buf[2 + 2 + 1]; /* 0x %2x \0 */ 336 (void) snprintf(buf, sizeof (buf), "0x%x", bits); 337 return (strdup(buf)); 338 } 339 340 static char * 341 regtostr(int cpuver, int regno, uint8_t bits) 342 { 343 const char *sname; 344 345 if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL) 346 return (strdup(sname)); 347 return (val8tostr(bits)); 348 } 349 350 struct xpcr { 351 uint8_t pic[2]; 352 int usr, sys; 353 }; 354 355 static void 356 unmake_pcr(uint64_t pcr, int cpuver, struct xpcr *xpcr) 357 { 358 const struct keyval *kv; 359 360 switch (cpuver) { 361 case CPC_ULTRA1: 362 case CPC_ULTRA2: 363 default: 364 kv = us2_keyvals; 365 break; 366 case CPC_ULTRA3: 367 case CPC_ULTRA3_PLUS: 368 case CPC_ULTRA3_I: 369 kv = us3_keyvals; 370 break; 371 } 372 xpcr->pic[0] = (uint8_t)((pcr >> kv[D_pic0].kv_shift) & 373 kv[D_pic0].kv_mask); 374 xpcr->pic[1] = (uint8_t)((pcr >> kv[D_pic1].kv_shift) & 375 kv[D_pic1].kv_mask); 376 xpcr->usr = (pcr >> kv[D_nouser].kv_shift) & 377 kv[D_nouser].kv_mask; 378 xpcr->sys = (pcr >> kv[D_sys].kv_shift) & 379 kv[D_sys].kv_mask; 380 } 381 382 char * 383 cpc_eventtostr(cpc_event_t *event) 384 { 385 struct xpcr xpcr; 386 char *pic[2]; 387 char buffer[1024]; 388 389 switch (event->ce_cpuver) { 390 case CPC_ULTRA1: 391 case CPC_ULTRA2: 392 case CPC_ULTRA3: 393 case CPC_ULTRA3_PLUS: 394 case CPC_ULTRA3_I: 395 break; 396 default: 397 return (NULL); 398 } 399 400 unmake_pcr(event->ce_pcr, event->ce_cpuver, &xpcr); 401 if ((pic[0] = regtostr(event->ce_cpuver, 0, xpcr.pic[0])) == NULL) 402 return (NULL); 403 if ((pic[1] = regtostr(event->ce_cpuver, 1, xpcr.pic[1])) == NULL) { 404 free(pic[0]); 405 return (NULL); 406 } 407 408 (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 409 tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 410 411 free(pic[1]); 412 free(pic[0]); 413 414 if (!xpcr.usr) 415 (void) strcat(strcat(buffer, ","), tokens[D_nouser]); 416 if (xpcr.sys) 417 (void) strcat(strcat(buffer, ","), tokens[D_sys]); 418 419 return (strdup(buffer)); 420 } 421 422 /* 423 * Utility operations on events 424 */ 425 void 426 cpc_event_accum(cpc_event_t *accum, cpc_event_t *event) 427 { 428 if (accum->ce_hrt < event->ce_hrt) 429 accum->ce_hrt = event->ce_hrt; 430 accum->ce_tick += event->ce_tick; 431 accum->ce_pic[0] += event->ce_pic[0]; 432 accum->ce_pic[1] += event->ce_pic[1]; 433 } 434 435 void 436 cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right) 437 { 438 diff->ce_hrt = left->ce_hrt; 439 diff->ce_tick = left->ce_tick - right->ce_tick; 440 diff->ce_pic[0] = left->ce_pic[0] - right->ce_pic[0]; 441 diff->ce_pic[1] = left->ce_pic[1] - right->ce_pic[1]; 442 } 443 444 /* 445 * Given a cpc_event_t and cpc_bind_event() flags, translate the event into the 446 * cpc_set_t format. 447 * 448 * Returns NULL on failure. 449 */ 450 cpc_set_t * 451 __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags) 452 { 453 cpc_set_t *set = NULL; 454 struct xpcr xpcr; 455 char *pic[2]; 456 uint32_t flag = 0; 457 cpc_attr_t attr = { "picnum", 0 }; 458 459 switch (event->ce_cpuver) { 460 case CPC_ULTRA1: 461 case CPC_ULTRA2: 462 case CPC_ULTRA3: 463 case CPC_ULTRA3_PLUS: 464 case CPC_ULTRA3_I: 465 break; 466 default: 467 return (NULL); 468 } 469 470 unmake_pcr(event->ce_pcr, event->ce_cpuver, &xpcr); 471 if ((pic[0] = regtostr(event->ce_cpuver, 0, xpcr.pic[0])) == NULL) 472 return (NULL); 473 if ((pic[1] = regtostr(event->ce_cpuver, 1, xpcr.pic[1])) == NULL) { 474 free(pic[0]); 475 return (NULL); 476 } 477 478 if (xpcr.usr) 479 flag |= CPC_COUNT_USER; 480 if (xpcr.sys) 481 flag |= CPC_COUNT_SYSTEM; 482 483 if (iflags & CPC_BIND_EMT_OVF) 484 flag |= CPC_OVF_NOTIFY_EMT; 485 486 if ((set = cpc_set_create(cpc)) == NULL) 487 goto bad; 488 489 if (cpc_set_add_request(cpc, set, pic[0], event->ce_pic[0], flag, 490 1, &attr) != 0) 491 goto bad; 492 493 attr.ca_val = 1; 494 if (cpc_set_add_request(cpc, set, pic[1], event->ce_pic[1], flag, 495 1, &attr) != 1) 496 goto bad; 497 498 free(pic[0]); 499 free(pic[1]); 500 501 return (set); 502 503 bad: 504 if (set != NULL) 505 (void) cpc_set_destroy(cpc, set); 506 free(pic[0]); 507 free(pic[1]); 508 return (NULL); 509 } 510