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