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