xref: /illumos-gate/usr/src/cmd/cpc/common/caps.c (revision c7a079a8)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #define	 __EXTENSIONS__	/* header bug! strtok_r is overly hidden */
27 #include <string.h>
28 #include <strings.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <libintl.h>
33 
34 #include <libcpc.h>
35 
36 #include "cpucmds.h"
37 
38 struct args {
39 	FILE *fp;
40 	int colnum;
41 	int margin;
42 };
43 
44 struct evlist {
45 	char *list;
46 	int size;
47 };
48 
49 #define	MAX_RHS_COLUMN	76
50 #define	EVENT_MARGIN	17
51 #define	ATTR_MARGIN	20
52 
53 /*ARGSUSED*/
54 static void
list_cap(void * arg,uint_t regno,const char * name)55 list_cap(void *arg, uint_t regno, const char *name)
56 {
57 	struct args *args = arg;
58 	int i;
59 
60 	if ((args->colnum + strlen(name) + 1) > MAX_RHS_COLUMN) {
61 		(void) fprintf(args->fp, "\n");
62 		for (i = 0; i < args->margin; i++)
63 			(void) fprintf(args->fp, " ");
64 		args->colnum = args->margin;
65 	}
66 	args->colnum += fprintf(args->fp, "%s ", name);
67 }
68 
69 static void
list_attr(void * arg,const char * name)70 list_attr(void *arg, const char *name)
71 {
72 	/*
73 	 * The following attributes are used by the commands but should not be
74 	 * reported to the user, since they may not be specified directly.
75 	 */
76 	if (strncmp(name, "picnum", 7) == 0 ||
77 	    strncmp(name, "count_sibling_usr", 18) == 0 ||
78 	    strncmp(name, "count_sibling_sys", 18) == 0)
79 		return;
80 
81 	list_cap(arg, 0, name);
82 }
83 
84 static void *
emalloc(size_t size)85 emalloc(size_t size)
86 {
87 	void *ptr;
88 
89 	if ((ptr = malloc(size)) == NULL) {
90 		(void) fprintf(stderr, gettext("no memory available\n"));
91 		exit(1);
92 	}
93 
94 	return (ptr);
95 }
96 
97 /*
98  * Used by allpics_equal().
99  */
100 /*ARGSUSED*/
101 static void
cap_walker(void * arg,uint_t regno,const char * name)102 cap_walker(void *arg, uint_t regno, const char *name)
103 {
104 	struct evlist *list = arg;
105 
106 	list->size += strlen(name);
107 	if ((list->list = realloc(list->list, list->size + 1)) == NULL) {
108 		(void) fprintf(stderr, gettext("no memory available\n"));
109 		exit(1);
110 	}
111 
112 	(void) strcat(list->list, name);
113 }
114 
115 /*
116  * Returns 1 if all counters on this chip can count all possible events.
117  */
118 static int
allpics_equal(cpc_t * cpc)119 allpics_equal(cpc_t *cpc)
120 {
121 	int	npics = cpc_npic(cpc);
122 	int	i;
123 	struct	evlist **lists;
124 	int	ret = 1;
125 
126 	lists = emalloc(npics * sizeof (struct evlist *));
127 
128 	for (i = 0; i < npics; i++) {
129 		lists[i] = emalloc(sizeof (struct evlist));
130 		lists[i]->size = 0;
131 		lists[i]->list = emalloc(1);
132 		lists[i]->list[0] = '\0';
133 		cpc_walk_events_pic(cpc, i, lists[i], cap_walker);
134 	}
135 
136 	for (i = 1; i < npics; i++)
137 		if (lists[i]->size != lists[0]->size ||
138 		    strncmp(lists[i]->list, lists[0]->list,
139 		    lists[0]->size) != 0) {
140 			ret = 0;
141 			break;
142 		}
143 
144 	for (i = 0; i < npics; i++) {
145 		free(lists[i]->list);
146 		free(lists[i]);
147 	}
148 	free(lists);
149 
150 	return (ret);
151 }
152 
153 int
capabilities(cpc_t * cpc,FILE * fp)154 capabilities(cpc_t *cpc, FILE *fp)
155 {
156 	struct args _args, *args = &_args;
157 	char *text, *tok, *cp;
158 	const char *ccp;
159 	int npic = cpc_npic(cpc);
160 	int i, pics_equal = allpics_equal(cpc);
161 
162 	args->fp = fp;
163 
164 	if ((ccp = cpc_cciname(cpc)) == NULL)
165 		ccp = "No information available";
166 	(void) fprintf(args->fp, "\t%s: %s\n\n",
167 	    gettext("CPU performance counter interface"), ccp);
168 
169 	(void) fprintf(args->fp, gettext("\tevent specification syntax:\n"));
170 
171 	(void) fprintf(args->fp, "\t[picn=]<eventn>[,attr[n][=<val>]]"
172 	    "[,[picn=]<eventn>[,attr[n][=<val>]],...]\n");
173 
174 	(void) fprintf(args->fp, gettext("\n\tGeneric Events:\n"));
175 
176 	if (pics_equal) {
177 		args->margin = args->colnum = EVENT_MARGIN;
178 		(void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1);
179 		cpc_walk_generic_events_pic(cpc, 0, args, list_cap);
180 		(void) fprintf(args->fp, "\n");
181 	} else {
182 		args->margin = EVENT_MARGIN;
183 		for (i = 0; i < npic; i++) {
184 			(void) fprintf(args->fp, "\n\tevent%d: ", i);
185 			if (i < 10) (void) fprintf(args->fp, " ");
186 			args->colnum = EVENT_MARGIN;
187 			cpc_walk_generic_events_pic(cpc, i, args, list_cap);
188 			(void) fprintf(args->fp, "\n");
189 		}
190 	}
191 
192 	(void) fprintf(args->fp, gettext("\n\tSee generic_events(3CPC) for"
193 	    " descriptions of these events\n\n"));
194 
195 	(void) fprintf(args->fp, gettext("\tPlatform Specific Events:\n"));
196 
197 	if (pics_equal) {
198 		args->margin = args->colnum = EVENT_MARGIN;
199 		(void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1);
200 		cpc_walk_events_pic(cpc, 0, args, list_cap);
201 		(void) fprintf(args->fp, "\n");
202 	} else {
203 		args->margin = EVENT_MARGIN;
204 		for (i = 0; i < npic; i++) {
205 			(void) fprintf(args->fp, "\n\tevent%d: ", i);
206 			if (i < 10) (void) fprintf(args->fp, " ");
207 			args->colnum = EVENT_MARGIN;
208 			cpc_walk_events_pic(cpc, i, args, list_cap);
209 			(void) fprintf(args->fp, "\n");
210 		}
211 	}
212 
213 	(void) fprintf(args->fp, "\n\tattributes: ");
214 	args->colnum = args->margin = ATTR_MARGIN;
215 	cpc_walk_attrs(cpc, args, list_attr);
216 	/*
217 	 * In addition to the attributes published by the kernel, we allow the
218 	 * user to specify two additional tokens on all platforms. List them
219 	 * here.
220 	 */
221 	list_cap(args, 0, "nouser");
222 	list_cap(args, 0, "sys");
223 	(void) fprintf(args->fp, "\n\n\t");
224 	args->colnum = 8;
225 
226 	if ((ccp = cpc_cpuref(cpc)) == NULL)
227 		ccp = "No information available";
228 	if ((text = strdup(ccp)) == NULL) {
229 		(void) fprintf(stderr, gettext("no memory available.\n"));
230 		exit(1);
231 	}
232 	for (cp = strtok_r(text, " ", &tok);
233 	    cp != NULL; cp = strtok_r(NULL, " ", &tok)) {
234 		if ((args->colnum + strlen(cp) + 1) > MAX_RHS_COLUMN) {
235 			(void) fprintf(args->fp, "\n\t");
236 			args->colnum = 8;
237 		}
238 		args->colnum += fprintf(args->fp, "%s ", cp);
239 	}
240 	(void) fprintf(args->fp, "\n");
241 	free(text);
242 
243 	return (0);
244 }
245 
246 /*
247  * Returns 1 on SMT processors which do not have full CPC hardware for each
248  * logical processor.
249  */
250 int
smt_limited_cpc_hw(cpc_t * cpc)251 smt_limited_cpc_hw(cpc_t *cpc)
252 {
253 	if (strcmp(cpc_cciname(cpc), "Pentium 4 with HyperThreading") == 0)
254 		return (1);
255 	return (0);
256 }
257