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