xref: /titanic_41/usr/src/cmd/cpc/common/caps.c (revision c7a079a873b863c236656bd0db7b2cf390841b4d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*c7a079a8SJonathan Haslam  * Common Development and Distribution License (the "License").
6*c7a079a8SJonathan Haslam  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*c7a079a8SJonathan Haslam  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #define	 __EXTENSIONS__	/* header bug! strtok_r is overly hidden */
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <strings.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <libintl.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <libcpc.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include "cpucmds.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate struct args {
397c478bd9Sstevel@tonic-gate 	FILE *fp;
407c478bd9Sstevel@tonic-gate 	int colnum;
417c478bd9Sstevel@tonic-gate 	int margin;
427c478bd9Sstevel@tonic-gate };
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate struct evlist {
457c478bd9Sstevel@tonic-gate 	char *list;
467c478bd9Sstevel@tonic-gate 	int size;
477c478bd9Sstevel@tonic-gate };
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #define	MAX_RHS_COLUMN	76
507c478bd9Sstevel@tonic-gate #define	EVENT_MARGIN	17
517c478bd9Sstevel@tonic-gate #define	ATTR_MARGIN	20
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*ARGSUSED*/
547c478bd9Sstevel@tonic-gate static void
list_cap(void * arg,uint_t regno,const char * name)557c478bd9Sstevel@tonic-gate list_cap(void *arg, uint_t regno, const char *name)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	struct args *args = arg;
587c478bd9Sstevel@tonic-gate 	int i;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	if ((args->colnum + strlen(name) + 1) > MAX_RHS_COLUMN) {
617c478bd9Sstevel@tonic-gate 		(void) fprintf(args->fp, "\n");
627c478bd9Sstevel@tonic-gate 		for (i = 0; i < args->margin; i++)
637c478bd9Sstevel@tonic-gate 			(void) fprintf(args->fp, " ");
647c478bd9Sstevel@tonic-gate 		args->colnum = args->margin;
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 	args->colnum += fprintf(args->fp, "%s ", name);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate static void
list_attr(void * arg,const char * name)707c478bd9Sstevel@tonic-gate list_attr(void *arg, const char *name)
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate 	/*
737c478bd9Sstevel@tonic-gate 	 * The following attributes are used by the commands but should not be
747c478bd9Sstevel@tonic-gate 	 * reported to the user, since they may not be specified directly.
757c478bd9Sstevel@tonic-gate 	 */
767c478bd9Sstevel@tonic-gate 	if (strncmp(name, "picnum", 7) == 0 ||
777c478bd9Sstevel@tonic-gate 	    strncmp(name, "count_sibling_usr", 18) == 0 ||
787c478bd9Sstevel@tonic-gate 	    strncmp(name, "count_sibling_sys", 18) == 0)
797c478bd9Sstevel@tonic-gate 		return;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	list_cap(arg, 0, name);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static void *
emalloc(size_t size)857c478bd9Sstevel@tonic-gate emalloc(size_t size)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	void *ptr;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if ((ptr = malloc(size)) == NULL) {
907c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("no memory available\n"));
917c478bd9Sstevel@tonic-gate 		exit(1);
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	return (ptr);
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * Used by allpics_equal().
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1017c478bd9Sstevel@tonic-gate static void
cap_walker(void * arg,uint_t regno,const char * name)1027c478bd9Sstevel@tonic-gate cap_walker(void *arg, uint_t regno, const char *name)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	struct evlist *list = arg;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	list->size += strlen(name);
1077c478bd9Sstevel@tonic-gate 	if ((list->list = realloc(list->list, list->size + 1)) == NULL) {
1087c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("no memory available\n"));
1097c478bd9Sstevel@tonic-gate 		exit(1);
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	(void) strcat(list->list, name);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * Returns 1 if all counters on this chip can count all possible events.
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate static int
allpics_equal(cpc_t * cpc)1197c478bd9Sstevel@tonic-gate allpics_equal(cpc_t *cpc)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	int	npics = cpc_npic(cpc);
1227c478bd9Sstevel@tonic-gate 	int	i;
1237c478bd9Sstevel@tonic-gate 	struct	evlist **lists;
1247c478bd9Sstevel@tonic-gate 	int	ret = 1;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	lists = emalloc(npics * sizeof (struct evlist *));
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	for (i = 0; i < npics; i++) {
1297c478bd9Sstevel@tonic-gate 		lists[i] = emalloc(sizeof (struct evlist));
1307c478bd9Sstevel@tonic-gate 		lists[i]->size = 0;
1317c478bd9Sstevel@tonic-gate 		lists[i]->list = emalloc(1);
1327c478bd9Sstevel@tonic-gate 		lists[i]->list[0] = '\0';
1337c478bd9Sstevel@tonic-gate 		cpc_walk_events_pic(cpc, i, lists[i], cap_walker);
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	for (i = 1; i < npics; i++)
1377c478bd9Sstevel@tonic-gate 		if (lists[i]->size != lists[0]->size ||
1387c478bd9Sstevel@tonic-gate 		    strncmp(lists[i]->list, lists[0]->list,
1397c478bd9Sstevel@tonic-gate 		    lists[0]->size) != 0) {
1407c478bd9Sstevel@tonic-gate 			ret = 0;
1417c478bd9Sstevel@tonic-gate 			break;
1427c478bd9Sstevel@tonic-gate 		}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	for (i = 0; i < npics; i++) {
1457c478bd9Sstevel@tonic-gate 		free(lists[i]->list);
1467c478bd9Sstevel@tonic-gate 		free(lists[i]);
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 	free(lists);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	return (ret);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate int
capabilities(cpc_t * cpc,FILE * fp)1547c478bd9Sstevel@tonic-gate capabilities(cpc_t *cpc, FILE *fp)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	struct args _args, *args = &_args;
1577c478bd9Sstevel@tonic-gate 	char *text, *tok, *cp;
1587c478bd9Sstevel@tonic-gate 	const char *ccp;
1597c478bd9Sstevel@tonic-gate 	int npic = cpc_npic(cpc);
160*c7a079a8SJonathan Haslam 	int i, pics_equal = allpics_equal(cpc);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	args->fp = fp;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if ((ccp = cpc_cciname(cpc)) == NULL)
1657c478bd9Sstevel@tonic-gate 		ccp = "No information available";
1667c478bd9Sstevel@tonic-gate 	(void) fprintf(args->fp, "\t%s: %s\n\n",
1677c478bd9Sstevel@tonic-gate 	    gettext("CPU performance counter interface"), ccp);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	(void) fprintf(args->fp, gettext("\tevent specification syntax:\n"));
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	(void) fprintf(args->fp, "\t[picn=]<eventn>[,attr[n][=<val>]]"
1727c478bd9Sstevel@tonic-gate 	    "[,[picn=]<eventn>[,attr[n][=<val>]],...]\n");
1737c478bd9Sstevel@tonic-gate 
174*c7a079a8SJonathan Haslam 	(void) fprintf(args->fp, gettext("\n\tGeneric Events:\n"));
175*c7a079a8SJonathan Haslam 
176*c7a079a8SJonathan Haslam 	if (pics_equal) {
177*c7a079a8SJonathan Haslam 		args->margin = args->colnum = EVENT_MARGIN;
178*c7a079a8SJonathan Haslam 		(void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1);
179*c7a079a8SJonathan Haslam 		cpc_walk_generic_events_pic(cpc, 0, args, list_cap);
180*c7a079a8SJonathan Haslam 		(void) fprintf(args->fp, "\n");
181*c7a079a8SJonathan Haslam 	} else {
182*c7a079a8SJonathan Haslam 		args->margin = EVENT_MARGIN;
183*c7a079a8SJonathan Haslam 		for (i = 0; i < npic; i++) {
184*c7a079a8SJonathan Haslam 			(void) fprintf(args->fp, "\n\tevent%d: ", i);
185*c7a079a8SJonathan Haslam 			if (i < 10) (void) fprintf(args->fp, " ");
186*c7a079a8SJonathan Haslam 			args->colnum = EVENT_MARGIN;
187*c7a079a8SJonathan Haslam 			cpc_walk_generic_events_pic(cpc, i, args, list_cap);
188*c7a079a8SJonathan Haslam 			(void) fprintf(args->fp, "\n");
189*c7a079a8SJonathan Haslam 		}
190*c7a079a8SJonathan Haslam 	}
191*c7a079a8SJonathan Haslam 
192*c7a079a8SJonathan Haslam 	(void) fprintf(args->fp, gettext("\n\tSee generic_events(3CPC) for"
193*c7a079a8SJonathan Haslam 	    " descriptions of these events\n\n"));
194*c7a079a8SJonathan Haslam 
195*c7a079a8SJonathan Haslam 	(void) fprintf(args->fp, gettext("\tPlatform Specific Events:\n"));
196*c7a079a8SJonathan Haslam 
197*c7a079a8SJonathan Haslam 	if (pics_equal) {
1987c478bd9Sstevel@tonic-gate 		args->margin = args->colnum = EVENT_MARGIN;
1997c478bd9Sstevel@tonic-gate 		(void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1);
2007c478bd9Sstevel@tonic-gate 		cpc_walk_events_pic(cpc, 0, args, list_cap);
2017c478bd9Sstevel@tonic-gate 		(void) fprintf(args->fp, "\n");
2027c478bd9Sstevel@tonic-gate 	} else {
2037c478bd9Sstevel@tonic-gate 		args->margin = EVENT_MARGIN;
2047c478bd9Sstevel@tonic-gate 		for (i = 0; i < npic; i++) {
2057c478bd9Sstevel@tonic-gate 			(void) fprintf(args->fp, "\n\tevent%d: ", i);
2067c478bd9Sstevel@tonic-gate 			if (i < 10) (void) fprintf(args->fp, " ");
2077c478bd9Sstevel@tonic-gate 			args->colnum = EVENT_MARGIN;
2087c478bd9Sstevel@tonic-gate 			cpc_walk_events_pic(cpc, i, args, list_cap);
2097c478bd9Sstevel@tonic-gate 			(void) fprintf(args->fp, "\n");
2107c478bd9Sstevel@tonic-gate 		}
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	(void) fprintf(args->fp, "\n\tattributes: ");
2147c478bd9Sstevel@tonic-gate 	args->colnum = args->margin = ATTR_MARGIN;
2157c478bd9Sstevel@tonic-gate 	cpc_walk_attrs(cpc, args, list_attr);
2167c478bd9Sstevel@tonic-gate 	/*
2177c478bd9Sstevel@tonic-gate 	 * In addition to the attributes published by the kernel, we allow the
2187c478bd9Sstevel@tonic-gate 	 * user to specify two additional tokens on all platforms. List them
2197c478bd9Sstevel@tonic-gate 	 * here.
2207c478bd9Sstevel@tonic-gate 	 */
2217c478bd9Sstevel@tonic-gate 	list_cap(args, 0, "nouser");
2227c478bd9Sstevel@tonic-gate 	list_cap(args, 0, "sys");
2237c478bd9Sstevel@tonic-gate 	(void) fprintf(args->fp, "\n\n\t");
2247c478bd9Sstevel@tonic-gate 	args->colnum = 8;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	if ((ccp = cpc_cpuref(cpc)) == NULL)
2277c478bd9Sstevel@tonic-gate 		ccp = "No information available";
2287c478bd9Sstevel@tonic-gate 	if ((text = strdup(ccp)) == NULL) {
2297c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("no memory available.\n"));
2307c478bd9Sstevel@tonic-gate 		exit(1);
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 	for (cp = strtok_r(text, " ", &tok);
2337c478bd9Sstevel@tonic-gate 	    cp != NULL; cp = strtok_r(NULL, " ", &tok)) {
2347c478bd9Sstevel@tonic-gate 		if ((args->colnum + strlen(cp) + 1) > MAX_RHS_COLUMN) {
2357c478bd9Sstevel@tonic-gate 			(void) fprintf(args->fp, "\n\t");
2367c478bd9Sstevel@tonic-gate 			args->colnum = 8;
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 		args->colnum += fprintf(args->fp, "%s ", cp);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 	(void) fprintf(args->fp, "\n");
2417c478bd9Sstevel@tonic-gate 	free(text);
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	return (0);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * Returns 1 on SMT processors which do not have full CPC hardware for each
2487c478bd9Sstevel@tonic-gate  * logical processor.
2497c478bd9Sstevel@tonic-gate  */
2507c478bd9Sstevel@tonic-gate int
smt_limited_cpc_hw(cpc_t * cpc)2517c478bd9Sstevel@tonic-gate smt_limited_cpc_hw(cpc_t *cpc)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	if (strcmp(cpc_cciname(cpc), "Pentium 4 with HyperThreading") == 0)
2547c478bd9Sstevel@tonic-gate 		return (1);
2557c478bd9Sstevel@tonic-gate 	return (0);
2567c478bd9Sstevel@tonic-gate }
257