xref: /illumos-gate/usr/src/cmd/cpc/common/setgrp.c (revision 7c478bd9)
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 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <libintl.h>
34 #include <sys/types.h>
35 
36 
37 #include <libcpc.h>
38 #include "cpucmds.h"
39 
40 #define	CHARS_PER_REQ 11	/* space required for printing column headers */
41 
42 /*
43  * These routines are solely used to manage a list of request sets.
44  */
45 
46 struct __cpc_setgrp {
47 	struct setgrp_elem {
48 		cpc_set_t	*set;
49 		uint8_t		sysonly;	/* All reqs sys-mode only ? */
50 		int		nreqs;
51 		int		*picnums;	/* picnum used per req */
52 		cpc_buf_t	*data1;
53 		cpc_buf_t	*data2;
54 		cpc_buf_t	*scratch;
55 		char *name;
56 		char *hdr;
57 	} *sets;		/* array of events and names */
58 	int nelem;		/* size of array */
59 	int current;		/* currently bound event in eventset */
60 	int smt;		/* Measures physical events on SMT CPU */
61 	int has_sysonly_set;	/* Does this group have a system-only set? */
62 	cpc_t *cpc;		/* library handle */
63 };
64 
65 static void *emalloc(size_t n);
66 
67 cpc_setgrp_t *
cpc_setgrp_new(cpc_t * cpc,int smt)68 cpc_setgrp_new(cpc_t *cpc, int smt)
69 {
70 	cpc_setgrp_t *sgrp;
71 
72 	sgrp = emalloc(sizeof (*sgrp));
73 	sgrp->current = -1;
74 	sgrp->cpc = cpc;
75 	sgrp->smt = smt;
76 	sgrp->has_sysonly_set = 0;
77 	return (sgrp);
78 }
79 
80 /*
81  * Walker to count the number of requests in a set, and check if any requests
82  * count user-mode events.
83  */
84 /*ARGSUSED*/
85 static void
cpc_setgrp_walker(void * arg,int index,const char * event,uint64_t preset,uint_t flags,int nattrs,const cpc_attr_t * attrs)86 cpc_setgrp_walker(void *arg, int index, const char *event, uint64_t preset,
87     uint_t flags, int nattrs, const cpc_attr_t *attrs)
88 {
89 	struct setgrp_elem *se = arg;
90 
91 	se->nreqs++;
92 	if (flags & CPC_COUNT_USER)
93 		se->sysonly = 0;
94 }
95 
96 /*
97  * Walker to discover the picnums used by the requests in a set.
98  */
99 /*ARGSUSED*/
100 static void
cpc_setgrp_picwalker(void * arg,int index,const char * event,uint64_t preset,uint_t flags,int nattrs,const cpc_attr_t * attrs)101 cpc_setgrp_picwalker(void *arg, int index, const char *event, uint64_t preset,
102     uint_t flags, int nattrs, const cpc_attr_t *attrs)
103 {
104 	int *picnums = arg;
105 	int i;
106 
107 	for (i = 0; i < nattrs; i++) {
108 		if (strncmp(attrs[i].ca_name, "picnum", 7) == 0)
109 			break;
110 	}
111 	if (i == nattrs)
112 		picnums[index] = -1;
113 
114 	picnums[index] = (int)attrs[i].ca_val;
115 }
116 
117 cpc_setgrp_t *
cpc_setgrp_newset(cpc_setgrp_t * sgrp,const char * spec,int * errcnt)118 cpc_setgrp_newset(cpc_setgrp_t *sgrp, const char *spec, int *errcnt)
119 {
120 	cpc_set_t		*set;
121 	struct setgrp_elem	*new;
122 	char			hdr[CHARS_PER_REQ+1];
123 	int			i;
124 
125 	if ((set = cpc_strtoset(sgrp->cpc, spec, sgrp->smt)) == NULL) {
126 		*errcnt += 1;
127 		return (NULL);
128 	}
129 
130 	if ((new = realloc(sgrp->sets, (1 + sgrp->nelem) * sizeof (*new)))
131 	    == NULL) {
132 		(void) fprintf(stderr,
133 		    gettext("cpc_setgrp: no re memory available\n"));
134 		exit(0);
135 	}
136 
137 	sgrp->sets = new;
138 	sgrp->sets[sgrp->nelem].set = set;
139 	/*
140 	 * Count the number of requests in the set we just made. If any requests
141 	 * in the set have CPC_COUNT_USER in the flags, the sysonly flag will
142 	 * be cleared.
143 	 */
144 	sgrp->sets[sgrp->nelem].nreqs = 0;
145 	sgrp->sets[sgrp->nelem].sysonly = 1;
146 	cpc_walk_requests(sgrp->cpc, set, &(sgrp->sets[sgrp->nelem]),
147 	    cpc_setgrp_walker);
148 
149 	if (sgrp->sets[sgrp->nelem].sysonly == 1)
150 		sgrp->has_sysonly_set = 1;
151 
152 	sgrp->sets[sgrp->nelem].picnums = emalloc(sgrp->sets[sgrp->nelem].nreqs
153 	    * sizeof (int));
154 
155 	sgrp->sets[sgrp->nelem].hdr = emalloc((sgrp->sets[sgrp->nelem].nreqs *
156 	    CHARS_PER_REQ) + 1);
157 
158 	/*
159 	 * Find out which picnums the requests are using.
160 	 */
161 	cpc_walk_requests(sgrp->cpc, set, sgrp->sets[sgrp->nelem].picnums,
162 	    cpc_setgrp_picwalker);
163 	/*
164 	 * Use the picnums we discovered to build a printable header for this
165 	 * set.
166 	 */
167 	sgrp->sets[sgrp->nelem].hdr[0] = '\0';
168 	for (i = 0; i < sgrp->sets[sgrp->nelem].nreqs; i++) {
169 		(void) snprintf(hdr, CHARS_PER_REQ, "%8s%-2d ", "pic",
170 		    sgrp->sets[sgrp->nelem].picnums[i]);
171 		(void) strncat(sgrp->sets[sgrp->nelem].hdr, hdr,
172 		    sgrp->sets[sgrp->nelem].nreqs * CHARS_PER_REQ);
173 	}
174 	sgrp->sets[sgrp->nelem].hdr[strlen(sgrp->sets[sgrp->nelem].hdr)] = '\0';
175 
176 	if ((sgrp->sets[sgrp->nelem].name = strdup(spec)) == NULL) {
177 		(void) fprintf(stderr,
178 		    gettext("cpc_setgrp: no memory available\n"));
179 		exit(0);
180 	}
181 
182 	if ((sgrp->sets[sgrp->nelem].data1 = cpc_buf_create(sgrp->cpc, set))
183 	    == NULL ||
184 	    (sgrp->sets[sgrp->nelem].data2 = cpc_buf_create(sgrp->cpc, set))
185 	    == NULL ||
186 	    (sgrp->sets[sgrp->nelem].scratch = cpc_buf_create(sgrp->cpc, set))
187 	    == NULL) {
188 		(void) fprintf(stderr,
189 		    gettext("cpc_setgrp: no memory available\n"));
190 		exit(0);
191 	}
192 
193 	if (sgrp->current < 0)
194 		sgrp->current = 0;
195 	sgrp->nelem++;
196 	return (sgrp);
197 }
198 
199 int
cpc_setgrp_getbufs(cpc_setgrp_t * sgrp,cpc_buf_t *** data1,cpc_buf_t *** data2,cpc_buf_t *** scratch)200 cpc_setgrp_getbufs(cpc_setgrp_t *sgrp, cpc_buf_t ***data1, cpc_buf_t ***data2,
201     cpc_buf_t ***scratch)
202 {
203 	if ((uint_t)sgrp->current >= sgrp->nelem)
204 		return (-1);
205 
206 	*data1   = &(sgrp->sets[sgrp->current].data1);
207 	*data2   = &(sgrp->sets[sgrp->current].data2);
208 	*scratch = &(sgrp->sets[sgrp->current].scratch);
209 
210 	return (sgrp->sets[sgrp->current].nreqs);
211 }
212 
213 cpc_setgrp_t *
cpc_setgrp_clone(cpc_setgrp_t * old)214 cpc_setgrp_clone(cpc_setgrp_t *old)
215 {
216 	int			i;
217 	cpc_setgrp_t		*new;
218 	struct setgrp_elem	*newa;
219 
220 	new = emalloc(sizeof (*new));
221 	newa = emalloc(old->nelem * sizeof (*newa));
222 
223 	new->nelem = old->nelem;
224 	new->current = old->current;
225 	new->cpc = old->cpc;
226 	new->sets = newa;
227 	new->smt = old->smt;
228 	new->has_sysonly_set = old->has_sysonly_set;
229 	for (i = 0; i < old->nelem; i++) {
230 		if ((newa[i].set = cpc_strtoset(old->cpc, old->sets[i].name,
231 		    old->smt)) == NULL) {
232 			(void) fprintf(stderr,
233 			    gettext("cpc_setgrp: cpc_strtoset() failed\n"));
234 			exit(0);
235 		}
236 		if ((newa[i].name = strdup(old->sets[i].name)) == NULL) {
237 			(void) fprintf(stderr,
238 			    gettext("cpc_setgrp: no memory available\n"));
239 			exit(0);
240 		}
241 		newa[i].sysonly = old->sets[i].sysonly;
242 		newa[i].nreqs = old->sets[i].nreqs;
243 		newa[i].data1 = cpc_buf_create(old->cpc, newa[i].set);
244 		newa[i].data2 = cpc_buf_create(old->cpc, newa[i].set);
245 		newa[i].scratch = cpc_buf_create(old->cpc, newa[i].set);
246 		if (newa[i].data1 == NULL || newa[i].data2 == NULL ||
247 		    newa[i].scratch == NULL) {
248 			(void) fprintf(stderr,
249 			    gettext("cpc_setgrp: no memory available\n"));
250 			exit(0);
251 		}
252 		cpc_buf_copy(old->cpc, newa[i].data1, old->sets[i].data1);
253 		cpc_buf_copy(old->cpc, newa[i].data2, old->sets[i].data2);
254 		cpc_buf_copy(old->cpc, newa[i].scratch, old->sets[i].scratch);
255 	}
256 	return (new);
257 }
258 
259 static void
cpc_setgrp_delset(cpc_setgrp_t * sgrp)260 cpc_setgrp_delset(cpc_setgrp_t *sgrp)
261 {
262 	int l;
263 
264 	if ((uint_t)sgrp->current >= sgrp->nelem)
265 		sgrp->current = sgrp->nelem - 1;
266 	if (sgrp->current < 0)
267 		return;
268 	free(sgrp->sets[sgrp->current].name);
269 	free(sgrp->sets[sgrp->current].hdr);
270 	free(sgrp->sets[sgrp->current].picnums);
271 	(void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].data1);
272 	(void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].data2);
273 	(void) cpc_buf_destroy(sgrp->cpc, sgrp->sets[sgrp->current].scratch);
274 	for (l = sgrp->current; l < sgrp->nelem - 1; l++)
275 		sgrp->sets[l] = sgrp->sets[l + 1];
276 	sgrp->nelem--;
277 }
278 
279 void
cpc_setgrp_free(cpc_setgrp_t * sgrp)280 cpc_setgrp_free(cpc_setgrp_t *sgrp)
281 {
282 	if (sgrp->sets) {
283 		while (sgrp->nelem)
284 			cpc_setgrp_delset(sgrp);
285 		free(sgrp->sets);
286 	}
287 	free(sgrp);
288 }
289 
290 cpc_set_t *
cpc_setgrp_getset(cpc_setgrp_t * sgrp)291 cpc_setgrp_getset(cpc_setgrp_t *sgrp)
292 {
293 	if ((uint_t)sgrp->current >= sgrp->nelem)
294 		return (NULL);
295 	return (sgrp->sets[sgrp->current].set);
296 }
297 
298 const char *
cpc_setgrp_getname(cpc_setgrp_t * sgrp)299 cpc_setgrp_getname(cpc_setgrp_t *sgrp)
300 {
301 	if ((uint_t)sgrp->current >= sgrp->nelem)
302 		return (NULL);
303 	return (sgrp->sets[sgrp->current].name);
304 }
305 
306 const char *
cpc_setgrp_gethdr(cpc_setgrp_t * sgrp)307 cpc_setgrp_gethdr(cpc_setgrp_t *sgrp)
308 {
309 	if ((uint_t)sgrp->current >= sgrp->nelem)
310 		return (NULL);
311 	return (sgrp->sets[sgrp->current].hdr);
312 }
313 
314 int
cpc_setgrp_numsets(cpc_setgrp_t * sgrp)315 cpc_setgrp_numsets(cpc_setgrp_t *sgrp)
316 {
317 	return (sgrp->nelem);
318 }
319 
320 cpc_set_t *
cpc_setgrp_nextset(cpc_setgrp_t * sgrp)321 cpc_setgrp_nextset(cpc_setgrp_t *sgrp)
322 {
323 	if (sgrp->current < 0)
324 		return (NULL);
325 
326 	if (++sgrp->current >= sgrp->nelem)
327 		sgrp->current = 0;
328 
329 	return (cpc_setgrp_getset(sgrp));
330 }
331 
332 /*
333  * Put the setgrp pointer back to the beginning of the set
334  */
335 void
cpc_setgrp_reset(cpc_setgrp_t * sgrp)336 cpc_setgrp_reset(cpc_setgrp_t *sgrp)
337 {
338 	if (sgrp->current > 0)
339 		sgrp->current = 0;
340 }
341 
342 /*
343  * Adds the data from the 'data1' buf into the accum setgrp.
344  */
345 void
cpc_setgrp_accum(cpc_setgrp_t * accum,cpc_setgrp_t * sgrp)346 cpc_setgrp_accum(cpc_setgrp_t *accum, cpc_setgrp_t *sgrp)
347 {
348 	int i;
349 
350 	cpc_setgrp_reset(accum);
351 	cpc_setgrp_reset(sgrp);
352 	if (accum->nelem != sgrp->nelem)
353 		return;
354 
355 	for (i = 0; i < sgrp->nelem; i++) {
356 		if (accum->sets[i].nreqs != sgrp->sets[i].nreqs)
357 			return;
358 		cpc_buf_add(sgrp->cpc, accum->sets[i].data1,
359 		    accum->sets[i].data1, sgrp->sets[i].data1);
360 	}
361 }
362 
363 /*
364  * Returns 1 if all requests in the current set count only system-mode events.
365  */
366 int
cpc_setgrp_sysonly(cpc_setgrp_t * sgrp)367 cpc_setgrp_sysonly(cpc_setgrp_t *sgrp)
368 {
369 	return ((int)sgrp->sets[sgrp->current].sysonly);
370 }
371 
372 /*
373  * Returns 1 if any set in the group is a system-mode-only set.
374  */
375 int
cpc_setgrp_has_sysonly(cpc_setgrp_t * sgrp)376 cpc_setgrp_has_sysonly(cpc_setgrp_t *sgrp)
377 {
378 	return (sgrp->has_sysonly_set);
379 }
380 
381 /*
382  * If we ever fail to get memory, we print an error message and exit.
383  */
384 static void *
emalloc(size_t n)385 emalloc(size_t n)
386 {
387 	/*
388 	 * Several callers of this routine need zero-filled buffers.
389 	 */
390 	void *p = calloc(1, n);
391 
392 	if (p == NULL) {
393 		(void) fprintf(stderr,
394 		    gettext("cpc_setgrp: no memory available\n"));
395 		exit(0);
396 	}
397 
398 	return (p);
399 }
400