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 *
cpc_getusage(int cpuver)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
eightbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)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
picbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)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
bitclr(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)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
bitset(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)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
nextpair(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)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
__tablecheck(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
cpc_strtoevent(int cpuver,const char * spec,cpc_event_t * event)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
flagstostr(char * buf,int flag0,int flag1,int defvalue,char * tok)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
masktostr(char * buf,uint8_t bits,char * tok)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 *
val8tostr(uint8_t bits)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 *
regtostr(int cpuver,int regno,uint8_t bits)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
unmake_pes(uint32_t pes,int cpuver,struct xpes * xpes)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
unmake_cesr(uint32_t cesr,int cpuver,struct xcesr * xcesr)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 *
cpc_eventtostr(cpc_event_t * event)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
cpc_event_accum(cpc_event_t * accum,cpc_event_t * event)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
cpc_event_diff(cpc_event_t * diff,cpc_event_t * left,cpc_event_t * right)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 *
__cpc_eventtoset(cpc_t * cpc,cpc_event_t * event,int iflags)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