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