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