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) 1999, 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
38 #include "libcpc.h"
39 #include "libcpc_impl.h"
40
41 /*
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:
45 *
46 * pic0=<eventspec>,pic1=<eventspec>
47 * [,nouser][,sys]
48 *
49 * For example:
50 * pic1=0x4,pic0=Instr_cnt
51 * or
52 * pic0=Instr_cnt,pic1=Cycle_cnt,nouser,sys
53 *
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).
56 *
57 * By default, user event counting is enabled, system event counting
58 * is disabled.
59 *
60 * The routine counts the number of errors encountered while parsing
61 * the string, if no errors are encountered, the event handle is
62 * returned.
63 */
64
65 const char *
cpc_getusage(int cpuver)66 cpc_getusage(int cpuver)
67 {
68 switch (cpuver) {
69 case CPC_ULTRA1:
70 case CPC_ULTRA2:
71 case CPC_ULTRA3:
72 case CPC_ULTRA3_PLUS:
73 case CPC_ULTRA3_I:
74 case CPC_ULTRA4_PLUS:
75 return ("pic0=<event0>,pic1=<event1> "
76 "[,sys] "
77 "[,nouser]");
78 default:
79 return (NULL);
80 }
81 }
82
83 /*
84 * This private structure is used to build tables that correspond
85 * to the bit patterns in the control registers of the processor.
86 */
87 struct keyval {
88 char *kv_token;
89 int (*kv_action)(const char *,
90 const struct keyval *, int, char *, uint64_t *);
91 uint64_t kv_mask;
92 int kv_shift;
93 };
94
95 static int
picbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint64_t * bits)96 picbits(const char *fn,
97 const struct keyval *kv, int cpuver, char *value, uint64_t *bits)
98 {
99 uint8_t val8;
100 uint_t regno;
101
102 regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1;
103
104 if (value == NULL) {
105 __cpc_error(fn, gettext("missing '%s' value\n"),
106 kv->kv_token);
107 return (-1);
108 }
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);
112 return (-1);
113 }
114 *bits |= (((uint64_t)val8 & kv->kv_mask) << kv->kv_shift);
115 return (0);
116 }
117
118 /*ARGSUSED*/
119 static int
bitclr(const char * fn,const struct keyval * kv,int cpuver,char * value,uint64_t * bits)120 bitclr(const char *fn,
121 const struct keyval *kv, int cpuver, char *value, uint64_t *bits)
122 {
123 if (value != NULL) {
124 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
125 return (-1);
126 }
127 *bits &= ~(kv->kv_mask << kv->kv_shift);
128 return (0);
129 }
130
131 /*ARGSUSED*/
132 static int
bitset(const char * fn,const struct keyval * kv,int cpuver,char * value,uint64_t * bits)133 bitset(const char *fn,
134 const struct keyval *kv, int cpuver, char *value, uint64_t *bits)
135 {
136 if (value != NULL) {
137 __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
138 return (-1);
139 }
140 *bits |= (kv->kv_mask << kv->kv_shift);
141 return (0);
142 }
143
144 /*
145 * This token table must match the keyval tables below.
146 */
147
148 static char * const tokens[] = {
149 #define D_pic0 0
150 "pic0", /* takes a valid event name */
151 #define D_pic1 1
152 "pic1", /* takes a valid event name */
153 #define D_nouser 2
154 "nouser", /* disables user counts */
155 #define D_sys 3
156 "sys", /* enables system counts */
157 NULL
158 };
159
160 static const struct keyval us2_keyvals[] = {
161 { "pic0", picbits,
162 CPC_ULTRA2_PCR_PIC0_MASK, CPC_ULTRA_PCR_PIC0_SHIFT },
163 { "pic1", picbits,
164 CPC_ULTRA2_PCR_PIC1_MASK, CPC_ULTRA_PCR_PIC1_SHIFT },
165 { "nouser", bitclr,
166 UINT64_C(1), CPC_ULTRA_PCR_USR },
167 { "sys", bitset,
168 UINT64_C(1), CPC_ULTRA_PCR_SYS },
169 };
170
171 static const struct keyval us3_keyvals[] = {
172 { "pic0", picbits,
173 CPC_ULTRA3_PCR_PIC0_MASK, CPC_ULTRA_PCR_PIC0_SHIFT },
174 { "pic1", picbits,
175 CPC_ULTRA3_PCR_PIC1_MASK, CPC_ULTRA_PCR_PIC1_SHIFT },
176 { "nouser", bitclr,
177 UINT64_C(1), CPC_ULTRA_PCR_USR },
178 { "sys", bitset,
179 UINT64_C(1), CPC_ULTRA_PCR_SYS },
180 };
181
182 #if !defined(NDEBUG)
183 #pragma init(__tablecheck)
184
185 static void
__tablecheck(void)186 __tablecheck(void)
187 {
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]);
191 uint_t n;
192
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);
199 }
200
201 #endif /* !NDEBUG */
202
203 int
cpc_strtoevent(int cpuver,const char * spec,cpc_event_t * event)204 cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event)
205 {
206 static const char fn[] = "strtoevent";
207 char *value;
208 char *pic[2];
209 char *opts;
210 int errcnt = 0;
211 uint_t ntokens;
212 const struct keyval *keyvals;
213 uint64_t *bits;
214
215 if (spec == NULL)
216 return (errcnt = 1);
217
218 bzero(event, sizeof (*event));
219 switch (event->ce_cpuver = cpuver) {
220 case CPC_ULTRA1:
221 case CPC_ULTRA2:
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;
226 break;
227 case CPC_ULTRA3:
228 case CPC_ULTRA3_PLUS:
229 case CPC_ULTRA3_I:
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;
235 break;
236 default:
237 return (errcnt = 1);
238 }
239
240 pic[0] = pic[1] = NULL;
241
242 opts = strdupa(spec);
243 while (*opts != '\0') {
244 const struct keyval *kv;
245 int idx = getsubopt(&opts, tokens, &value);
246
247 if (idx >= 0 && idx < ntokens) {
248 kv = &keyvals[idx];
249 if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) {
250 errcnt++;
251 break;
252 }
253
254 if (idx == D_pic0) {
255 if (pic[0] != NULL) {
256 __cpc_error(fn,
257 "repeated '%s' token\n",
258 tokens[idx]);
259 errcnt++;
260 break;
261 }
262 pic[0] = value;
263 } else if (idx == D_pic1) {
264 if (pic[1] != NULL) {
265 __cpc_error(fn,
266 "repeated '%s' token\n",
267 tokens[idx]);
268 errcnt++;
269 break;
270 }
271 pic[1] = value;
272 }
273 } else if (idx == -1) {
274 /*
275 * The token given wasn't recognized.
276 * See if it was an implicit pic specification..
277 */
278 if (pic[0] == NULL) {
279 kv = &keyvals[D_pic0];
280 if (kv->kv_action(fn,
281 kv, cpuver, value, bits) != 0) {
282 errcnt++;
283 break;
284 }
285 pic[0] = value;
286 } else if (pic[1] == NULL) {
287 kv = &keyvals[D_pic1];
288 if (kv->kv_action(fn,
289 kv, cpuver, value, bits) != 0) {
290 errcnt++;
291 break;
292 }
293 pic[1] = value;
294 } else {
295 __cpc_error(fn,
296 gettext("bad token '%s'\n"), value);
297 errcnt++;
298 break;
299 }
300 } else {
301 if (idx >= 0 &&
302 idx < sizeof (tokens) / sizeof (tokens[0]))
303 __cpc_error(fn,
304 gettext("bad token '%s'\n"), tokens[idx]);
305 else
306 __cpc_error(fn, gettext("bad token\n"));
307 errcnt++;
308 break;
309 }
310 }
311
312 if (pic[0] == NULL || pic[1] == NULL) {
313 __cpc_error(fn, gettext("two events must be specified\n"));
314 errcnt++;
315 }
316
317 return (errcnt);
318 }
319
320 /*
321 * Return a printable description of the control registers.
322 *
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.
326 *
327 * The caller is responsible for free(3c)ing the string returned.
328 */
329
330 static char *
val8tostr(uint8_t bits)331 val8tostr(uint8_t bits)
332 {
333 char buf[2 + 2 + 1]; /* 0x %2x \0 */
334 (void) snprintf(buf, sizeof (buf), "0x%x", bits);
335 return (strdup(buf));
336 }
337
338 static char *
regtostr(int cpuver,int regno,uint8_t bits)339 regtostr(int cpuver, int regno, uint8_t bits)
340 {
341 const char *sname;
342
343 if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL)
344 return (strdup(sname));
345 return (val8tostr(bits));
346 }
347
348 struct xpcr {
349 uint8_t pic[2];
350 int usr, sys;
351 };
352
353 static void
unmake_pcr(uint64_t pcr,int cpuver,struct xpcr * xpcr)354 unmake_pcr(uint64_t pcr, int cpuver, struct xpcr *xpcr)
355 {
356 const struct keyval *kv;
357
358 switch (cpuver) {
359 case CPC_ULTRA1:
360 case CPC_ULTRA2:
361 default:
362 kv = us2_keyvals;
363 break;
364 case CPC_ULTRA3:
365 case CPC_ULTRA3_PLUS:
366 case CPC_ULTRA3_I:
367 case CPC_ULTRA4_PLUS:
368 kv = us3_keyvals;
369 break;
370 }
371 xpcr->pic[0] = (uint8_t)((pcr >> kv[D_pic0].kv_shift) &
372 kv[D_pic0].kv_mask);
373 xpcr->pic[1] = (uint8_t)((pcr >> kv[D_pic1].kv_shift) &
374 kv[D_pic1].kv_mask);
375 xpcr->usr = (pcr >> kv[D_nouser].kv_shift) &
376 kv[D_nouser].kv_mask;
377 xpcr->sys = (pcr >> kv[D_sys].kv_shift) &
378 kv[D_sys].kv_mask;
379 }
380
381 char *
cpc_eventtostr(cpc_event_t * event)382 cpc_eventtostr(cpc_event_t *event)
383 {
384 struct xpcr xpcr;
385 char *pic[2];
386 char buffer[1024];
387
388 switch (event->ce_cpuver) {
389 case CPC_ULTRA1:
390 case CPC_ULTRA2:
391 case CPC_ULTRA3:
392 case CPC_ULTRA3_PLUS:
393 case CPC_ULTRA3_I:
394 case CPC_ULTRA4_PLUS:
395 break;
396 default:
397 return (NULL);
398 }
399
400 unmake_pcr(event->ce_pcr, event->ce_cpuver, &xpcr);
401 if ((pic[0] = regtostr(event->ce_cpuver, 0, xpcr.pic[0])) == NULL)
402 return (NULL);
403 if ((pic[1] = regtostr(event->ce_cpuver, 1, xpcr.pic[1])) == NULL) {
404 free(pic[0]);
405 return (NULL);
406 }
407
408 (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s",
409 tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]);
410
411 free(pic[1]);
412 free(pic[0]);
413
414 if (!xpcr.usr)
415 (void) strcat(strcat(buffer, ","), tokens[D_nouser]);
416 if (xpcr.sys)
417 (void) strcat(strcat(buffer, ","), tokens[D_sys]);
418
419 return (strdup(buffer));
420 }
421
422 /*
423 * Utility operations on events
424 */
425 void
cpc_event_accum(cpc_event_t * accum,cpc_event_t * event)426 cpc_event_accum(cpc_event_t *accum, cpc_event_t *event)
427 {
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];
433 }
434
435 void
cpc_event_diff(cpc_event_t * diff,cpc_event_t * left,cpc_event_t * right)436 cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right)
437 {
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];
442 }
443
444 /*
445 * Given a cpc_event_t and cpc_bind_event() flags, translate the event into the
446 * cpc_set_t format.
447 *
448 * Returns NULL on failure.
449 */
450 cpc_set_t *
__cpc_eventtoset(cpc_t * cpc,cpc_event_t * event,int iflags)451 __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags)
452 {
453 cpc_set_t *set = NULL;
454 struct xpcr xpcr;
455 char *pic[2];
456 uint32_t flag = 0;
457 cpc_attr_t attr = { "picnum", 0 };
458
459 switch (event->ce_cpuver) {
460 case CPC_ULTRA1:
461 case CPC_ULTRA2:
462 case CPC_ULTRA3:
463 case CPC_ULTRA3_PLUS:
464 case CPC_ULTRA3_I:
465 case CPC_ULTRA4_PLUS:
466 break;
467 default:
468 return (NULL);
469 }
470
471 unmake_pcr(event->ce_pcr, event->ce_cpuver, &xpcr);
472 if ((pic[0] = regtostr(event->ce_cpuver, 0, xpcr.pic[0])) == NULL)
473 return (NULL);
474 if ((pic[1] = regtostr(event->ce_cpuver, 1, xpcr.pic[1])) == NULL) {
475 free(pic[0]);
476 return (NULL);
477 }
478
479 if (xpcr.usr)
480 flag |= CPC_COUNT_USER;
481 if (xpcr.sys)
482 flag |= CPC_COUNT_SYSTEM;
483
484 if (iflags & CPC_BIND_EMT_OVF)
485 flag |= CPC_OVF_NOTIFY_EMT;
486
487 if ((set = cpc_set_create(cpc)) == NULL)
488 goto bad;
489
490 if (cpc_set_add_request(cpc, set, pic[0], event->ce_pic[0], flag,
491 1, &attr) != 0)
492 goto bad;
493
494 attr.ca_val = 1;
495 if (cpc_set_add_request(cpc, set, pic[1], event->ce_pic[1], flag,
496 1, &attr) != 1)
497 goto bad;
498
499 free(pic[0]);
500 free(pic[1]);
501
502 return (set);
503
504 bad:
505 if (set != NULL)
506 (void) cpc_set_destroy(cpc, set);
507 free(pic[0]);
508 free(pic[1]);
509 return (NULL);
510 }
511