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