10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7640SJonathan.Haslam@Sun.COM * Common Development and Distribution License (the "License"). 6*7640SJonathan.Haslam@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*7640SJonathan.Haslam@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #define __EXTENSIONS__ /* header bug! strtok_r is overly hidden */ 270Sstevel@tonic-gate #include <string.h> 280Sstevel@tonic-gate #include <strings.h> 290Sstevel@tonic-gate #include <stdio.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <unistd.h> 320Sstevel@tonic-gate #include <libintl.h> 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include <libcpc.h> 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include "cpucmds.h" 370Sstevel@tonic-gate 380Sstevel@tonic-gate struct args { 390Sstevel@tonic-gate FILE *fp; 400Sstevel@tonic-gate int colnum; 410Sstevel@tonic-gate int margin; 420Sstevel@tonic-gate }; 430Sstevel@tonic-gate 440Sstevel@tonic-gate struct evlist { 450Sstevel@tonic-gate char *list; 460Sstevel@tonic-gate int size; 470Sstevel@tonic-gate }; 480Sstevel@tonic-gate 490Sstevel@tonic-gate #define MAX_RHS_COLUMN 76 500Sstevel@tonic-gate #define EVENT_MARGIN 17 510Sstevel@tonic-gate #define ATTR_MARGIN 20 520Sstevel@tonic-gate 530Sstevel@tonic-gate /*ARGSUSED*/ 540Sstevel@tonic-gate static void 550Sstevel@tonic-gate list_cap(void *arg, uint_t regno, const char *name) 560Sstevel@tonic-gate { 570Sstevel@tonic-gate struct args *args = arg; 580Sstevel@tonic-gate int i; 590Sstevel@tonic-gate 600Sstevel@tonic-gate if ((args->colnum + strlen(name) + 1) > MAX_RHS_COLUMN) { 610Sstevel@tonic-gate (void) fprintf(args->fp, "\n"); 620Sstevel@tonic-gate for (i = 0; i < args->margin; i++) 630Sstevel@tonic-gate (void) fprintf(args->fp, " "); 640Sstevel@tonic-gate args->colnum = args->margin; 650Sstevel@tonic-gate } 660Sstevel@tonic-gate args->colnum += fprintf(args->fp, "%s ", name); 670Sstevel@tonic-gate } 680Sstevel@tonic-gate 690Sstevel@tonic-gate static void 700Sstevel@tonic-gate list_attr(void *arg, const char *name) 710Sstevel@tonic-gate { 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * The following attributes are used by the commands but should not be 740Sstevel@tonic-gate * reported to the user, since they may not be specified directly. 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate if (strncmp(name, "picnum", 7) == 0 || 770Sstevel@tonic-gate strncmp(name, "count_sibling_usr", 18) == 0 || 780Sstevel@tonic-gate strncmp(name, "count_sibling_sys", 18) == 0) 790Sstevel@tonic-gate return; 800Sstevel@tonic-gate 810Sstevel@tonic-gate list_cap(arg, 0, name); 820Sstevel@tonic-gate } 830Sstevel@tonic-gate 840Sstevel@tonic-gate static void * 850Sstevel@tonic-gate emalloc(size_t size) 860Sstevel@tonic-gate { 870Sstevel@tonic-gate void *ptr; 880Sstevel@tonic-gate 890Sstevel@tonic-gate if ((ptr = malloc(size)) == NULL) { 900Sstevel@tonic-gate (void) fprintf(stderr, gettext("no memory available\n")); 910Sstevel@tonic-gate exit(1); 920Sstevel@tonic-gate } 930Sstevel@tonic-gate 940Sstevel@tonic-gate return (ptr); 950Sstevel@tonic-gate } 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * Used by allpics_equal(). 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate /*ARGSUSED*/ 1010Sstevel@tonic-gate static void 1020Sstevel@tonic-gate cap_walker(void *arg, uint_t regno, const char *name) 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate struct evlist *list = arg; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate list->size += strlen(name); 1070Sstevel@tonic-gate if ((list->list = realloc(list->list, list->size + 1)) == NULL) { 1080Sstevel@tonic-gate (void) fprintf(stderr, gettext("no memory available\n")); 1090Sstevel@tonic-gate exit(1); 1100Sstevel@tonic-gate } 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate (void) strcat(list->list, name); 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate /* 1160Sstevel@tonic-gate * Returns 1 if all counters on this chip can count all possible events. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate static int 1190Sstevel@tonic-gate allpics_equal(cpc_t *cpc) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate int npics = cpc_npic(cpc); 1220Sstevel@tonic-gate int i; 1230Sstevel@tonic-gate struct evlist **lists; 1240Sstevel@tonic-gate int ret = 1; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate lists = emalloc(npics * sizeof (struct evlist *)); 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate for (i = 0; i < npics; i++) { 1290Sstevel@tonic-gate lists[i] = emalloc(sizeof (struct evlist)); 1300Sstevel@tonic-gate lists[i]->size = 0; 1310Sstevel@tonic-gate lists[i]->list = emalloc(1); 1320Sstevel@tonic-gate lists[i]->list[0] = '\0'; 1330Sstevel@tonic-gate cpc_walk_events_pic(cpc, i, lists[i], cap_walker); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate for (i = 1; i < npics; i++) 1370Sstevel@tonic-gate if (lists[i]->size != lists[0]->size || 1380Sstevel@tonic-gate strncmp(lists[i]->list, lists[0]->list, 139*7640SJonathan.Haslam@Sun.COM lists[0]->size) != 0) { 1400Sstevel@tonic-gate ret = 0; 1410Sstevel@tonic-gate break; 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate for (i = 0; i < npics; i++) { 1450Sstevel@tonic-gate free(lists[i]->list); 1460Sstevel@tonic-gate free(lists[i]); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate free(lists); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate return (ret); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate int 1540Sstevel@tonic-gate capabilities(cpc_t *cpc, FILE *fp) 1550Sstevel@tonic-gate { 1560Sstevel@tonic-gate struct args _args, *args = &_args; 1570Sstevel@tonic-gate char *text, *tok, *cp; 1580Sstevel@tonic-gate const char *ccp; 1590Sstevel@tonic-gate int npic = cpc_npic(cpc); 160*7640SJonathan.Haslam@Sun.COM int i, pics_equal = allpics_equal(cpc); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate args->fp = fp; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate if ((ccp = cpc_cciname(cpc)) == NULL) 1650Sstevel@tonic-gate ccp = "No information available"; 1660Sstevel@tonic-gate (void) fprintf(args->fp, "\t%s: %s\n\n", 1670Sstevel@tonic-gate gettext("CPU performance counter interface"), ccp); 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate (void) fprintf(args->fp, gettext("\tevent specification syntax:\n")); 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate (void) fprintf(args->fp, "\t[picn=]<eventn>[,attr[n][=<val>]]" 1720Sstevel@tonic-gate "[,[picn=]<eventn>[,attr[n][=<val>]],...]\n"); 1730Sstevel@tonic-gate 174*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, gettext("\n\tGeneric Events:\n")); 175*7640SJonathan.Haslam@Sun.COM 176*7640SJonathan.Haslam@Sun.COM if (pics_equal) { 177*7640SJonathan.Haslam@Sun.COM args->margin = args->colnum = EVENT_MARGIN; 178*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1); 179*7640SJonathan.Haslam@Sun.COM cpc_walk_generic_events_pic(cpc, 0, args, list_cap); 180*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, "\n"); 181*7640SJonathan.Haslam@Sun.COM } else { 182*7640SJonathan.Haslam@Sun.COM args->margin = EVENT_MARGIN; 183*7640SJonathan.Haslam@Sun.COM for (i = 0; i < npic; i++) { 184*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, "\n\tevent%d: ", i); 185*7640SJonathan.Haslam@Sun.COM if (i < 10) (void) fprintf(args->fp, " "); 186*7640SJonathan.Haslam@Sun.COM args->colnum = EVENT_MARGIN; 187*7640SJonathan.Haslam@Sun.COM cpc_walk_generic_events_pic(cpc, i, args, list_cap); 188*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, "\n"); 189*7640SJonathan.Haslam@Sun.COM } 190*7640SJonathan.Haslam@Sun.COM } 191*7640SJonathan.Haslam@Sun.COM 192*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, gettext("\n\tSee generic_events(3CPC) for" 193*7640SJonathan.Haslam@Sun.COM " descriptions of these events\n\n")); 194*7640SJonathan.Haslam@Sun.COM 195*7640SJonathan.Haslam@Sun.COM (void) fprintf(args->fp, gettext("\tPlatform Specific Events:\n")); 196*7640SJonathan.Haslam@Sun.COM 197*7640SJonathan.Haslam@Sun.COM if (pics_equal) { 1980Sstevel@tonic-gate args->margin = args->colnum = EVENT_MARGIN; 1990Sstevel@tonic-gate (void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1); 2000Sstevel@tonic-gate cpc_walk_events_pic(cpc, 0, args, list_cap); 2010Sstevel@tonic-gate (void) fprintf(args->fp, "\n"); 2020Sstevel@tonic-gate } else { 2030Sstevel@tonic-gate args->margin = EVENT_MARGIN; 2040Sstevel@tonic-gate for (i = 0; i < npic; i++) { 2050Sstevel@tonic-gate (void) fprintf(args->fp, "\n\tevent%d: ", i); 2060Sstevel@tonic-gate if (i < 10) (void) fprintf(args->fp, " "); 2070Sstevel@tonic-gate args->colnum = EVENT_MARGIN; 2080Sstevel@tonic-gate cpc_walk_events_pic(cpc, i, args, list_cap); 2090Sstevel@tonic-gate (void) fprintf(args->fp, "\n"); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate } 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate (void) fprintf(args->fp, "\n\tattributes: "); 2140Sstevel@tonic-gate args->colnum = args->margin = ATTR_MARGIN; 2150Sstevel@tonic-gate cpc_walk_attrs(cpc, args, list_attr); 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * In addition to the attributes published by the kernel, we allow the 2180Sstevel@tonic-gate * user to specify two additional tokens on all platforms. List them 2190Sstevel@tonic-gate * here. 2200Sstevel@tonic-gate */ 2210Sstevel@tonic-gate list_cap(args, 0, "nouser"); 2220Sstevel@tonic-gate list_cap(args, 0, "sys"); 2230Sstevel@tonic-gate (void) fprintf(args->fp, "\n\n\t"); 2240Sstevel@tonic-gate args->colnum = 8; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if ((ccp = cpc_cpuref(cpc)) == NULL) 2270Sstevel@tonic-gate ccp = "No information available"; 2280Sstevel@tonic-gate if ((text = strdup(ccp)) == NULL) { 2290Sstevel@tonic-gate (void) fprintf(stderr, gettext("no memory available.\n")); 2300Sstevel@tonic-gate exit(1); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate for (cp = strtok_r(text, " ", &tok); 2330Sstevel@tonic-gate cp != NULL; cp = strtok_r(NULL, " ", &tok)) { 2340Sstevel@tonic-gate if ((args->colnum + strlen(cp) + 1) > MAX_RHS_COLUMN) { 2350Sstevel@tonic-gate (void) fprintf(args->fp, "\n\t"); 2360Sstevel@tonic-gate args->colnum = 8; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate args->colnum += fprintf(args->fp, "%s ", cp); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate (void) fprintf(args->fp, "\n"); 2410Sstevel@tonic-gate free(text); 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate return (0); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * Returns 1 on SMT processors which do not have full CPC hardware for each 2480Sstevel@tonic-gate * logical processor. 2490Sstevel@tonic-gate */ 2500Sstevel@tonic-gate int 2510Sstevel@tonic-gate smt_limited_cpc_hw(cpc_t *cpc) 2520Sstevel@tonic-gate { 2530Sstevel@tonic-gate if (strcmp(cpc_cciname(cpc), "Pentium 4 with HyperThreading") == 0) 2540Sstevel@tonic-gate return (1); 2550Sstevel@tonic-gate return (0); 2560Sstevel@tonic-gate } 257