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.
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.
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]
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Routines to capture processor-dependencies in event specification.
30 #include <sys/types.h>
39 #include "libcpc_impl.h"
42 * Event specifications for UltraSPARC performance counters are based
43 * on the content of a getsubopt-like string.
44 * The string should contain something that looks like this:
46 * pic0=<eventspec>,pic1=<eventspec>
50 * pic1=0x4,pic0=Instr_cnt
52 * pic0=Instr_cnt,pic1=Cycle_cnt,nouser,sys
54 * The two events must be named. The names can be ascii or
55 * a decimal, octal or hexadecimal number as parsed by strtol(3C).
57 * By default, user event counting is enabled, system event counting
60 * The routine counts the number of errors encountered while parsing
61 * the string, if no errors are encountered, the event handle is
66 cpc_getusage(int cpuver
)
75 return ("pic0=<event0>,pic1=<event1> "
84 * This private structure is used to build tables that correspond
85 * to the bit patterns in the control registers of the processor.
89 int (*kv_action
)(const char *,
90 const struct keyval
*, int, char *, uint64_t *);
96 picbits(const char *fn
,
97 const struct keyval
*kv
, int cpuver
, char *value
, uint64_t *bits
)
102 regno
= strcmp(kv
->kv_token
, "pic0") == 0 ? 0 : 1;
105 __cpc_error(fn
, gettext("missing '%s' value\n"),
109 if (__cpc_name_to_reg(cpuver
, regno
, value
, &val8
) != 0) {
110 __cpc_error(fn
, gettext("%%pic%d cannot measure "
111 "event '%s' on this cpu\n"), regno
, value
);
114 *bits
|= (((uint64_t)val8
& kv
->kv_mask
) << kv
->kv_shift
);
120 bitclr(const char *fn
,
121 const struct keyval
*kv
, int cpuver
, char *value
, uint64_t *bits
)
124 __cpc_error(fn
, gettext("bad arg to '%s'\n"), kv
->kv_token
);
127 *bits
&= ~(kv
->kv_mask
<< kv
->kv_shift
);
133 bitset(const char *fn
,
134 const struct keyval
*kv
, int cpuver
, char *value
, uint64_t *bits
)
137 __cpc_error(fn
, gettext("bad arg to '%s'\n"), kv
->kv_token
);
140 *bits
|= (kv
->kv_mask
<< kv
->kv_shift
);
145 * This token table must match the keyval tables below.
148 static char * const tokens
[] = {
150 "pic0", /* takes a valid event name */
152 "pic1", /* takes a valid event name */
154 "nouser", /* disables user counts */
156 "sys", /* enables system counts */
160 static const struct keyval us2_keyvals
[] = {
162 CPC_ULTRA2_PCR_PIC0_MASK
, CPC_ULTRA_PCR_PIC0_SHIFT
},
164 CPC_ULTRA2_PCR_PIC1_MASK
, CPC_ULTRA_PCR_PIC1_SHIFT
},
166 UINT64_C(1), CPC_ULTRA_PCR_USR
},
168 UINT64_C(1), CPC_ULTRA_PCR_SYS
},
171 static const struct keyval us3_keyvals
[] = {
173 CPC_ULTRA3_PCR_PIC0_MASK
, CPC_ULTRA_PCR_PIC0_SHIFT
},
175 CPC_ULTRA3_PCR_PIC1_MASK
, CPC_ULTRA_PCR_PIC1_SHIFT
},
177 UINT64_C(1), CPC_ULTRA_PCR_USR
},
179 UINT64_C(1), CPC_ULTRA_PCR_SYS
},
183 #pragma init(__tablecheck)
188 uint_t ntokens
= sizeof (tokens
) / sizeof (tokens
[0]) - 1;
189 uint_t us3_nkeys
= sizeof (us3_keyvals
) / sizeof (us3_keyvals
[0]);
190 uint_t us2_nkeys
= sizeof (us2_keyvals
) / sizeof (us2_keyvals
[0]);
193 assert(ntokens
== us3_nkeys
);
194 for (n
= 0; n
< ntokens
; n
++)
195 assert(strcmp(tokens
[n
], us3_keyvals
[n
].kv_token
) == 0);
196 assert(us3_nkeys
>= us2_nkeys
);
197 for (n
= 0; n
< us2_nkeys
; n
++)
198 assert(strcmp(tokens
[n
], us2_keyvals
[n
].kv_token
) == 0);
204 cpc_strtoevent(int cpuver
, const char *spec
, cpc_event_t
*event
)
206 static const char fn
[] = "strtoevent";
212 const struct keyval
*keyvals
;
218 bzero(event
, sizeof (*event
));
219 switch (event
->ce_cpuver
= cpuver
) {
222 keyvals
= us2_keyvals
;
223 ntokens
= sizeof (us2_keyvals
) / sizeof (us2_keyvals
[0]);
224 bits
= &event
->ce_pcr
;
225 *bits
= UINT64_C(1) << CPC_ULTRA_PCR_USR
;
228 case CPC_ULTRA3_PLUS
:
230 case CPC_ULTRA4_PLUS
:
231 keyvals
= us3_keyvals
;
232 ntokens
= sizeof (us3_keyvals
) / sizeof (us3_keyvals
[0]);
233 bits
= &event
->ce_pcr
;
234 *bits
= UINT64_C(1) << CPC_ULTRA_PCR_USR
;
240 pic
[0] = pic
[1] = NULL
;
242 opts
= strdupa(spec
);
243 while (*opts
!= '\0') {
244 const struct keyval
*kv
;
245 int idx
= getsubopt(&opts
, tokens
, &value
);
247 if (idx
>= 0 && idx
< ntokens
) {
249 if (kv
->kv_action(fn
, kv
, cpuver
, value
, bits
) != 0) {
255 if (pic
[0] != NULL
) {
257 "repeated '%s' token\n",
263 } else if (idx
== D_pic1
) {
264 if (pic
[1] != NULL
) {
266 "repeated '%s' token\n",
273 } else if (idx
== -1) {
275 * The token given wasn't recognized.
276 * See if it was an implicit pic specification..
278 if (pic
[0] == NULL
) {
279 kv
= &keyvals
[D_pic0
];
280 if (kv
->kv_action(fn
,
281 kv
, cpuver
, value
, bits
) != 0) {
286 } else if (pic
[1] == NULL
) {
287 kv
= &keyvals
[D_pic1
];
288 if (kv
->kv_action(fn
,
289 kv
, cpuver
, value
, bits
) != 0) {
296 gettext("bad token '%s'\n"), value
);
302 idx
< sizeof (tokens
) / sizeof (tokens
[0]))
304 gettext("bad token '%s'\n"), tokens
[idx
]);
306 __cpc_error(fn
, gettext("bad token\n"));
312 if (pic
[0] == NULL
|| pic
[1] == NULL
) {
313 __cpc_error(fn
, gettext("two events must be specified\n"));
321 * Return a printable description of the control registers.
323 * This routine should always succeed (notwithstanding heap problems),
324 * but may not be able to correctly decode the registers, if, for
325 * example, a new processor is under test.
327 * The caller is responsible for free(3c)ing the string returned.
331 val8tostr(uint8_t bits
)
333 char buf
[2 + 2 + 1]; /* 0x %2x \0 */
334 (void) snprintf(buf
, sizeof (buf
), "0x%x", bits
);
335 return (strdup(buf
));
339 regtostr(int cpuver
, int regno
, uint8_t bits
)
343 if ((sname
= __cpc_reg_to_name(cpuver
, regno
, bits
)) != NULL
)
344 return (strdup(sname
));
345 return (val8tostr(bits
));
354 unmake_pcr(uint64_t pcr
, int cpuver
, struct xpcr
*xpcr
)
356 const struct keyval
*kv
;
365 case CPC_ULTRA3_PLUS
:
367 case CPC_ULTRA4_PLUS
:
371 xpcr
->pic
[0] = (uint8_t)((pcr
>> kv
[D_pic0
].kv_shift
) &
373 xpcr
->pic
[1] = (uint8_t)((pcr
>> kv
[D_pic1
].kv_shift
) &
375 xpcr
->usr
= (pcr
>> kv
[D_nouser
].kv_shift
) &
376 kv
[D_nouser
].kv_mask
;
377 xpcr
->sys
= (pcr
>> kv
[D_sys
].kv_shift
) &
382 cpc_eventtostr(cpc_event_t
*event
)
388 switch (event
->ce_cpuver
) {
392 case CPC_ULTRA3_PLUS
:
394 case CPC_ULTRA4_PLUS
:
400 unmake_pcr(event
->ce_pcr
, event
->ce_cpuver
, &xpcr
);
401 if ((pic
[0] = regtostr(event
->ce_cpuver
, 0, xpcr
.pic
[0])) == NULL
)
403 if ((pic
[1] = regtostr(event
->ce_cpuver
, 1, xpcr
.pic
[1])) == NULL
) {
408 (void) snprintf(buffer
, sizeof (buffer
), "%s=%s,%s=%s",
409 tokens
[D_pic0
], pic
[0], tokens
[D_pic1
], pic
[1]);
415 (void) strcat(strcat(buffer
, ","), tokens
[D_nouser
]);
417 (void) strcat(strcat(buffer
, ","), tokens
[D_sys
]);
419 return (strdup(buffer
));
423 * Utility operations on events
426 cpc_event_accum(cpc_event_t
*accum
, cpc_event_t
*event
)
428 if (accum
->ce_hrt
< event
->ce_hrt
)
429 accum
->ce_hrt
= event
->ce_hrt
;
430 accum
->ce_tick
+= event
->ce_tick
;
431 accum
->ce_pic
[0] += event
->ce_pic
[0];
432 accum
->ce_pic
[1] += event
->ce_pic
[1];
436 cpc_event_diff(cpc_event_t
*diff
, cpc_event_t
*left
, cpc_event_t
*right
)
438 diff
->ce_hrt
= left
->ce_hrt
;
439 diff
->ce_tick
= left
->ce_tick
- right
->ce_tick
;
440 diff
->ce_pic
[0] = left
->ce_pic
[0] - right
->ce_pic
[0];
441 diff
->ce_pic
[1] = left
->ce_pic
[1] - right
->ce_pic
[1];
445 * Given a cpc_event_t and cpc_bind_event() flags, translate the event into the
448 * Returns NULL on failure.
451 __cpc_eventtoset(cpc_t
*cpc
, cpc_event_t
*event
, int iflags
)
453 cpc_set_t
*set
= NULL
;
457 cpc_attr_t attr
= { "picnum", 0 };
459 switch (event
->ce_cpuver
) {
463 case CPC_ULTRA3_PLUS
:
465 case CPC_ULTRA4_PLUS
:
471 unmake_pcr(event
->ce_pcr
, event
->ce_cpuver
, &xpcr
);
472 if ((pic
[0] = regtostr(event
->ce_cpuver
, 0, xpcr
.pic
[0])) == NULL
)
474 if ((pic
[1] = regtostr(event
->ce_cpuver
, 1, xpcr
.pic
[1])) == NULL
) {
480 flag
|= CPC_COUNT_USER
;
482 flag
|= CPC_COUNT_SYSTEM
;
484 if (iflags
& CPC_BIND_EMT_OVF
)
485 flag
|= CPC_OVF_NOTIFY_EMT
;
487 if ((set
= cpc_set_create(cpc
)) == NULL
)
490 if (cpc_set_add_request(cpc
, set
, pic
[0], event
->ce_pic
[0], flag
,
495 if (cpc_set_add_request(cpc
, set
, pic
[1], event
->ce_pic
[1], flag
,
506 (void) cpc_set_destroy(cpc
, set
);