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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Routines to capture processor-dependencies in event specification. 28 */ 29 30 #include <sys/types.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <libintl.h> 36 #include <assert.h> 37 38 #include "libcpc.h" 39 #include "libcpc_impl.h" 40 41 /* 42 * Event specifications for UltraSPARC performance counters are based 43 * on the content of a getsubopt-like string. 44 * The string should contain something that looks like this: 45 * 46 * pic0=<eventspec>,pic1=<eventspec> 47 * [,nouser][,sys] 48 * 49 * For example: 50 * pic1=0x4,pic0=Instr_cnt 51 * or 52 * pic0=Instr_cnt,pic1=Cycle_cnt,nouser,sys 53 * 54 * The two events must be named. The names can be ascii or 55 * a decimal, octal or hexadecimal number as parsed by strtol(3C). 56 * 57 * By default, user event counting is enabled, system event counting 58 * is disabled. 59 * 60 * The routine counts the number of errors encountered while parsing 61 * the string, if no errors are encountered, the event handle is 62 * returned. 63 */ 64 65 const char * 66 cpc_getusage(int cpuver) 67 { 68 switch (cpuver) { 69 case CPC_ULTRA1: 70 case CPC_ULTRA2: 71 case CPC_ULTRA3: 72 case CPC_ULTRA3_PLUS: 73 case CPC_ULTRA3_I: 74 case CPC_ULTRA4_PLUS: 75 return ("pic0=<event0>,pic1=<event1> " 76 "[,sys] " 77 "[,nouser]"); 78 default: 79 return (NULL); 80 } 81 } 82 83 /* 84 * This private structure is used to build tables that correspond 85 * to the bit patterns in the control registers of the processor. 86 */ 87 struct keyval { 88 char *kv_token; 89 int (*kv_action)(const char *, 90 const struct keyval *, int, char *, uint64_t *); 91 uint64_t kv_mask; 92 int kv_shift; 93 }; 94 95 static int 96 picbits(const char *fn, 97 const struct keyval *kv, int cpuver, char *value, uint64_t *bits) 98 { 99 uint8_t val8; 100 uint_t regno; 101 102 regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1; 103 104 if (value == NULL) { 105 __cpc_error(fn, gettext("missing '%s' value\n"), 106 kv->kv_token); 107 return (-1); 108 } 109 if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) { 110 __cpc_error(fn, gettext("%%pic%d cannot measure " 111 "event '%s' on this cpu\n"), regno, value); 112 return (-1); 113 } 114 *bits |= (((uint64_t)val8 & kv->kv_mask) << kv->kv_shift); 115 return (0); 116 } 117 118 /*ARGSUSED*/ 119 static int 120 bitclr(const char *fn, 121 const struct keyval *kv, int cpuver, char *value, uint64_t *bits) 122 { 123 if (value != NULL) { 124 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 125 return (-1); 126 } 127 *bits &= ~(kv->kv_mask << kv->kv_shift); 128 return (0); 129 } 130 131 /*ARGSUSED*/ 132 static int 133 bitset(const char *fn, 134 const struct keyval *kv, int cpuver, char *value, uint64_t *bits) 135 { 136 if (value != NULL) { 137 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 138 return (-1); 139 } 140 *bits |= (kv->kv_mask << kv->kv_shift); 141 return (0); 142 } 143 144 /* 145 * This token table must match the keyval tables below. 146 */ 147 148 static char * const tokens[] = { 149 #define D_pic0 0 150 "pic0", /* takes a valid event name */ 151 #define D_pic1 1 152 "pic1", /* takes a valid event name */ 153 #define D_nouser 2 154 "nouser", /* disables user counts */ 155 #define D_sys 3 156 "sys", /* enables system counts */ 157 NULL 158 }; 159 160 static const struct keyval us2_keyvals[] = { 161 { "pic0", picbits, 162 CPC_ULTRA2_PCR_PIC0_MASK, CPC_ULTRA_PCR_PIC0_SHIFT }, 163 { "pic1", picbits, 164 CPC_ULTRA2_PCR_PIC1_MASK, CPC_ULTRA_PCR_PIC1_SHIFT }, 165 { "nouser", bitclr, 166 UINT64_C(1), CPC_ULTRA_PCR_USR }, 167 { "sys", bitset, 168 UINT64_C(1), CPC_ULTRA_PCR_SYS }, 169 }; 170 171 static const struct keyval us3_keyvals[] = { 172 { "pic0", picbits, 173 CPC_ULTRA3_PCR_PIC0_MASK, CPC_ULTRA_PCR_PIC0_SHIFT }, 174 { "pic1", picbits, 175 CPC_ULTRA3_PCR_PIC1_MASK, CPC_ULTRA_PCR_PIC1_SHIFT }, 176 { "nouser", bitclr, 177 UINT64_C(1), CPC_ULTRA_PCR_USR }, 178 { "sys", bitset, 179 UINT64_C(1), CPC_ULTRA_PCR_SYS }, 180 }; 181 182 #if !defined(NDEBUG) 183 #pragma init(__tablecheck) 184 185 static void 186 __tablecheck(void) 187 { 188 uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1; 189 uint_t us3_nkeys = sizeof (us3_keyvals) / sizeof (us3_keyvals[0]); 190 uint_t us2_nkeys = sizeof (us2_keyvals) / sizeof (us2_keyvals[0]); 191 uint_t n; 192 193 assert(ntokens == us3_nkeys); 194 for (n = 0; n < ntokens; n++) 195 assert(strcmp(tokens[n], us3_keyvals[n].kv_token) == 0); 196 assert(us3_nkeys >= us2_nkeys); 197 for (n = 0; n < us2_nkeys; n++) 198 assert(strcmp(tokens[n], us2_keyvals[n].kv_token) == 0); 199 } 200 201 #endif /* !NDEBUG */ 202 203 int 204 cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event) 205 { 206 static const char fn[] = "strtoevent"; 207 char *value; 208 char *pic[2]; 209 char *opts; 210 int errcnt = 0; 211 uint_t ntokens; 212 const struct keyval *keyvals; 213 uint64_t *bits; 214 215 if (spec == NULL) 216 return (errcnt = 1); 217 218 bzero(event, sizeof (*event)); 219 switch (event->ce_cpuver = cpuver) { 220 case CPC_ULTRA1: 221 case CPC_ULTRA2: 222 keyvals = us2_keyvals; 223 ntokens = sizeof (us2_keyvals) / sizeof (us2_keyvals[0]); 224 bits = &event->ce_pcr; 225 *bits = UINT64_C(1) << CPC_ULTRA_PCR_USR; 226 break; 227 case CPC_ULTRA3: 228 case CPC_ULTRA3_PLUS: 229 case CPC_ULTRA3_I: 230 case CPC_ULTRA4_PLUS: 231 keyvals = us3_keyvals; 232 ntokens = sizeof (us3_keyvals) / sizeof (us3_keyvals[0]); 233 bits = &event->ce_pcr; 234 *bits = UINT64_C(1) << CPC_ULTRA_PCR_USR; 235 break; 236 default: 237 return (errcnt = 1); 238 } 239 240 pic[0] = pic[1] = NULL; 241 242 opts = strdupa(spec); 243 while (*opts != '\0') { 244 const struct keyval *kv; 245 int idx = getsubopt(&opts, tokens, &value); 246 247 if (idx >= 0 && idx < ntokens) { 248 kv = &keyvals[idx]; 249 if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) { 250 errcnt++; 251 break; 252 } 253 254 if (idx == D_pic0) { 255 if (pic[0] != NULL) { 256 __cpc_error(fn, 257 "repeated '%s' token\n", 258 tokens[idx]); 259 errcnt++; 260 break; 261 } 262 pic[0] = value; 263 } else if (idx == D_pic1) { 264 if (pic[1] != NULL) { 265 __cpc_error(fn, 266 "repeated '%s' token\n", 267 tokens[idx]); 268 errcnt++; 269 break; 270 } 271 pic[1] = value; 272 } 273 } else if (idx == -1) { 274 /* 275 * The token given wasn't recognized. 276 * See if it was an implicit pic specification.. 277 */ 278 if (pic[0] == NULL) { 279 kv = &keyvals[D_pic0]; 280 if (kv->kv_action(fn, 281 kv, cpuver, value, bits) != 0) { 282 errcnt++; 283 break; 284 } 285 pic[0] = value; 286 } else if (pic[1] == NULL) { 287 kv = &keyvals[D_pic1]; 288 if (kv->kv_action(fn, 289 kv, cpuver, value, bits) != 0) { 290 errcnt++; 291 break; 292 } 293 pic[1] = value; 294 } else { 295 __cpc_error(fn, 296 gettext("bad token '%s'\n"), value); 297 errcnt++; 298 break; 299 } 300 } else { 301 if (idx >= 0 && 302 idx < sizeof (tokens) / sizeof (tokens[0])) 303 __cpc_error(fn, 304 gettext("bad token '%s'\n"), tokens[idx]); 305 else 306 __cpc_error(fn, gettext("bad token\n")); 307 errcnt++; 308 break; 309 } 310 } 311 312 if (pic[0] == NULL || pic[1] == NULL) { 313 __cpc_error(fn, gettext("two events must be specified\n")); 314 errcnt++; 315 } 316 317 return (errcnt); 318 } 319 320 /* 321 * Return a printable description of the control registers. 322 * 323 * This routine should always succeed (notwithstanding heap problems), 324 * but may not be able to correctly decode the registers, if, for 325 * example, a new processor is under test. 326 * 327 * The caller is responsible for free(3c)ing the string returned. 328 */ 329 330 static char * 331 val8tostr(uint8_t bits) 332 { 333 char buf[2 + 2 + 1]; /* 0x %2x \0 */ 334 (void) snprintf(buf, sizeof (buf), "0x%x", bits); 335 return (strdup(buf)); 336 } 337 338 static char * 339 regtostr(int cpuver, int regno, uint8_t bits) 340 { 341 const char *sname; 342 343 if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL) 344 return (strdup(sname)); 345 return (val8tostr(bits)); 346 } 347 348 struct xpcr { 349 uint8_t pic[2]; 350 int usr, sys; 351 }; 352 353 static void 354 unmake_pcr(uint64_t pcr, int cpuver, struct xpcr *xpcr) 355 { 356 const struct keyval *kv; 357 358 switch (cpuver) { 359 case CPC_ULTRA1: 360 case CPC_ULTRA2: 361 default: 362 kv = us2_keyvals; 363 break; 364 case CPC_ULTRA3: 365 case CPC_ULTRA3_PLUS: 366 case CPC_ULTRA3_I: 367 case CPC_ULTRA4_PLUS: 368 kv = us3_keyvals; 369 break; 370 } 371 xpcr->pic[0] = (uint8_t)((pcr >> kv[D_pic0].kv_shift) & 372 kv[D_pic0].kv_mask); 373 xpcr->pic[1] = (uint8_t)((pcr >> kv[D_pic1].kv_shift) & 374 kv[D_pic1].kv_mask); 375 xpcr->usr = (pcr >> kv[D_nouser].kv_shift) & 376 kv[D_nouser].kv_mask; 377 xpcr->sys = (pcr >> kv[D_sys].kv_shift) & 378 kv[D_sys].kv_mask; 379 } 380 381 char * 382 cpc_eventtostr(cpc_event_t *event) 383 { 384 struct xpcr xpcr; 385 char *pic[2]; 386 char buffer[1024]; 387 388 switch (event->ce_cpuver) { 389 case CPC_ULTRA1: 390 case CPC_ULTRA2: 391 case CPC_ULTRA3: 392 case CPC_ULTRA3_PLUS: 393 case CPC_ULTRA3_I: 394 case CPC_ULTRA4_PLUS: 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 case CPC_ULTRA4_PLUS: 466 break; 467 default: 468 return (NULL); 469 } 470 471 unmake_pcr(event->ce_pcr, event->ce_cpuver, &xpcr); 472 if ((pic[0] = regtostr(event->ce_cpuver, 0, xpcr.pic[0])) == NULL) 473 return (NULL); 474 if ((pic[1] = regtostr(event->ce_cpuver, 1, xpcr.pic[1])) == NULL) { 475 free(pic[0]); 476 return (NULL); 477 } 478 479 if (xpcr.usr) 480 flag |= CPC_COUNT_USER; 481 if (xpcr.sys) 482 flag |= CPC_COUNT_SYSTEM; 483 484 if (iflags & CPC_BIND_EMT_OVF) 485 flag |= CPC_OVF_NOTIFY_EMT; 486 487 if ((set = cpc_set_create(cpc)) == NULL) 488 goto bad; 489 490 if (cpc_set_add_request(cpc, set, pic[0], event->ce_pic[0], flag, 491 1, &attr) != 0) 492 goto bad; 493 494 attr.ca_val = 1; 495 if (cpc_set_add_request(cpc, set, pic[1], event->ce_pic[1], flag, 496 1, &attr) != 1) 497 goto bad; 498 499 free(pic[0]); 500 free(pic[1]); 501 502 return (set); 503 504 bad: 505 if (set != NULL) 506 (void) cpc_set_destroy(cpc, set); 507 free(pic[0]); 508 free(pic[1]); 509 return (NULL); 510 } 511