Home | History | Annotate | Download | only in i386
      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