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 #include <errno.h> 42 43 #include "libcpc.h" 44 #include "libcpc_impl.h" 45 46 /* 47 * Event specifications for Pentium performance counters are based 48 * on the content of a getsubopt-like string. 49 * The string should contain something that looks like this: 50 * 51 * pic0=<eventspec>,pic1=<eventspec> 52 * [,cmask0=<maskspec>][,cmask1=<maskspec>] 53 * [,umask0=<maskspec>][,umask1=<maskspec>] 54 * [,inv[0|1]][,noedge[0|1]] 55 * [,sys[0|1]][,nouser[0|1]] 56 * 57 * For example: 58 * pic0=data_mem_refs,pic1=l2_ld,sys 59 * or 60 * pic0=l2_ld,pic1=bus_drdy_clocks,umask1=0x20,nouser1 61 * 62 * By default, user event counting is enabled, system event counting 63 * is disabled. 64 * 65 * Note that Pentium and Pentium Pro have different event specifications. 66 * 67 * The two events must be named. The names can be ascii or 68 * a decimal, octal or hexadecimal number as parsed by strtol(3C). 69 * 70 * The routine counts the number of errors encountered while parsing 71 * the string, if no errors are encountered, the event handle is 72 * returned. 73 */ 74 75 const char * 76 cpc_getusage(int cpuver) 77 { 78 switch (cpuver) { 79 case CPC_PENTIUM_PRO_MMX: 80 case CPC_PENTIUM_PRO: 81 return ("pic0=<event0>,pic1=<event1> " 82 "[,sys[0|1]] " 83 "[,nouser[0|1]] " 84 "[,noedge[0|1]] " 85 "[,pc[0|1]] " 86 "[,int[0|1]] " 87 "[,inv[0|1]] " 88 "[,cmask[0|1]=<maskspec>] " 89 "[,umask[0|1]=<maskspec>] "); 90 case CPC_PENTIUM_MMX: 91 case CPC_PENTIUM: 92 return ("pic0=<event0>,pic1=<event1> " 93 "[,sys[0|1]] " 94 "[,nouser[0|1]] " 95 "[,noedge[0|1]] " 96 "[,pc[0|1]]"); 97 default: 98 return (NULL); 99 } 100 } 101 102 struct keyval { 103 char *kv_token; 104 int (*kv_action)(const char *, 105 const struct keyval *, int, char *, uint32_t *); 106 uint_t kv_regno; 107 uint32_t kv_mask; 108 int kv_shift; 109 }; 110 111 /*ARGSUSED*/ 112 static int 113 eightbits(const char *fn, 114 const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 115 { 116 char *eptr = NULL; 117 long l; 118 119 if (value == NULL) { 120 __cpc_error(fn, gettext("missing '%s' value\n"), 121 kv->kv_token); 122 return (-1); 123 } 124 l = strtol(value, &eptr, 0); 125 if (value == eptr || l < 0 || l > UINT8_MAX) { 126 __cpc_error(fn, gettext("bad '%s' value\n"), kv->kv_token); 127 return (-1); 128 } 129 bits[kv->kv_regno] |= ((uint8_t)l & kv->kv_mask) << kv->kv_shift; 130 return (0); 131 } 132 133 static int 134 picbits(const char *fn, 135 const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 136 { 137 uint8_t val8; 138 uint_t regno; 139 140 regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1; 141 142 if (value == NULL) { 143 __cpc_error(fn, gettext("missing '%s' value\n"), 144 kv->kv_token); 145 return (-1); 146 } 147 148 if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) { 149 switch (cpuver) { 150 case CPC_PENTIUM_PRO_MMX: 151 case CPC_PENTIUM_PRO: 152 assert(kv->kv_regno == regno); 153 __cpc_error(fn, gettext( 154 "PerfCtr%d cannot measure '%s' on this cpu\n"), 155 regno, value); 156 break; 157 case CPC_PENTIUM_MMX: 158 case CPC_PENTIUM: 159 assert(kv->kv_regno == 0); 160 __cpc_error(fn, gettext( 161 "CTR%d cannot measure '%s' on this cpu\n"), 162 regno, value); 163 break; 164 } 165 return (-1); 166 } 167 bits[kv->kv_regno] |= (val8 & kv->kv_mask) << kv->kv_shift; 168 return (0); 169 } 170 171 /*ARGSUSED2*/ 172 static int 173 bitclr(const char *fn, 174 const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 175 { 176 if (value != NULL) { 177 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 178 return (-1); 179 } 180 bits[kv->kv_regno] &= ~(kv->kv_mask << kv->kv_shift); 181 return (0); 182 } 183 184 /*ARGSUSED2*/ 185 static int 186 bitset(const char *fn, 187 const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 188 { 189 if (value != NULL) { 190 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 191 return (-1); 192 } 193 bits[kv->kv_regno] |= (kv->kv_mask << kv->kv_shift); 194 return (0); 195 } 196 197 static int 198 nextpair(const char *fn, 199 const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 200 { 201 int rv; 202 203 if (value != NULL) { 204 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 205 return (-1); 206 } 207 kv++; 208 if ((rv = kv->kv_action(fn, kv, cpuver, value, bits)) != 0) 209 return (rv); 210 kv++; 211 return (kv->kv_action(fn, kv, cpuver, value, bits)); 212 } 213 214 /* 215 * This token table must match the keyval tables below. 216 */ 217 218 static char * const tokens[] = { 219 #define D_pic0 0 220 "pic0", /* takes a valid event name */ 221 #define D_pic1 1 222 "pic1", /* takes a valid event name */ 223 #define D_nouser 2 224 "nouser", /* disables user counts */ 225 #define D_nouser0 3 226 "nouser0", 227 #define D_nouser1 4 228 "nouser1", 229 #define D_sys 5 230 "sys", /* enables system counts */ 231 #define D_sys0 6 232 "sys0", 233 #define D_sys1 7 234 "sys1", 235 #define D_noedge 8 236 "noedge", /* disable edge detect */ 237 #define D_noedge0 9 238 "noedge0", 239 #define D_noedge1 10 240 "noedge1", 241 #define D_pc 11 242 "pc", /* sets pin control high */ 243 #define D_pc0 12 244 "pc0", 245 #define D_pc1 13 246 "pc1", 247 248 /* 249 * These additional keywords are for Pentium Pro / Pentium II machines. 250 */ 251 #define D_int 14 252 "int", /* enable interrupt on counter overflow */ 253 #define D_int0 15 254 "int0", 255 #define D_int1 16 256 "int1", 257 #define D_inv 17 258 "inv", /* invert cmask comparison */ 259 #define D_inv0 18 260 "inv0", 261 #define D_inv1 19 262 "inv1", 263 #define D_umask0 20 264 "umask0", /* PerfCtr0 unit mask */ 265 #define D_umask1 21 266 "umask1", /* PerfCtr1 unit mask */ 267 #define D_cmask0 22 268 "cmask0", /* PerfCtr0 counter mask */ 269 #define D_cmask1 23 270 "cmask1", /* PerfCtr1 counter mask */ 271 NULL 272 }; 273 274 static const struct keyval p6_keyvals[] = { 275 { "pic0", picbits, 0, 276 CPC_P6_PES_PIC0_MASK, 0 }, 277 { "pic1", picbits, 1, 278 CPC_P6_PES_PIC1_MASK, 0 }, 279 { "nouser", nextpair }, 280 { "nouser0", bitclr, 0, 281 UINT32_C(1), CPC_P6_PES_USR }, 282 { "nouser1", bitclr, 1, 283 UINT32_C(1), CPC_P6_PES_USR }, 284 { "sys", nextpair }, 285 { "sys0", bitset, 0, 286 UINT32_C(1), CPC_P6_PES_OS }, 287 { "sys1", bitset, 1, 288 UINT32_C(1), CPC_P6_PES_OS }, 289 { "noedge", nextpair }, 290 { "noedge0", bitclr, 0, 291 UINT32_C(1), CPC_P6_PES_E }, 292 { "noedge1", bitclr, 1, 293 UINT32_C(1), CPC_P6_PES_E }, 294 { "pc", nextpair }, 295 { "pc0", bitset, 0, 296 UINT32_C(1), CPC_P6_PES_PC }, 297 { "pc1", bitset, 1, 298 UINT32_C(1), CPC_P6_PES_PC }, 299 { "int", nextpair }, 300 { "int0", bitset, 0, 301 UINT32_C(1), CPC_P6_PES_INT }, 302 { "int1", bitset, 1, 303 UINT32_C(1), CPC_P6_PES_INT }, 304 { "inv", nextpair }, 305 { "inv0", bitset, 0, 306 UINT32_C(1), CPC_P6_PES_INV }, 307 { "inv1", bitset, 1, 308 UINT32_C(1), CPC_P6_PES_INV }, 309 { "umask0", eightbits, 0, 310 CPC_P6_PES_UMASK_MASK, CPC_P6_PES_UMASK_SHIFT }, 311 { "umask1", eightbits, 1, 312 CPC_P6_PES_UMASK_MASK, CPC_P6_PES_UMASK_SHIFT }, 313 { "cmask0", eightbits, 0, 314 CPC_P6_PES_CMASK_MASK, CPC_P6_PES_CMASK_SHIFT }, 315 { "cmask1", eightbits, 1, 316 CPC_P6_PES_CMASK_MASK, CPC_P6_PES_CMASK_SHIFT }, 317 }; 318 319 /* 320 * Note that this table -must- be an identically indexed 321 * subset of p6_keyvals. 322 */ 323 static const struct keyval p5_keyvals[] = { 324 { "pic0", picbits, 0, 325 CPC_P5_CESR_ES0_MASK, CPC_P5_CESR_ES0_SHIFT }, 326 { "pic1", picbits, 0, 327 CPC_P5_CESR_ES1_MASK, CPC_P5_CESR_ES1_SHIFT }, 328 { "nouser", nextpair }, 329 { "nouser0", bitclr, 0, 330 UINT32_C(1), CPC_P5_CESR_USR0 }, 331 { "nouser1", bitclr, 0, 332 UINT32_C(1), CPC_P5_CESR_USR1 }, 333 { "sys", nextpair }, 334 { "sys0", bitset, 0, 335 UINT32_C(1), CPC_P5_CESR_OS0 }, 336 { "sys1", bitset, 0, 337 UINT32_C(1), CPC_P5_CESR_OS1 }, 338 { "noedge", nextpair }, 339 { "noedge0", bitset, 0, 340 UINT32_C(1), CPC_P5_CESR_CLK0 }, 341 { "noedge1", bitset, 0, 342 UINT32_C(1), CPC_P5_CESR_CLK1 }, 343 { "pc", nextpair }, 344 { "pc0", bitset, 0, 345 UINT32_C(1), CPC_P5_CESR_PC0 }, 346 { "pc1", bitset, 0, 347 UINT32_C(1), CPC_P5_CESR_PC1 }, 348 }; 349 350 #if !defined(NDEBUG) 351 #pragma init(__tablecheck) 352 353 static void 354 __tablecheck(void) 355 { 356 uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1; 357 uint_t p6_nkeys = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]); 358 uint_t p5_nkeys = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]); 359 uint_t n; 360 361 assert(ntokens == p6_nkeys); 362 for (n = 0; n < ntokens; n++) 363 assert(strcmp(tokens[n], p6_keyvals[n].kv_token) == 0); 364 assert(p6_nkeys >= p5_nkeys); 365 for (n = 0; n < p5_nkeys; n++) 366 assert(strcmp(tokens[n], p5_keyvals[n].kv_token) == 0); 367 } 368 369 #endif /* !NDEBUG */ 370 371 int 372 cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event) 373 { 374 static const char fn[] = "strtoevent"; 375 char *value; 376 char *pic[2]; 377 char *opts; 378 int errcnt = 0; 379 uint_t ntokens; 380 const struct keyval *keyvals; 381 uint32_t *bits; 382 383 if (spec == NULL) 384 return (errcnt = 1); 385 386 bzero(event, sizeof (*event)); 387 switch (event->ce_cpuver = cpuver) { 388 case CPC_PENTIUM_PRO_MMX: 389 case CPC_PENTIUM_PRO: 390 keyvals = p6_keyvals; 391 ntokens = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]); 392 bits = &event->ce_pes[0]; 393 bits[0] = bits[1] = 394 (1u << CPC_P6_PES_USR) | (1u << CPC_P6_PES_E); 395 break; 396 case CPC_PENTIUM_MMX: 397 case CPC_PENTIUM: 398 keyvals = p5_keyvals; 399 ntokens = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]); 400 bits = &event->ce_cesr; 401 bits[0] = 402 (1u << CPC_P5_CESR_USR0) | (1u << CPC_P5_CESR_USR1); 403 break; 404 default: 405 return (errcnt = 1); 406 } 407 408 pic[0] = pic[1] = NULL; 409 410 opts = strcpy(alloca(strlen(spec) + 1), spec); 411 while (*opts != '\0') { 412 const struct keyval *kv; 413 int idx = getsubopt(&opts, tokens, &value); 414 415 if (idx >= 0 && idx < ntokens) { 416 kv = &keyvals[idx]; 417 if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) { 418 errcnt++; 419 break; 420 } 421 422 if (idx == D_pic0) { 423 if (pic[0] != NULL) { 424 __cpc_error(fn, 425 "repeated '%s' token\n", 426 tokens[idx]); 427 errcnt++; 428 break; 429 } 430 pic[0] = value; 431 } else if (idx == D_pic1) { 432 if (pic[1] != NULL) { 433 __cpc_error(fn, 434 "repeated '%s' token\n", 435 tokens[idx]); 436 errcnt++; 437 break; 438 } 439 pic[1] = value; 440 } 441 } else if (idx == -1) { 442 /* 443 * The token given wasn't recognized. 444 * See if it was an implicit pic specification.. 445 */ 446 if (pic[0] == NULL) { 447 kv = &keyvals[D_pic0]; 448 if (kv->kv_action(fn, 449 kv, cpuver, value, bits) != 0) { 450 errcnt++; 451 break; 452 } 453 pic[0] = value; 454 } else if (pic[1] == NULL) { 455 kv = &keyvals[D_pic1]; 456 if (kv->kv_action(fn, 457 kv, cpuver, value, bits) != 0) { 458 errcnt++; 459 break; 460 } 461 pic[1] = value; 462 } else { 463 __cpc_error(fn, 464 gettext("bad token '%s'\n"), value); 465 errcnt++; 466 break; 467 } 468 } else { 469 if (idx >= 0 && 470 idx < sizeof (tokens) / sizeof (tokens[0])) 471 __cpc_error(fn, 472 gettext("bad token '%s'\n"), tokens[idx]); 473 else 474 __cpc_error(fn, gettext("bad token\n")); 475 errcnt++; 476 break; 477 } 478 } 479 480 if (pic[0] == NULL || pic[1] == NULL) { 481 __cpc_error(fn, gettext("two events must be specified\n")); 482 errcnt++; 483 } 484 485 return (errcnt); 486 } 487 488 /* 489 * Return a printable description of the control registers. 490 * 491 * This routine should always succeed (notwithstanding heap problems), 492 * but may not be able to correctly decode the registers, if, for 493 * example, a new processor is under test. 494 * 495 * The caller is responsible for free(3c)ing the string returned. 496 */ 497 498 static void 499 flagstostr(char *buf, int flag0, int flag1, int defvalue, char *tok) 500 { 501 buf += strlen(buf); 502 if (flag0 != defvalue) { 503 if (flag1 != defvalue) 504 (void) sprintf(buf, ",%s", tok); 505 else 506 (void) sprintf(buf, ",%s0", tok); 507 } else { 508 if (flag1 != defvalue) 509 (void) sprintf(buf, ",%s1", tok); 510 } 511 } 512 513 static void 514 masktostr(char *buf, uint8_t bits, char *tok) 515 { 516 if (bits != 0) { 517 buf += strlen(buf); 518 (void) sprintf(buf, ",%s=0x%x", tok, bits); 519 } 520 } 521 522 static char * 523 val8tostr(uint8_t bits) 524 { 525 char buf[2 + 2 + 1]; /* 0x %2x \0 */ 526 (void) snprintf(buf, sizeof (buf), "0x%x", bits); 527 return (strdup(buf)); 528 } 529 530 static char * 531 regtostr(int cpuver, int regno, uint8_t bits) 532 { 533 const char *sname; 534 535 if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL) 536 return (strdup(sname)); 537 return (val8tostr(bits)); 538 } 539 540 struct xpes { 541 uint8_t cmask, umask, evsel; 542 int usr, sys, edge, inv, irupt, pc; 543 }; 544 545 /*ARGSUSED1*/ 546 static void 547 unmake_pes(uint32_t pes, int cpuver, struct xpes *xpes) 548 { 549 xpes->cmask = (uint8_t)(pes >> CPC_P6_PES_CMASK_SHIFT); 550 xpes->pc = (pes >> CPC_P6_PES_PC) & 1u; 551 xpes->inv = (pes >> CPC_P6_PES_INV) & 1u; 552 xpes->irupt = (pes >> CPC_P6_PES_INT) & 1u; 553 xpes->edge = (pes >> CPC_P6_PES_E) & 1u; 554 xpes->sys = (pes >> CPC_P6_PES_OS) & 1u; 555 xpes->usr = (pes >> CPC_P6_PES_USR) & 1u; 556 xpes->umask = (uint8_t)(pes >> CPC_P6_PES_UMASK_SHIFT); 557 xpes->evsel = (uint8_t)pes; 558 } 559 560 struct xcesr { 561 uint8_t evsel[2]; 562 int usr[2], sys[2], clk[2], pc[2]; 563 }; 564 565 /*ARGSUSED1*/ 566 static void 567 unmake_cesr(uint32_t cesr, int cpuver, struct xcesr *xcesr) 568 { 569 xcesr->evsel[0] = (cesr >> CPC_P5_CESR_ES0_SHIFT) & 570 CPC_P5_CESR_ES0_MASK; 571 xcesr->evsel[1] = (cesr >> CPC_P5_CESR_ES1_SHIFT) & 572 CPC_P5_CESR_ES1_MASK; 573 xcesr->usr[0] = (cesr >> CPC_P5_CESR_USR0) & 1u; 574 xcesr->usr[1] = (cesr >> CPC_P5_CESR_USR1) & 1u; 575 xcesr->sys[0] = (cesr >> CPC_P5_CESR_OS0) & 1u; 576 xcesr->sys[1] = (cesr >> CPC_P5_CESR_OS1) & 1u; 577 xcesr->clk[0] = (cesr >> CPC_P5_CESR_CLK0) & 1u; 578 xcesr->clk[1] = (cesr >> CPC_P5_CESR_CLK1) & 1u; 579 xcesr->pc[0] = (cesr >> CPC_P5_CESR_PC0) & 1u; 580 xcesr->pc[1] = (cesr >> CPC_P5_CESR_PC1) & 1u; 581 /* 582 * If usr and sys are both disabled, the counter is disabled. 583 */ 584 if (xcesr->usr[0] == 0 && xcesr->sys[0] == 0) 585 xcesr->clk[0] = 0; 586 if (xcesr->usr[1] == 0 && xcesr->sys[1] == 0) 587 xcesr->clk[1] = 0; 588 } 589 590 char * 591 cpc_eventtostr(cpc_event_t *event) 592 { 593 char *pic[2]; 594 char buffer[1024]; 595 int cpuver = event->ce_cpuver; 596 597 switch (cpuver) { 598 case CPC_PENTIUM_PRO_MMX: 599 case CPC_PENTIUM_PRO: 600 { 601 struct xpes xpes[2]; 602 603 unmake_pes(event->ce_pes[0], cpuver, &xpes[0]); 604 if ((pic[0] = regtostr(cpuver, 0, xpes[0].evsel)) == NULL) 605 return (NULL); 606 607 unmake_pes(event->ce_pes[1], cpuver, &xpes[1]); 608 if ((pic[1] = regtostr(cpuver, 1, xpes[1].evsel)) == NULL) { 609 free(pic[0]); 610 return (NULL); 611 } 612 (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 613 tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 614 free(pic[1]); 615 free(pic[0]); 616 masktostr(buffer, xpes[0].cmask, tokens[D_cmask0]); 617 masktostr(buffer, xpes[1].cmask, tokens[D_cmask1]); 618 masktostr(buffer, xpes[0].umask, tokens[D_umask0]); 619 masktostr(buffer, xpes[1].umask, tokens[D_umask1]); 620 flagstostr(buffer, 621 xpes[0].usr, xpes[1].usr, 1, tokens[D_nouser]); 622 flagstostr(buffer, 623 xpes[0].sys, xpes[1].sys, 0, tokens[D_sys]); 624 flagstostr(buffer, 625 xpes[0].edge, xpes[1].edge, 1, tokens[D_noedge]); 626 flagstostr(buffer, 627 xpes[0].irupt, xpes[1].irupt, 0, tokens[D_int]); 628 flagstostr(buffer, 629 xpes[0].inv, xpes[1].inv, 0, tokens[D_inv]); 630 flagstostr(buffer, 631 xpes[0].pc, xpes[1].pc, 0, tokens[D_pc]); 632 } break; 633 case CPC_PENTIUM_MMX: 634 case CPC_PENTIUM: 635 { 636 struct xcesr xcesr; 637 638 unmake_cesr(event->ce_cesr, cpuver, &xcesr); 639 if ((pic[0] = regtostr(cpuver, 0, xcesr.evsel[0])) == NULL) 640 return (NULL); 641 if ((pic[1] = regtostr(cpuver, 1, xcesr.evsel[1])) == NULL) { 642 free(pic[0]); 643 return (NULL); 644 } 645 (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 646 tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 647 free(pic[1]); 648 free(pic[0]); 649 flagstostr(buffer, 650 xcesr.usr[0], xcesr.usr[1], 1, tokens[D_nouser]); 651 flagstostr(buffer, 652 xcesr.sys[0], xcesr.sys[1], 0, tokens[D_sys]); 653 flagstostr(buffer, 654 xcesr.clk[0], xcesr.clk[1], 0, tokens[D_noedge]); 655 flagstostr(buffer, 656 xcesr.pc[0], xcesr.pc[1], 0, tokens[D_pc]); 657 } break; 658 default: 659 return (NULL); 660 } 661 return (strdup(buffer)); 662 } 663 664 /* 665 * Utility operations on events 666 */ 667 void 668 cpc_event_accum(cpc_event_t *accum, cpc_event_t *event) 669 { 670 if (accum->ce_hrt < event->ce_hrt) 671 accum->ce_hrt = event->ce_hrt; 672 accum->ce_tsc += event->ce_tsc; 673 accum->ce_pic[0] += event->ce_pic[0]; 674 accum->ce_pic[1] += event->ce_pic[1]; 675 } 676 677 void 678 cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right) 679 { 680 diff->ce_hrt = left->ce_hrt; 681 diff->ce_tsc = left->ce_tsc - right->ce_tsc; 682 diff->ce_pic[0] = left->ce_pic[0] - right->ce_pic[0]; 683 diff->ce_pic[1] = left->ce_pic[1] - right->ce_pic[1]; 684 } 685 686 /* 687 * Given a cpc_event_t and cpc_bind_event() flags, 688 * translate the cpc_event_t into the cpc_set_t format. 689 * 690 * Returns NULL on failure. 691 */ 692 cpc_set_t * 693 __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags) 694 { 695 cpc_set_t *set; 696 int cpuver = event->ce_cpuver; 697 char *pic[2]; 698 int flags[2] = { 0, 0 }; 699 int i; 700 int j; 701 int nattrs; 702 cpc_attr_t *attr; 703 int intr; 704 705 if ((set = cpc_set_create(cpc)) == NULL) { 706 return (NULL); 707 } 708 709 if (iflags & CPC_BIND_EMT_OVF) 710 flags[0] = flags[1] = CPC_OVF_NOTIFY_EMT; 711 712 switch (cpuver) { 713 case CPC_PENTIUM_PRO_MMX: 714 case CPC_PENTIUM_PRO: 715 { 716 struct xpes xpes[2]; 717 718 for (i = 0; i < 2; i++) { 719 intr = 0; 720 nattrs = j = 1; 721 unmake_pes(event->ce_pes[i], cpuver, &xpes[i]); 722 if ((pic[i] = regtostr(cpuver, i, 723 xpes[i].evsel)) == NULL) { 724 (void) cpc_set_destroy(cpc, set); 725 return (NULL); 726 } 727 if (xpes[i].usr == 1) 728 flags[i] |= CPC_COUNT_USER; 729 if (xpes[i].sys == 1) 730 flags[i] |= CPC_COUNT_SYSTEM; 731 if (xpes[i].irupt == 1) { 732 nattrs++; 733 intr = 1; 734 } 735 736 if (xpes[i].cmask) 737 nattrs++; 738 if (xpes[i].umask) 739 nattrs++; 740 if (xpes[i].inv) 741 nattrs++; 742 if (xpes[i].pc) 743 nattrs++; 744 if (xpes[i].edge == 0) 745 nattrs++; 746 747 if ((attr = (cpc_attr_t *)malloc(nattrs * 748 sizeof (cpc_attr_t))) == NULL) { 749 (void) cpc_set_destroy(cpc, set); 750 errno = ENOMEM; 751 return (NULL); 752 } 753 754 /* 755 * Ensure that pic[0] in the cpc_event_t is bound to 756 * physical pic0. 757 */ 758 attr[0].ca_name = "picnum"; 759 attr[0].ca_val = i; 760 761 if (intr) { 762 attr[j].ca_name = "int"; 763 attr[j].ca_val = 1; 764 j++; 765 } 766 if (xpes[i].cmask) { 767 attr[j].ca_name = "cmask"; 768 attr[j].ca_val = xpes[i].cmask; 769 j++; 770 } 771 if (xpes[i].umask) { 772 attr[j].ca_name = "umask"; 773 attr[j].ca_val = xpes[i].umask; 774 j++; 775 } 776 if (xpes[i].inv) { 777 attr[j].ca_name = "inv"; 778 attr[j].ca_val = 1; 779 j++; 780 } 781 if (xpes[i].pc) { 782 attr[j].ca_name = "pc"; 783 attr[j].ca_val = 1; 784 j++; 785 } 786 if (xpes[i].edge == 0) { 787 attr[j].ca_name = "noedge"; 788 attr[j].ca_val = 1; 789 j++; 790 } 791 792 if (cpc_set_add_request(cpc, set, pic[i], 793 event->ce_pic[i], flags[i], nattrs, attr) == -1) { 794 (void) cpc_set_destroy(cpc, set); 795 free(pic[i]); 796 free(attr); 797 return (NULL); 798 } 799 free(pic[i]); 800 free(attr); 801 } 802 } 803 break; 804 case CPC_PENTIUM_MMX: 805 case CPC_PENTIUM: 806 { 807 struct xcesr xcesr; 808 unmake_cesr(event->ce_cesr, cpuver, &xcesr); 809 810 for (i = 0; i < 2; i++) { 811 nattrs = j = 1; 812 813 if ((pic[i] = regtostr(cpuver, i, xcesr.evsel[i])) 814 == NULL) { 815 (void) cpc_set_destroy(cpc, set); 816 return (NULL); 817 } 818 819 if (xcesr.usr[i] == 1) 820 flags[i] |= CPC_COUNT_USER; 821 if (xcesr.sys[i] == 1) 822 flags[i] |= CPC_COUNT_SYSTEM; 823 if (xcesr.clk[i] == 1) 824 nattrs++; 825 if (xcesr.pc[i] == 1) 826 nattrs++; 827 828 if ((attr = (cpc_attr_t *)malloc(nattrs * 829 sizeof (cpc_attr_t))) == NULL) { 830 (void) cpc_set_destroy(cpc, set); 831 errno = ENOMEM; 832 return (NULL); 833 } 834 835 /* 836 * Ensure that pic[0] in the cpc_event_t is bound to 837 * physical pic0. 838 */ 839 attr[0].ca_name = "picnum"; 840 attr[0].ca_val = i; 841 842 if (xcesr.clk[i] == 1) { 843 attr[j].ca_name = "noedge"; 844 attr[j].ca_val = 1; 845 j++; 846 } 847 848 if (xcesr.pc[i] == 1) { 849 attr[j].ca_name = "pc"; 850 attr[j].ca_val = 1; 851 j++; 852 } 853 854 if (cpc_set_add_request(cpc, set, pic[i], 855 event->ce_pic[i], flags[i], nattrs, attr) == -1) { 856 (void) cpc_set_destroy(cpc, set); 857 free(pic[i]); 858 free(attr); 859 return (NULL); 860 } 861 862 free(pic[i]); 863 free(attr); 864 } 865 } 866 break; 867 default: 868 (void) cpc_set_destroy(cpc, set); 869 return (NULL); 870 } 871 872 return (set); 873 } 874