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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #define __EXTENSIONS__ /* header bug! strtok_r is overly hidden */ 27 #include <string.h> 28 #include <strings.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <libintl.h> 33 34 #include <libcpc.h> 35 36 #include "cpucmds.h" 37 38 struct args { 39 FILE *fp; 40 int colnum; 41 int margin; 42 }; 43 44 struct evlist { 45 char *list; 46 int size; 47 }; 48 49 #define MAX_RHS_COLUMN 76 50 #define EVENT_MARGIN 17 51 #define ATTR_MARGIN 20 52 53 /*ARGSUSED*/ 54 static void 55 list_cap(void *arg, uint_t regno, const char *name) 56 { 57 struct args *args = arg; 58 int i; 59 60 if ((args->colnum + strlen(name) + 1) > MAX_RHS_COLUMN) { 61 (void) fprintf(args->fp, "\n"); 62 for (i = 0; i < args->margin; i++) 63 (void) fprintf(args->fp, " "); 64 args->colnum = args->margin; 65 } 66 args->colnum += fprintf(args->fp, "%s ", name); 67 } 68 69 static void 70 list_attr(void *arg, const char *name) 71 { 72 /* 73 * The following attributes are used by the commands but should not be 74 * reported to the user, since they may not be specified directly. 75 */ 76 if (strncmp(name, "picnum", 7) == 0 || 77 strncmp(name, "count_sibling_usr", 18) == 0 || 78 strncmp(name, "count_sibling_sys", 18) == 0) 79 return; 80 81 list_cap(arg, 0, name); 82 } 83 84 static void * 85 emalloc(size_t size) 86 { 87 void *ptr; 88 89 if ((ptr = malloc(size)) == NULL) { 90 (void) fprintf(stderr, gettext("no memory available\n")); 91 exit(1); 92 } 93 94 return (ptr); 95 } 96 97 /* 98 * Used by allpics_equal(). 99 */ 100 /*ARGSUSED*/ 101 static void 102 cap_walker(void *arg, uint_t regno, const char *name) 103 { 104 struct evlist *list = arg; 105 106 list->size += strlen(name); 107 if ((list->list = realloc(list->list, list->size + 1)) == NULL) { 108 (void) fprintf(stderr, gettext("no memory available\n")); 109 exit(1); 110 } 111 112 (void) strcat(list->list, name); 113 } 114 115 /* 116 * Returns 1 if all counters on this chip can count all possible events. 117 */ 118 static int 119 allpics_equal(cpc_t *cpc) 120 { 121 int npics = cpc_npic(cpc); 122 int i; 123 struct evlist **lists; 124 int ret = 1; 125 126 lists = emalloc(npics * sizeof (struct evlist *)); 127 128 for (i = 0; i < npics; i++) { 129 lists[i] = emalloc(sizeof (struct evlist)); 130 lists[i]->size = 0; 131 lists[i]->list = emalloc(1); 132 lists[i]->list[0] = '\0'; 133 cpc_walk_events_pic(cpc, i, lists[i], cap_walker); 134 } 135 136 for (i = 1; i < npics; i++) 137 if (lists[i]->size != lists[0]->size || 138 strncmp(lists[i]->list, lists[0]->list, 139 lists[0]->size) != 0) { 140 ret = 0; 141 break; 142 } 143 144 for (i = 0; i < npics; i++) { 145 free(lists[i]->list); 146 free(lists[i]); 147 } 148 free(lists); 149 150 return (ret); 151 } 152 153 int 154 capabilities(cpc_t *cpc, FILE *fp) 155 { 156 struct args _args, *args = &_args; 157 char *text, *tok, *cp; 158 const char *ccp; 159 int npic = cpc_npic(cpc); 160 int i, pics_equal = allpics_equal(cpc); 161 162 args->fp = fp; 163 164 if ((ccp = cpc_cciname(cpc)) == NULL) 165 ccp = "No information available"; 166 (void) fprintf(args->fp, "\t%s: %s\n\n", 167 gettext("CPU performance counter interface"), ccp); 168 169 (void) fprintf(args->fp, gettext("\tevent specification syntax:\n")); 170 171 (void) fprintf(args->fp, "\t[picn=]<eventn>[,attr[n][=<val>]]" 172 "[,[picn=]<eventn>[,attr[n][=<val>]],...]\n"); 173 174 (void) fprintf(args->fp, gettext("\n\tGeneric Events:\n")); 175 176 if (pics_equal) { 177 args->margin = args->colnum = EVENT_MARGIN; 178 (void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1); 179 cpc_walk_generic_events_pic(cpc, 0, args, list_cap); 180 (void) fprintf(args->fp, "\n"); 181 } else { 182 args->margin = EVENT_MARGIN; 183 for (i = 0; i < npic; i++) { 184 (void) fprintf(args->fp, "\n\tevent%d: ", i); 185 if (i < 10) (void) fprintf(args->fp, " "); 186 args->colnum = EVENT_MARGIN; 187 cpc_walk_generic_events_pic(cpc, i, args, list_cap); 188 (void) fprintf(args->fp, "\n"); 189 } 190 } 191 192 (void) fprintf(args->fp, gettext("\n\tSee generic_events(3CPC) for" 193 " descriptions of these events\n\n")); 194 195 (void) fprintf(args->fp, gettext("\tPlatform Specific Events:\n")); 196 197 if (pics_equal) { 198 args->margin = args->colnum = EVENT_MARGIN; 199 (void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1); 200 cpc_walk_events_pic(cpc, 0, args, list_cap); 201 (void) fprintf(args->fp, "\n"); 202 } else { 203 args->margin = EVENT_MARGIN; 204 for (i = 0; i < npic; i++) { 205 (void) fprintf(args->fp, "\n\tevent%d: ", i); 206 if (i < 10) (void) fprintf(args->fp, " "); 207 args->colnum = EVENT_MARGIN; 208 cpc_walk_events_pic(cpc, i, args, list_cap); 209 (void) fprintf(args->fp, "\n"); 210 } 211 } 212 213 (void) fprintf(args->fp, "\n\tattributes: "); 214 args->colnum = args->margin = ATTR_MARGIN; 215 cpc_walk_attrs(cpc, args, list_attr); 216 /* 217 * In addition to the attributes published by the kernel, we allow the 218 * user to specify two additional tokens on all platforms. List them 219 * here. 220 */ 221 list_cap(args, 0, "nouser"); 222 list_cap(args, 0, "sys"); 223 (void) fprintf(args->fp, "\n\n\t"); 224 args->colnum = 8; 225 226 if ((ccp = cpc_cpuref(cpc)) == NULL) 227 ccp = "No information available"; 228 if ((text = strdup(ccp)) == NULL) { 229 (void) fprintf(stderr, gettext("no memory available.\n")); 230 exit(1); 231 } 232 for (cp = strtok_r(text, " ", &tok); 233 cp != NULL; cp = strtok_r(NULL, " ", &tok)) { 234 if ((args->colnum + strlen(cp) + 1) > MAX_RHS_COLUMN) { 235 (void) fprintf(args->fp, "\n\t"); 236 args->colnum = 8; 237 } 238 args->colnum += fprintf(args->fp, "%s ", cp); 239 } 240 (void) fprintf(args->fp, "\n"); 241 free(text); 242 243 return (0); 244 } 245 246 /* 247 * Returns 1 on SMT processors which do not have full CPC hardware for each 248 * logical processor. 249 */ 250 int 251 smt_limited_cpc_hw(cpc_t *cpc) 252 { 253 if (strcmp(cpc_cciname(cpc), "Pentium 4 with HyperThreading") == 0) 254 return (1); 255 return (0); 256 } 257