xref: /titanic_52/usr/src/lib/libcpc/sparc/event_ultra.c (revision 84ab085a13f931bc78e7415e7ce921dbaa14fcb3)
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 
42 #include "libcpc.h"
43 #include "libcpc_impl.h"
44 
45 /*
46  * Event specifications for UltraSPARC performance counters are based
47  * on the content of a getsubopt-like string.
48  * The string should contain something that looks like this:
49  *
50  *	pic0=<eventspec>,pic1=<eventspec>
51  *		[,nouser][,sys]
52  *
53  * For example:
54  *	pic1=0x4,pic0=Instr_cnt
55  * or
56  *	pic0=Instr_cnt,pic1=Cycle_cnt,nouser,sys
57  *
58  * The two events must be named.  The names can be ascii or
59  * a decimal, octal or hexadecimal number as parsed by strtol(3C).
60  *
61  * By default, user event counting is enabled, system event counting
62  * is disabled.
63  *
64  * The routine counts the number of errors encountered while parsing
65  * the string, if no errors are encountered, the event handle is
66  * returned.
67  */
68 
69 const char *
70 cpc_getusage(int cpuver)
71 {
72 	switch (cpuver) {
73 	case CPC_ULTRA1:
74 	case CPC_ULTRA2:
75 	case CPC_ULTRA3:
76 	case CPC_ULTRA3_PLUS:
77 	case CPC_ULTRA3_I:
78 		return ("pic0=<event0>,pic1=<event1> "
79 		    "[,sys] "
80 		    "[,nouser]");
81 	default:
82 		return (NULL);
83 	}
84 }
85 
86 /*
87  * This private structure is used to build tables that correspond
88  * to the bit patterns in the control registers of the processor.
89  */
90 struct keyval {
91 	char *kv_token;
92 	int (*kv_action)(const char *,
93 	    const struct keyval *, int, char *, uint64_t *);
94 	uint64_t kv_mask;
95 	int kv_shift;
96 };
97 
98 static int
99 picbits(const char *fn,
100     const struct keyval *kv, int cpuver, char *value, uint64_t *bits)
101 {
102 	uint8_t val8;
103 	uint_t regno;
104 
105 	regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1;
106 
107 	if (value == NULL) {
108 		__cpc_error(fn, gettext("missing '%s' value\n"),
109 		    kv->kv_token);
110 		return (-1);
111 	}
112 	if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) {
113 		__cpc_error(fn, gettext("%%pic%d cannot measure "
114 		    "event '%s' on this cpu\n"), regno, value);
115 		return (-1);
116 	}
117 	*bits |= (((uint64_t)val8 & kv->kv_mask) << kv->kv_shift);
118 	return (0);
119 }
120 
121 /*ARGSUSED*/
122 static int
123 bitclr(const char *fn,
124     const struct keyval *kv, int cpuver, char *value, uint64_t *bits)
125 {
126 	if (value != NULL) {
127 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
128 		return (-1);
129 	}
130 	*bits &= ~(kv->kv_mask << kv->kv_shift);
131 	return (0);
132 }
133 
134 /*ARGSUSED*/
135 static int
136 bitset(const char *fn,
137     const struct keyval *kv, int cpuver, char *value, uint64_t *bits)
138 {
139 	if (value != NULL) {
140 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
141 		return (-1);
142 	}
143 	*bits |= (kv->kv_mask << kv->kv_shift);
144 	return (0);
145 }
146 
147 /*
148  * This token table must match the keyval tables below.
149  */
150 
151 static char * const tokens[] = {
152 #define	D_pic0		0
153 	"pic0",			/* takes a valid event name */
154 #define	D_pic1		1
155 	"pic1",			/* takes a valid event name */
156 #define	D_nouser	2
157 	"nouser",		/* disables user counts */
158 #define	D_sys		3
159 	"sys",			/* enables system counts */
160 	NULL
161 };
162 
163 static const struct keyval us2_keyvals[] = {
164 	{ "pic0",   picbits,
165 		CPC_ULTRA2_PCR_PIC0_MASK,	CPC_ULTRA_PCR_PIC0_SHIFT },
166 	{ "pic1",   picbits,
167 		CPC_ULTRA2_PCR_PIC1_MASK,	CPC_ULTRA_PCR_PIC1_SHIFT },
168 	{ "nouser", bitclr,
169 		UINT64_C(1),			CPC_ULTRA_PCR_USR },
170 	{ "sys",    bitset,
171 		UINT64_C(1),			CPC_ULTRA_PCR_SYS },
172 };
173 
174 static const struct keyval us3_keyvals[] = {
175 	{ "pic0",   picbits,
176 		CPC_ULTRA3_PCR_PIC0_MASK,	CPC_ULTRA_PCR_PIC0_SHIFT },
177 	{ "pic1",   picbits,
178 		CPC_ULTRA3_PCR_PIC1_MASK,	CPC_ULTRA_PCR_PIC1_SHIFT },
179 	{ "nouser", bitclr,
180 		UINT64_C(1),			CPC_ULTRA_PCR_USR },
181 	{ "sys",    bitset,
182 		UINT64_C(1),			CPC_ULTRA_PCR_SYS },
183 };
184 
185 #if !defined(NDEBUG)
186 #pragma	init(__tablecheck)
187 
188 static void
189 __tablecheck(void)
190 {
191 	uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1;
192 	uint_t us3_nkeys = sizeof (us3_keyvals) / sizeof (us3_keyvals[0]);
193 	uint_t us2_nkeys = sizeof (us2_keyvals) / sizeof (us2_keyvals[0]);
194 	uint_t n;
195 
196 	assert(ntokens == us3_nkeys);
197 	for (n = 0; n < ntokens; n++)
198 		assert(strcmp(tokens[n], us3_keyvals[n].kv_token) == 0);
199 	assert(us3_nkeys >= us2_nkeys);
200 	for (n = 0; n < us2_nkeys; n++)
201 		assert(strcmp(tokens[n], us2_keyvals[n].kv_token) == 0);
202 }
203 
204 #endif	/* !NDEBUG */
205 
206 int
207 cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event)
208 {
209 	static const char fn[] = "strtoevent";
210 	char *value;
211 	char *pic[2];
212 	char *opts;
213 	int errcnt = 0;
214 	uint_t ntokens;
215 	const struct keyval *keyvals;
216 	uint64_t *bits;
217 
218 	if (spec == NULL)
219 		return (errcnt = 1);
220 
221 	bzero(event, sizeof (*event));
222 	switch (event->ce_cpuver = cpuver) {
223 	case CPC_ULTRA1:
224 	case CPC_ULTRA2:
225 		keyvals = us2_keyvals;
226 		ntokens = sizeof (us2_keyvals) / sizeof (us2_keyvals[0]);
227 		bits = &event->ce_pcr;
228 		*bits = UINT64_C(1) << CPC_ULTRA_PCR_USR;
229 		break;
230 	case CPC_ULTRA3:
231 	case CPC_ULTRA3_PLUS:
232 	case CPC_ULTRA3_I:
233 		keyvals = us3_keyvals;
234 		ntokens = sizeof (us3_keyvals) / sizeof	(us3_keyvals[0]);
235 		bits = &event->ce_pcr;
236 		*bits = UINT64_C(1) << CPC_ULTRA_PCR_USR;
237 		break;
238 	default:
239 		return (errcnt = 1);
240 	}
241 
242 	pic[0] = pic[1] = NULL;
243 
244 	opts = strcpy(alloca(strlen(spec) + 1), spec);
245 	while (*opts != '\0') {
246 		const struct keyval *kv;
247 		int idx = getsubopt(&opts, tokens, &value);
248 
249 		if (idx >= 0 && idx < ntokens) {
250 			kv = &keyvals[idx];
251 			if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) {
252 				errcnt++;
253 				break;
254 			}
255 
256 			if (idx == D_pic0) {
257 				if (pic[0] != NULL) {
258 					__cpc_error(fn,
259 					    "repeated '%s' token\n",
260 					    tokens[idx]);
261 					errcnt++;
262 					break;
263 				}
264 				pic[0] = value;
265 			} else if (idx == D_pic1) {
266 				if (pic[1] != NULL) {
267 					__cpc_error(fn,
268 					    "repeated '%s' token\n",
269 					    tokens[idx]);
270 					errcnt++;
271 					break;
272 				}
273 				pic[1] = value;
274 			}
275 		} else if (idx == -1) {
276 			/*
277 			 * The token given wasn't recognized.
278 			 * See if it was an implicit pic specification..
279 			 */
280 			if (pic[0] == NULL) {
281 				kv = &keyvals[D_pic0];
282 				if (kv->kv_action(fn,
283 				    kv, cpuver, value, bits) != 0) {
284 					errcnt++;
285 					break;
286 				}
287 				pic[0] = value;
288 			} else if (pic[1] == NULL) {
289 				kv = &keyvals[D_pic1];
290 				if (kv->kv_action(fn,
291 				    kv, cpuver, value, bits) != 0) {
292 					errcnt++;
293 					break;
294 				}
295 				pic[1] = value;
296 			} else {
297 				__cpc_error(fn,
298 				    gettext("bad token '%s'\n"), value);
299 				errcnt++;
300 				break;
301 			}
302 		} else {
303 			if (idx >= 0 &&
304 			    idx < sizeof (tokens) / sizeof (tokens[0]))
305 				__cpc_error(fn,
306 				    gettext("bad token '%s'\n"), tokens[idx]);
307 			else
308 				__cpc_error(fn, gettext("bad token\n"));
309 			errcnt++;
310 			break;
311 		}
312 	}
313 
314 	if (pic[0] == NULL || pic[1] == NULL) {
315 		__cpc_error(fn, gettext("two events must be specified\n"));
316 		errcnt++;
317 	}
318 
319 	return (errcnt);
320 }
321 
322 /*
323  * Return a printable description of the control registers.
324  *
325  * This routine should always succeed (notwithstanding heap problems),
326  * but may not be able to correctly decode the registers, if, for
327  * example, a new processor is under test.
328  *
329  * The caller is responsible for free(3c)ing the string returned.
330  */
331 
332 static char *
333 val8tostr(uint8_t bits)
334 {
335 	char buf[2 + 2 + 1];	/* 0x %2x \0 */
336 	(void) snprintf(buf, sizeof (buf), "0x%x", bits);
337 	return (strdup(buf));
338 }
339 
340 static char *
341 regtostr(int cpuver, int regno, uint8_t bits)
342 {
343 	const char *sname;
344 
345 	if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL)
346 		return (strdup(sname));
347 	return (val8tostr(bits));
348 }
349 
350 struct xpcr {
351 	uint8_t pic[2];
352 	int usr, sys;
353 };
354 
355 static void
356 unmake_pcr(uint64_t pcr, int cpuver, struct xpcr *xpcr)
357 {
358 	const struct keyval *kv;
359 
360 	switch (cpuver) {
361 	case CPC_ULTRA1:
362 	case CPC_ULTRA2:
363 	default:
364 		kv = us2_keyvals;
365 		break;
366 	case CPC_ULTRA3:
367 	case CPC_ULTRA3_PLUS:
368 	case CPC_ULTRA3_I:
369 		kv = us3_keyvals;
370 		break;
371 	}
372 	xpcr->pic[0] = (uint8_t)((pcr >> kv[D_pic0].kv_shift) &
373 	    kv[D_pic0].kv_mask);
374 	xpcr->pic[1] = (uint8_t)((pcr >> kv[D_pic1].kv_shift) &
375 	    kv[D_pic1].kv_mask);
376 	xpcr->usr = (pcr >> kv[D_nouser].kv_shift) &
377 	    kv[D_nouser].kv_mask;
378 	xpcr->sys = (pcr >> kv[D_sys].kv_shift) &
379 	    kv[D_sys].kv_mask;
380 }
381 
382 char *
383 cpc_eventtostr(cpc_event_t *event)
384 {
385 	struct xpcr xpcr;
386 	char *pic[2];
387 	char buffer[1024];
388 
389 	switch (event->ce_cpuver) {
390 	case CPC_ULTRA1:
391 	case CPC_ULTRA2:
392 	case CPC_ULTRA3:
393 	case CPC_ULTRA3_PLUS:
394 	case CPC_ULTRA3_I:
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
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
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 *
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 		break;
466 	default:
467 		return (NULL);
468 	}
469 
470 	unmake_pcr(event->ce_pcr, event->ce_cpuver, &xpcr);
471 	if ((pic[0] = regtostr(event->ce_cpuver, 0, xpcr.pic[0])) == NULL)
472 		return (NULL);
473 	if ((pic[1] = regtostr(event->ce_cpuver, 1, xpcr.pic[1])) == NULL) {
474 		free(pic[0]);
475 		return (NULL);
476 	}
477 
478 	if (xpcr.usr)
479 		flag |= CPC_COUNT_USER;
480 	if (xpcr.sys)
481 		flag |= CPC_COUNT_SYSTEM;
482 
483 	if (iflags & CPC_BIND_EMT_OVF)
484 		flag |= CPC_OVF_NOTIFY_EMT;
485 
486 	if ((set = cpc_set_create(cpc)) == NULL)
487 		goto bad;
488 
489 	if (cpc_set_add_request(cpc, set, pic[0], event->ce_pic[0], flag,
490 	    1, &attr) != 0)
491 		goto bad;
492 
493 	attr.ca_val = 1;
494 	if (cpc_set_add_request(cpc, set, pic[1], event->ce_pic[1], flag,
495 	    1, &attr) != 1)
496 		goto bad;
497 
498 	free(pic[0]);
499 	free(pic[1]);
500 
501 	return (set);
502 
503 bad:
504 	if (set != NULL)
505 		(void) cpc_set_destroy(cpc, set);
506 	free(pic[0]);
507 	free(pic[1]);
508 	return (NULL);
509 }
510