caps.c revision c7a079a873b863c236656bd0db7b2cf390841b4d
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#define __EXTENSIONS__ /* header bug! strtok_r is overly hidden */
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <libintl.h>
2N/A
2N/A#include <libcpc.h>
2N/A
2N/A#include "cpucmds.h"
2N/A
2N/Astruct args {
2N/A FILE *fp;
2N/A int colnum;
2N/A int margin;
2N/A};
2N/A
2N/Astruct evlist {
2N/A char *list;
2N/A int size;
2N/A};
2N/A
2N/A#define MAX_RHS_COLUMN 76
2N/A#define EVENT_MARGIN 17
2N/A#define ATTR_MARGIN 20
2N/A
2N/A/*ARGSUSED*/
2N/Astatic void
2N/Alist_cap(void *arg, uint_t regno, const char *name)
2N/A{
2N/A struct args *args = arg;
2N/A int i;
2N/A
2N/A if ((args->colnum + strlen(name) + 1) > MAX_RHS_COLUMN) {
2N/A (void) fprintf(args->fp, "\n");
2N/A for (i = 0; i < args->margin; i++)
2N/A (void) fprintf(args->fp, " ");
2N/A args->colnum = args->margin;
2N/A }
2N/A args->colnum += fprintf(args->fp, "%s ", name);
2N/A}
2N/A
2N/Astatic void
2N/Alist_attr(void *arg, const char *name)
2N/A{
2N/A /*
2N/A * The following attributes are used by the commands but should not be
2N/A * reported to the user, since they may not be specified directly.
2N/A */
2N/A if (strncmp(name, "picnum", 7) == 0 ||
2N/A strncmp(name, "count_sibling_usr", 18) == 0 ||
2N/A strncmp(name, "count_sibling_sys", 18) == 0)
2N/A return;
2N/A
2N/A list_cap(arg, 0, name);
2N/A}
2N/A
2N/Astatic void *
2N/Aemalloc(size_t size)
2N/A{
2N/A void *ptr;
2N/A
2N/A if ((ptr = malloc(size)) == NULL) {
2N/A (void) fprintf(stderr, gettext("no memory available\n"));
2N/A exit(1);
2N/A }
2N/A
2N/A return (ptr);
2N/A}
2N/A
2N/A/*
2N/A * Used by allpics_equal().
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic void
2N/Acap_walker(void *arg, uint_t regno, const char *name)
2N/A{
2N/A struct evlist *list = arg;
2N/A
2N/A list->size += strlen(name);
2N/A if ((list->list = realloc(list->list, list->size + 1)) == NULL) {
2N/A (void) fprintf(stderr, gettext("no memory available\n"));
2N/A exit(1);
2N/A }
2N/A
2N/A (void) strcat(list->list, name);
2N/A}
2N/A
2N/A/*
2N/A * Returns 1 if all counters on this chip can count all possible events.
2N/A */
2N/Astatic int
2N/Aallpics_equal(cpc_t *cpc)
2N/A{
2N/A int npics = cpc_npic(cpc);
2N/A int i;
2N/A struct evlist **lists;
2N/A int ret = 1;
2N/A
2N/A lists = emalloc(npics * sizeof (struct evlist *));
2N/A
2N/A for (i = 0; i < npics; i++) {
2N/A lists[i] = emalloc(sizeof (struct evlist));
2N/A lists[i]->size = 0;
2N/A lists[i]->list = emalloc(1);
2N/A lists[i]->list[0] = '\0';
2N/A cpc_walk_events_pic(cpc, i, lists[i], cap_walker);
2N/A }
2N/A
2N/A for (i = 1; i < npics; i++)
2N/A if (lists[i]->size != lists[0]->size ||
2N/A strncmp(lists[i]->list, lists[0]->list,
2N/A lists[0]->size) != 0) {
2N/A ret = 0;
2N/A break;
2N/A }
2N/A
2N/A for (i = 0; i < npics; i++) {
2N/A free(lists[i]->list);
2N/A free(lists[i]);
2N/A }
2N/A free(lists);
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/Aint
2N/Acapabilities(cpc_t *cpc, FILE *fp)
2N/A{
2N/A struct args _args, *args = &_args;
2N/A char *text, *tok, *cp;
2N/A const char *ccp;
2N/A int npic = cpc_npic(cpc);
2N/A int i, pics_equal = allpics_equal(cpc);
2N/A
2N/A args->fp = fp;
2N/A
2N/A if ((ccp = cpc_cciname(cpc)) == NULL)
2N/A ccp = "No information available";
2N/A (void) fprintf(args->fp, "\t%s: %s\n\n",
2N/A gettext("CPU performance counter interface"), ccp);
2N/A
2N/A (void) fprintf(args->fp, gettext("\tevent specification syntax:\n"));
2N/A
2N/A (void) fprintf(args->fp, "\t[picn=]<eventn>[,attr[n][=<val>]]"
2N/A "[,[picn=]<eventn>[,attr[n][=<val>]],...]\n");
2N/A
2N/A (void) fprintf(args->fp, gettext("\n\tGeneric Events:\n"));
2N/A
2N/A if (pics_equal) {
2N/A args->margin = args->colnum = EVENT_MARGIN;
2N/A (void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1);
2N/A cpc_walk_generic_events_pic(cpc, 0, args, list_cap);
2N/A (void) fprintf(args->fp, "\n");
2N/A } else {
2N/A args->margin = EVENT_MARGIN;
2N/A for (i = 0; i < npic; i++) {
2N/A (void) fprintf(args->fp, "\n\tevent%d: ", i);
2N/A if (i < 10) (void) fprintf(args->fp, " ");
2N/A args->colnum = EVENT_MARGIN;
2N/A cpc_walk_generic_events_pic(cpc, i, args, list_cap);
2N/A (void) fprintf(args->fp, "\n");
2N/A }
2N/A }
2N/A
2N/A (void) fprintf(args->fp, gettext("\n\tSee generic_events(3CPC) for"
2N/A " descriptions of these events\n\n"));
2N/A
2N/A (void) fprintf(args->fp, gettext("\tPlatform Specific Events:\n"));
2N/A
2N/A if (pics_equal) {
2N/A args->margin = args->colnum = EVENT_MARGIN;
2N/A (void) fprintf(args->fp, "\n\tevent[0-%d]: ", npic - 1);
2N/A cpc_walk_events_pic(cpc, 0, args, list_cap);
2N/A (void) fprintf(args->fp, "\n");
2N/A } else {
2N/A args->margin = EVENT_MARGIN;
2N/A for (i = 0; i < npic; i++) {
2N/A (void) fprintf(args->fp, "\n\tevent%d: ", i);
2N/A if (i < 10) (void) fprintf(args->fp, " ");
2N/A args->colnum = EVENT_MARGIN;
2N/A cpc_walk_events_pic(cpc, i, args, list_cap);
2N/A (void) fprintf(args->fp, "\n");
2N/A }
2N/A }
2N/A
2N/A (void) fprintf(args->fp, "\n\tattributes: ");
2N/A args->colnum = args->margin = ATTR_MARGIN;
2N/A cpc_walk_attrs(cpc, args, list_attr);
2N/A /*
2N/A * In addition to the attributes published by the kernel, we allow the
2N/A * user to specify two additional tokens on all platforms. List them
2N/A * here.
2N/A */
2N/A list_cap(args, 0, "nouser");
2N/A list_cap(args, 0, "sys");
2N/A (void) fprintf(args->fp, "\n\n\t");
2N/A args->colnum = 8;
2N/A
2N/A if ((ccp = cpc_cpuref(cpc)) == NULL)
2N/A ccp = "No information available";
2N/A if ((text = strdup(ccp)) == NULL) {
2N/A (void) fprintf(stderr, gettext("no memory available.\n"));
2N/A exit(1);
2N/A }
2N/A for (cp = strtok_r(text, " ", &tok);
2N/A cp != NULL; cp = strtok_r(NULL, " ", &tok)) {
2N/A if ((args->colnum + strlen(cp) + 1) > MAX_RHS_COLUMN) {
2N/A (void) fprintf(args->fp, "\n\t");
2N/A args->colnum = 8;
2N/A }
2N/A args->colnum += fprintf(args->fp, "%s ", cp);
2N/A }
2N/A (void) fprintf(args->fp, "\n");
2N/A free(text);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Returns 1 on SMT processors which do not have full CPC hardware for each
2N/A * logical processor.
2N/A */
2N/Aint
2N/Asmt_limited_cpc_hw(cpc_t *cpc)
2N/A{
2N/A if (strcmp(cpc_cciname(cpc), "Pentium 4 with HyperThreading") == 0)
2N/A return (1);
2N/A return (0);
2N/A}
2N/A