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