1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Routines to capture processor-dependencies in event specification. 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <strings.h> 36*0Sstevel@tonic-gate #include <alloca.h> 37*0Sstevel@tonic-gate #include <stdlib.h> 38*0Sstevel@tonic-gate #include <stdio.h> 39*0Sstevel@tonic-gate #include <libintl.h> 40*0Sstevel@tonic-gate #include <assert.h> 41*0Sstevel@tonic-gate #include <errno.h> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate #include "libcpc.h" 44*0Sstevel@tonic-gate #include "libcpc_impl.h" 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* 47*0Sstevel@tonic-gate * Event specifications for Pentium performance counters are based 48*0Sstevel@tonic-gate * on the content of a getsubopt-like string. 49*0Sstevel@tonic-gate * The string should contain something that looks like this: 50*0Sstevel@tonic-gate * 51*0Sstevel@tonic-gate * pic0=<eventspec>,pic1=<eventspec> 52*0Sstevel@tonic-gate * [,cmask0=<maskspec>][,cmask1=<maskspec>] 53*0Sstevel@tonic-gate * [,umask0=<maskspec>][,umask1=<maskspec>] 54*0Sstevel@tonic-gate * [,inv[0|1]][,noedge[0|1]] 55*0Sstevel@tonic-gate * [,sys[0|1]][,nouser[0|1]] 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * For example: 58*0Sstevel@tonic-gate * pic0=data_mem_refs,pic1=l2_ld,sys 59*0Sstevel@tonic-gate * or 60*0Sstevel@tonic-gate * pic0=l2_ld,pic1=bus_drdy_clocks,umask1=0x20,nouser1 61*0Sstevel@tonic-gate * 62*0Sstevel@tonic-gate * By default, user event counting is enabled, system event counting 63*0Sstevel@tonic-gate * is disabled. 64*0Sstevel@tonic-gate * 65*0Sstevel@tonic-gate * Note that Pentium and Pentium Pro have different event specifications. 66*0Sstevel@tonic-gate * 67*0Sstevel@tonic-gate * The two events must be named. The names can be ascii or 68*0Sstevel@tonic-gate * a decimal, octal or hexadecimal number as parsed by strtol(3C). 69*0Sstevel@tonic-gate * 70*0Sstevel@tonic-gate * The routine counts the number of errors encountered while parsing 71*0Sstevel@tonic-gate * the string, if no errors are encountered, the event handle is 72*0Sstevel@tonic-gate * returned. 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate const char * 76*0Sstevel@tonic-gate cpc_getusage(int cpuver) 77*0Sstevel@tonic-gate { 78*0Sstevel@tonic-gate switch (cpuver) { 79*0Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 80*0Sstevel@tonic-gate case CPC_PENTIUM_PRO: 81*0Sstevel@tonic-gate return ("pic0=<event0>,pic1=<event1> " 82*0Sstevel@tonic-gate "[,sys[0|1]] " 83*0Sstevel@tonic-gate "[,nouser[0|1]] " 84*0Sstevel@tonic-gate "[,noedge[0|1]] " 85*0Sstevel@tonic-gate "[,pc[0|1]] " 86*0Sstevel@tonic-gate "[,int[0|1]] " 87*0Sstevel@tonic-gate "[,inv[0|1]] " 88*0Sstevel@tonic-gate "[,cmask[0|1]=<maskspec>] " 89*0Sstevel@tonic-gate "[,umask[0|1]=<maskspec>] "); 90*0Sstevel@tonic-gate case CPC_PENTIUM_MMX: 91*0Sstevel@tonic-gate case CPC_PENTIUM: 92*0Sstevel@tonic-gate return ("pic0=<event0>,pic1=<event1> " 93*0Sstevel@tonic-gate "[,sys[0|1]] " 94*0Sstevel@tonic-gate "[,nouser[0|1]] " 95*0Sstevel@tonic-gate "[,noedge[0|1]] " 96*0Sstevel@tonic-gate "[,pc[0|1]]"); 97*0Sstevel@tonic-gate default: 98*0Sstevel@tonic-gate return (NULL); 99*0Sstevel@tonic-gate } 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate struct keyval { 103*0Sstevel@tonic-gate char *kv_token; 104*0Sstevel@tonic-gate int (*kv_action)(const char *, 105*0Sstevel@tonic-gate const struct keyval *, int, char *, uint32_t *); 106*0Sstevel@tonic-gate uint_t kv_regno; 107*0Sstevel@tonic-gate uint32_t kv_mask; 108*0Sstevel@tonic-gate int kv_shift; 109*0Sstevel@tonic-gate }; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate /*ARGSUSED*/ 112*0Sstevel@tonic-gate static int 113*0Sstevel@tonic-gate eightbits(const char *fn, 114*0Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate char *eptr = NULL; 117*0Sstevel@tonic-gate long l; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate if (value == NULL) { 120*0Sstevel@tonic-gate __cpc_error(fn, gettext("missing '%s' value\n"), 121*0Sstevel@tonic-gate kv->kv_token); 122*0Sstevel@tonic-gate return (-1); 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate l = strtol(value, &eptr, 0); 125*0Sstevel@tonic-gate if (value == eptr || l < 0 || l > UINT8_MAX) { 126*0Sstevel@tonic-gate __cpc_error(fn, gettext("bad '%s' value\n"), kv->kv_token); 127*0Sstevel@tonic-gate return (-1); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate bits[kv->kv_regno] |= ((uint8_t)l & kv->kv_mask) << kv->kv_shift; 130*0Sstevel@tonic-gate return (0); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate static int 134*0Sstevel@tonic-gate picbits(const char *fn, 135*0Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 136*0Sstevel@tonic-gate { 137*0Sstevel@tonic-gate uint8_t val8; 138*0Sstevel@tonic-gate uint_t regno; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate if (value == NULL) { 143*0Sstevel@tonic-gate __cpc_error(fn, gettext("missing '%s' value\n"), 144*0Sstevel@tonic-gate kv->kv_token); 145*0Sstevel@tonic-gate return (-1); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) { 149*0Sstevel@tonic-gate switch (cpuver) { 150*0Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 151*0Sstevel@tonic-gate case CPC_PENTIUM_PRO: 152*0Sstevel@tonic-gate assert(kv->kv_regno == regno); 153*0Sstevel@tonic-gate __cpc_error(fn, gettext( 154*0Sstevel@tonic-gate "PerfCtr%d cannot measure '%s' on this cpu\n"), 155*0Sstevel@tonic-gate regno, value); 156*0Sstevel@tonic-gate break; 157*0Sstevel@tonic-gate case CPC_PENTIUM_MMX: 158*0Sstevel@tonic-gate case CPC_PENTIUM: 159*0Sstevel@tonic-gate assert(kv->kv_regno == 0); 160*0Sstevel@tonic-gate __cpc_error(fn, gettext( 161*0Sstevel@tonic-gate "CTR%d cannot measure '%s' on this cpu\n"), 162*0Sstevel@tonic-gate regno, value); 163*0Sstevel@tonic-gate break; 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate return (-1); 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate bits[kv->kv_regno] |= (val8 & kv->kv_mask) << kv->kv_shift; 168*0Sstevel@tonic-gate return (0); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /*ARGSUSED2*/ 172*0Sstevel@tonic-gate static int 173*0Sstevel@tonic-gate bitclr(const char *fn, 174*0Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 175*0Sstevel@tonic-gate { 176*0Sstevel@tonic-gate if (value != NULL) { 177*0Sstevel@tonic-gate __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 178*0Sstevel@tonic-gate return (-1); 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate bits[kv->kv_regno] &= ~(kv->kv_mask << kv->kv_shift); 181*0Sstevel@tonic-gate return (0); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /*ARGSUSED2*/ 185*0Sstevel@tonic-gate static int 186*0Sstevel@tonic-gate bitset(const char *fn, 187*0Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 188*0Sstevel@tonic-gate { 189*0Sstevel@tonic-gate if (value != NULL) { 190*0Sstevel@tonic-gate __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 191*0Sstevel@tonic-gate return (-1); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate bits[kv->kv_regno] |= (kv->kv_mask << kv->kv_shift); 194*0Sstevel@tonic-gate return (0); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate static int 198*0Sstevel@tonic-gate nextpair(const char *fn, 199*0Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 200*0Sstevel@tonic-gate { 201*0Sstevel@tonic-gate int rv; 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate if (value != NULL) { 204*0Sstevel@tonic-gate __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 205*0Sstevel@tonic-gate return (-1); 206*0Sstevel@tonic-gate } 207*0Sstevel@tonic-gate kv++; 208*0Sstevel@tonic-gate if ((rv = kv->kv_action(fn, kv, cpuver, value, bits)) != 0) 209*0Sstevel@tonic-gate return (rv); 210*0Sstevel@tonic-gate kv++; 211*0Sstevel@tonic-gate return (kv->kv_action(fn, kv, cpuver, value, bits)); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * This token table must match the keyval tables below. 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate static char * const tokens[] = { 219*0Sstevel@tonic-gate #define D_pic0 0 220*0Sstevel@tonic-gate "pic0", /* takes a valid event name */ 221*0Sstevel@tonic-gate #define D_pic1 1 222*0Sstevel@tonic-gate "pic1", /* takes a valid event name */ 223*0Sstevel@tonic-gate #define D_nouser 2 224*0Sstevel@tonic-gate "nouser", /* disables user counts */ 225*0Sstevel@tonic-gate #define D_nouser0 3 226*0Sstevel@tonic-gate "nouser0", 227*0Sstevel@tonic-gate #define D_nouser1 4 228*0Sstevel@tonic-gate "nouser1", 229*0Sstevel@tonic-gate #define D_sys 5 230*0Sstevel@tonic-gate "sys", /* enables system counts */ 231*0Sstevel@tonic-gate #define D_sys0 6 232*0Sstevel@tonic-gate "sys0", 233*0Sstevel@tonic-gate #define D_sys1 7 234*0Sstevel@tonic-gate "sys1", 235*0Sstevel@tonic-gate #define D_noedge 8 236*0Sstevel@tonic-gate "noedge", /* disable edge detect */ 237*0Sstevel@tonic-gate #define D_noedge0 9 238*0Sstevel@tonic-gate "noedge0", 239*0Sstevel@tonic-gate #define D_noedge1 10 240*0Sstevel@tonic-gate "noedge1", 241*0Sstevel@tonic-gate #define D_pc 11 242*0Sstevel@tonic-gate "pc", /* sets pin control high */ 243*0Sstevel@tonic-gate #define D_pc0 12 244*0Sstevel@tonic-gate "pc0", 245*0Sstevel@tonic-gate #define D_pc1 13 246*0Sstevel@tonic-gate "pc1", 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /* 249*0Sstevel@tonic-gate * These additional keywords are for Pentium Pro / Pentium II machines. 250*0Sstevel@tonic-gate */ 251*0Sstevel@tonic-gate #define D_int 14 252*0Sstevel@tonic-gate "int", /* enable interrupt on counter overflow */ 253*0Sstevel@tonic-gate #define D_int0 15 254*0Sstevel@tonic-gate "int0", 255*0Sstevel@tonic-gate #define D_int1 16 256*0Sstevel@tonic-gate "int1", 257*0Sstevel@tonic-gate #define D_inv 17 258*0Sstevel@tonic-gate "inv", /* invert cmask comparison */ 259*0Sstevel@tonic-gate #define D_inv0 18 260*0Sstevel@tonic-gate "inv0", 261*0Sstevel@tonic-gate #define D_inv1 19 262*0Sstevel@tonic-gate "inv1", 263*0Sstevel@tonic-gate #define D_umask0 20 264*0Sstevel@tonic-gate "umask0", /* PerfCtr0 unit mask */ 265*0Sstevel@tonic-gate #define D_umask1 21 266*0Sstevel@tonic-gate "umask1", /* PerfCtr1 unit mask */ 267*0Sstevel@tonic-gate #define D_cmask0 22 268*0Sstevel@tonic-gate "cmask0", /* PerfCtr0 counter mask */ 269*0Sstevel@tonic-gate #define D_cmask1 23 270*0Sstevel@tonic-gate "cmask1", /* PerfCtr1 counter mask */ 271*0Sstevel@tonic-gate NULL 272*0Sstevel@tonic-gate }; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate static const struct keyval p6_keyvals[] = { 275*0Sstevel@tonic-gate { "pic0", picbits, 0, 276*0Sstevel@tonic-gate CPC_P6_PES_PIC0_MASK, 0 }, 277*0Sstevel@tonic-gate { "pic1", picbits, 1, 278*0Sstevel@tonic-gate CPC_P6_PES_PIC1_MASK, 0 }, 279*0Sstevel@tonic-gate { "nouser", nextpair }, 280*0Sstevel@tonic-gate { "nouser0", bitclr, 0, 281*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_USR }, 282*0Sstevel@tonic-gate { "nouser1", bitclr, 1, 283*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_USR }, 284*0Sstevel@tonic-gate { "sys", nextpair }, 285*0Sstevel@tonic-gate { "sys0", bitset, 0, 286*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_OS }, 287*0Sstevel@tonic-gate { "sys1", bitset, 1, 288*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_OS }, 289*0Sstevel@tonic-gate { "noedge", nextpair }, 290*0Sstevel@tonic-gate { "noedge0", bitclr, 0, 291*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_E }, 292*0Sstevel@tonic-gate { "noedge1", bitclr, 1, 293*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_E }, 294*0Sstevel@tonic-gate { "pc", nextpair }, 295*0Sstevel@tonic-gate { "pc0", bitset, 0, 296*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_PC }, 297*0Sstevel@tonic-gate { "pc1", bitset, 1, 298*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_PC }, 299*0Sstevel@tonic-gate { "int", nextpair }, 300*0Sstevel@tonic-gate { "int0", bitset, 0, 301*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INT }, 302*0Sstevel@tonic-gate { "int1", bitset, 1, 303*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INT }, 304*0Sstevel@tonic-gate { "inv", nextpair }, 305*0Sstevel@tonic-gate { "inv0", bitset, 0, 306*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INV }, 307*0Sstevel@tonic-gate { "inv1", bitset, 1, 308*0Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INV }, 309*0Sstevel@tonic-gate { "umask0", eightbits, 0, 310*0Sstevel@tonic-gate CPC_P6_PES_UMASK_MASK, CPC_P6_PES_UMASK_SHIFT }, 311*0Sstevel@tonic-gate { "umask1", eightbits, 1, 312*0Sstevel@tonic-gate CPC_P6_PES_UMASK_MASK, CPC_P6_PES_UMASK_SHIFT }, 313*0Sstevel@tonic-gate { "cmask0", eightbits, 0, 314*0Sstevel@tonic-gate CPC_P6_PES_CMASK_MASK, CPC_P6_PES_CMASK_SHIFT }, 315*0Sstevel@tonic-gate { "cmask1", eightbits, 1, 316*0Sstevel@tonic-gate CPC_P6_PES_CMASK_MASK, CPC_P6_PES_CMASK_SHIFT }, 317*0Sstevel@tonic-gate }; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Note that this table -must- be an identically indexed 321*0Sstevel@tonic-gate * subset of p6_keyvals. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate static const struct keyval p5_keyvals[] = { 324*0Sstevel@tonic-gate { "pic0", picbits, 0, 325*0Sstevel@tonic-gate CPC_P5_CESR_ES0_MASK, CPC_P5_CESR_ES0_SHIFT }, 326*0Sstevel@tonic-gate { "pic1", picbits, 0, 327*0Sstevel@tonic-gate CPC_P5_CESR_ES1_MASK, CPC_P5_CESR_ES1_SHIFT }, 328*0Sstevel@tonic-gate { "nouser", nextpair }, 329*0Sstevel@tonic-gate { "nouser0", bitclr, 0, 330*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_USR0 }, 331*0Sstevel@tonic-gate { "nouser1", bitclr, 0, 332*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_USR1 }, 333*0Sstevel@tonic-gate { "sys", nextpair }, 334*0Sstevel@tonic-gate { "sys0", bitset, 0, 335*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_OS0 }, 336*0Sstevel@tonic-gate { "sys1", bitset, 0, 337*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_OS1 }, 338*0Sstevel@tonic-gate { "noedge", nextpair }, 339*0Sstevel@tonic-gate { "noedge0", bitset, 0, 340*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_CLK0 }, 341*0Sstevel@tonic-gate { "noedge1", bitset, 0, 342*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_CLK1 }, 343*0Sstevel@tonic-gate { "pc", nextpair }, 344*0Sstevel@tonic-gate { "pc0", bitset, 0, 345*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_PC0 }, 346*0Sstevel@tonic-gate { "pc1", bitset, 0, 347*0Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_PC1 }, 348*0Sstevel@tonic-gate }; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate #if !defined(NDEBUG) 351*0Sstevel@tonic-gate #pragma init(__tablecheck) 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate static void 354*0Sstevel@tonic-gate __tablecheck(void) 355*0Sstevel@tonic-gate { 356*0Sstevel@tonic-gate uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1; 357*0Sstevel@tonic-gate uint_t p6_nkeys = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]); 358*0Sstevel@tonic-gate uint_t p5_nkeys = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]); 359*0Sstevel@tonic-gate uint_t n; 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate assert(ntokens == p6_nkeys); 362*0Sstevel@tonic-gate for (n = 0; n < ntokens; n++) 363*0Sstevel@tonic-gate assert(strcmp(tokens[n], p6_keyvals[n].kv_token) == 0); 364*0Sstevel@tonic-gate assert(p6_nkeys >= p5_nkeys); 365*0Sstevel@tonic-gate for (n = 0; n < p5_nkeys; n++) 366*0Sstevel@tonic-gate assert(strcmp(tokens[n], p5_keyvals[n].kv_token) == 0); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate #endif /* !NDEBUG */ 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate int 372*0Sstevel@tonic-gate cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event) 373*0Sstevel@tonic-gate { 374*0Sstevel@tonic-gate static const char fn[] = "strtoevent"; 375*0Sstevel@tonic-gate char *value; 376*0Sstevel@tonic-gate char *pic[2]; 377*0Sstevel@tonic-gate char *opts; 378*0Sstevel@tonic-gate int errcnt = 0; 379*0Sstevel@tonic-gate uint_t ntokens; 380*0Sstevel@tonic-gate const struct keyval *keyvals; 381*0Sstevel@tonic-gate uint32_t *bits; 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate if (spec == NULL) 384*0Sstevel@tonic-gate return (errcnt = 1); 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate bzero(event, sizeof (*event)); 387*0Sstevel@tonic-gate switch (event->ce_cpuver = cpuver) { 388*0Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 389*0Sstevel@tonic-gate case CPC_PENTIUM_PRO: 390*0Sstevel@tonic-gate keyvals = p6_keyvals; 391*0Sstevel@tonic-gate ntokens = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]); 392*0Sstevel@tonic-gate bits = &event->ce_pes[0]; 393*0Sstevel@tonic-gate bits[0] = bits[1] = 394*0Sstevel@tonic-gate (1u << CPC_P6_PES_USR) | (1u << CPC_P6_PES_E); 395*0Sstevel@tonic-gate break; 396*0Sstevel@tonic-gate case CPC_PENTIUM_MMX: 397*0Sstevel@tonic-gate case CPC_PENTIUM: 398*0Sstevel@tonic-gate keyvals = p5_keyvals; 399*0Sstevel@tonic-gate ntokens = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]); 400*0Sstevel@tonic-gate bits = &event->ce_cesr; 401*0Sstevel@tonic-gate bits[0] = 402*0Sstevel@tonic-gate (1u << CPC_P5_CESR_USR0) | (1u << CPC_P5_CESR_USR1); 403*0Sstevel@tonic-gate break; 404*0Sstevel@tonic-gate default: 405*0Sstevel@tonic-gate return (errcnt = 1); 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate pic[0] = pic[1] = NULL; 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate opts = strcpy(alloca(strlen(spec) + 1), spec); 411*0Sstevel@tonic-gate while (*opts != '\0') { 412*0Sstevel@tonic-gate const struct keyval *kv; 413*0Sstevel@tonic-gate int idx = getsubopt(&opts, tokens, &value); 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate if (idx >= 0 && idx < ntokens) { 416*0Sstevel@tonic-gate kv = &keyvals[idx]; 417*0Sstevel@tonic-gate if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) { 418*0Sstevel@tonic-gate errcnt++; 419*0Sstevel@tonic-gate break; 420*0Sstevel@tonic-gate } 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if (idx == D_pic0) { 423*0Sstevel@tonic-gate if (pic[0] != NULL) { 424*0Sstevel@tonic-gate __cpc_error(fn, 425*0Sstevel@tonic-gate "repeated '%s' token\n", 426*0Sstevel@tonic-gate tokens[idx]); 427*0Sstevel@tonic-gate errcnt++; 428*0Sstevel@tonic-gate break; 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate pic[0] = value; 431*0Sstevel@tonic-gate } else if (idx == D_pic1) { 432*0Sstevel@tonic-gate if (pic[1] != NULL) { 433*0Sstevel@tonic-gate __cpc_error(fn, 434*0Sstevel@tonic-gate "repeated '%s' token\n", 435*0Sstevel@tonic-gate tokens[idx]); 436*0Sstevel@tonic-gate errcnt++; 437*0Sstevel@tonic-gate break; 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate pic[1] = value; 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate } else if (idx == -1) { 442*0Sstevel@tonic-gate /* 443*0Sstevel@tonic-gate * The token given wasn't recognized. 444*0Sstevel@tonic-gate * See if it was an implicit pic specification.. 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate if (pic[0] == NULL) { 447*0Sstevel@tonic-gate kv = &keyvals[D_pic0]; 448*0Sstevel@tonic-gate if (kv->kv_action(fn, 449*0Sstevel@tonic-gate kv, cpuver, value, bits) != 0) { 450*0Sstevel@tonic-gate errcnt++; 451*0Sstevel@tonic-gate break; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate pic[0] = value; 454*0Sstevel@tonic-gate } else if (pic[1] == NULL) { 455*0Sstevel@tonic-gate kv = &keyvals[D_pic1]; 456*0Sstevel@tonic-gate if (kv->kv_action(fn, 457*0Sstevel@tonic-gate kv, cpuver, value, bits) != 0) { 458*0Sstevel@tonic-gate errcnt++; 459*0Sstevel@tonic-gate break; 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate pic[1] = value; 462*0Sstevel@tonic-gate } else { 463*0Sstevel@tonic-gate __cpc_error(fn, 464*0Sstevel@tonic-gate gettext("bad token '%s'\n"), value); 465*0Sstevel@tonic-gate errcnt++; 466*0Sstevel@tonic-gate break; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate } else { 469*0Sstevel@tonic-gate if (idx >= 0 && 470*0Sstevel@tonic-gate idx < sizeof (tokens) / sizeof (tokens[0])) 471*0Sstevel@tonic-gate __cpc_error(fn, 472*0Sstevel@tonic-gate gettext("bad token '%s'\n"), tokens[idx]); 473*0Sstevel@tonic-gate else 474*0Sstevel@tonic-gate __cpc_error(fn, gettext("bad token\n")); 475*0Sstevel@tonic-gate errcnt++; 476*0Sstevel@tonic-gate break; 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate if (pic[0] == NULL || pic[1] == NULL) { 481*0Sstevel@tonic-gate __cpc_error(fn, gettext("two events must be specified\n")); 482*0Sstevel@tonic-gate errcnt++; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate return (errcnt); 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate /* 489*0Sstevel@tonic-gate * Return a printable description of the control registers. 490*0Sstevel@tonic-gate * 491*0Sstevel@tonic-gate * This routine should always succeed (notwithstanding heap problems), 492*0Sstevel@tonic-gate * but may not be able to correctly decode the registers, if, for 493*0Sstevel@tonic-gate * example, a new processor is under test. 494*0Sstevel@tonic-gate * 495*0Sstevel@tonic-gate * The caller is responsible for free(3c)ing the string returned. 496*0Sstevel@tonic-gate */ 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate static void 499*0Sstevel@tonic-gate flagstostr(char *buf, int flag0, int flag1, int defvalue, char *tok) 500*0Sstevel@tonic-gate { 501*0Sstevel@tonic-gate buf += strlen(buf); 502*0Sstevel@tonic-gate if (flag0 != defvalue) { 503*0Sstevel@tonic-gate if (flag1 != defvalue) 504*0Sstevel@tonic-gate (void) sprintf(buf, ",%s", tok); 505*0Sstevel@tonic-gate else 506*0Sstevel@tonic-gate (void) sprintf(buf, ",%s0", tok); 507*0Sstevel@tonic-gate } else { 508*0Sstevel@tonic-gate if (flag1 != defvalue) 509*0Sstevel@tonic-gate (void) sprintf(buf, ",%s1", tok); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate static void 514*0Sstevel@tonic-gate masktostr(char *buf, uint8_t bits, char *tok) 515*0Sstevel@tonic-gate { 516*0Sstevel@tonic-gate if (bits != 0) { 517*0Sstevel@tonic-gate buf += strlen(buf); 518*0Sstevel@tonic-gate (void) sprintf(buf, ",%s=0x%x", tok, bits); 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate static char * 523*0Sstevel@tonic-gate val8tostr(uint8_t bits) 524*0Sstevel@tonic-gate { 525*0Sstevel@tonic-gate char buf[2 + 2 + 1]; /* 0x %2x \0 */ 526*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "0x%x", bits); 527*0Sstevel@tonic-gate return (strdup(buf)); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate static char * 531*0Sstevel@tonic-gate regtostr(int cpuver, int regno, uint8_t bits) 532*0Sstevel@tonic-gate { 533*0Sstevel@tonic-gate const char *sname; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL) 536*0Sstevel@tonic-gate return (strdup(sname)); 537*0Sstevel@tonic-gate return (val8tostr(bits)); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate struct xpes { 541*0Sstevel@tonic-gate uint8_t cmask, umask, evsel; 542*0Sstevel@tonic-gate int usr, sys, edge, inv, irupt, pc; 543*0Sstevel@tonic-gate }; 544*0Sstevel@tonic-gate 545*0Sstevel@tonic-gate /*ARGSUSED1*/ 546*0Sstevel@tonic-gate static void 547*0Sstevel@tonic-gate unmake_pes(uint32_t pes, int cpuver, struct xpes *xpes) 548*0Sstevel@tonic-gate { 549*0Sstevel@tonic-gate xpes->cmask = (uint8_t)(pes >> CPC_P6_PES_CMASK_SHIFT); 550*0Sstevel@tonic-gate xpes->pc = (pes >> CPC_P6_PES_PC) & 1u; 551*0Sstevel@tonic-gate xpes->inv = (pes >> CPC_P6_PES_INV) & 1u; 552*0Sstevel@tonic-gate xpes->irupt = (pes >> CPC_P6_PES_INT) & 1u; 553*0Sstevel@tonic-gate xpes->edge = (pes >> CPC_P6_PES_E) & 1u; 554*0Sstevel@tonic-gate xpes->sys = (pes >> CPC_P6_PES_OS) & 1u; 555*0Sstevel@tonic-gate xpes->usr = (pes >> CPC_P6_PES_USR) & 1u; 556*0Sstevel@tonic-gate xpes->umask = (uint8_t)(pes >> CPC_P6_PES_UMASK_SHIFT); 557*0Sstevel@tonic-gate xpes->evsel = (uint8_t)pes; 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate struct xcesr { 561*0Sstevel@tonic-gate uint8_t evsel[2]; 562*0Sstevel@tonic-gate int usr[2], sys[2], clk[2], pc[2]; 563*0Sstevel@tonic-gate }; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /*ARGSUSED1*/ 566*0Sstevel@tonic-gate static void 567*0Sstevel@tonic-gate unmake_cesr(uint32_t cesr, int cpuver, struct xcesr *xcesr) 568*0Sstevel@tonic-gate { 569*0Sstevel@tonic-gate xcesr->evsel[0] = (cesr >> CPC_P5_CESR_ES0_SHIFT) & 570*0Sstevel@tonic-gate CPC_P5_CESR_ES0_MASK; 571*0Sstevel@tonic-gate xcesr->evsel[1] = (cesr >> CPC_P5_CESR_ES1_SHIFT) & 572*0Sstevel@tonic-gate CPC_P5_CESR_ES1_MASK; 573*0Sstevel@tonic-gate xcesr->usr[0] = (cesr >> CPC_P5_CESR_USR0) & 1u; 574*0Sstevel@tonic-gate xcesr->usr[1] = (cesr >> CPC_P5_CESR_USR1) & 1u; 575*0Sstevel@tonic-gate xcesr->sys[0] = (cesr >> CPC_P5_CESR_OS0) & 1u; 576*0Sstevel@tonic-gate xcesr->sys[1] = (cesr >> CPC_P5_CESR_OS1) & 1u; 577*0Sstevel@tonic-gate xcesr->clk[0] = (cesr >> CPC_P5_CESR_CLK0) & 1u; 578*0Sstevel@tonic-gate xcesr->clk[1] = (cesr >> CPC_P5_CESR_CLK1) & 1u; 579*0Sstevel@tonic-gate xcesr->pc[0] = (cesr >> CPC_P5_CESR_PC0) & 1u; 580*0Sstevel@tonic-gate xcesr->pc[1] = (cesr >> CPC_P5_CESR_PC1) & 1u; 581*0Sstevel@tonic-gate /* 582*0Sstevel@tonic-gate * If usr and sys are both disabled, the counter is disabled. 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate if (xcesr->usr[0] == 0 && xcesr->sys[0] == 0) 585*0Sstevel@tonic-gate xcesr->clk[0] = 0; 586*0Sstevel@tonic-gate if (xcesr->usr[1] == 0 && xcesr->sys[1] == 0) 587*0Sstevel@tonic-gate xcesr->clk[1] = 0; 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate char * 591*0Sstevel@tonic-gate cpc_eventtostr(cpc_event_t *event) 592*0Sstevel@tonic-gate { 593*0Sstevel@tonic-gate char *pic[2]; 594*0Sstevel@tonic-gate char buffer[1024]; 595*0Sstevel@tonic-gate int cpuver = event->ce_cpuver; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate switch (cpuver) { 598*0Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 599*0Sstevel@tonic-gate case CPC_PENTIUM_PRO: 600*0Sstevel@tonic-gate { 601*0Sstevel@tonic-gate struct xpes xpes[2]; 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate unmake_pes(event->ce_pes[0], cpuver, &xpes[0]); 604*0Sstevel@tonic-gate if ((pic[0] = regtostr(cpuver, 0, xpes[0].evsel)) == NULL) 605*0Sstevel@tonic-gate return (NULL); 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate unmake_pes(event->ce_pes[1], cpuver, &xpes[1]); 608*0Sstevel@tonic-gate if ((pic[1] = regtostr(cpuver, 1, xpes[1].evsel)) == NULL) { 609*0Sstevel@tonic-gate free(pic[0]); 610*0Sstevel@tonic-gate return (NULL); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 613*0Sstevel@tonic-gate tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 614*0Sstevel@tonic-gate free(pic[1]); 615*0Sstevel@tonic-gate free(pic[0]); 616*0Sstevel@tonic-gate masktostr(buffer, xpes[0].cmask, tokens[D_cmask0]); 617*0Sstevel@tonic-gate masktostr(buffer, xpes[1].cmask, tokens[D_cmask1]); 618*0Sstevel@tonic-gate masktostr(buffer, xpes[0].umask, tokens[D_umask0]); 619*0Sstevel@tonic-gate masktostr(buffer, xpes[1].umask, tokens[D_umask1]); 620*0Sstevel@tonic-gate flagstostr(buffer, 621*0Sstevel@tonic-gate xpes[0].usr, xpes[1].usr, 1, tokens[D_nouser]); 622*0Sstevel@tonic-gate flagstostr(buffer, 623*0Sstevel@tonic-gate xpes[0].sys, xpes[1].sys, 0, tokens[D_sys]); 624*0Sstevel@tonic-gate flagstostr(buffer, 625*0Sstevel@tonic-gate xpes[0].edge, xpes[1].edge, 1, tokens[D_noedge]); 626*0Sstevel@tonic-gate flagstostr(buffer, 627*0Sstevel@tonic-gate xpes[0].irupt, xpes[1].irupt, 0, tokens[D_int]); 628*0Sstevel@tonic-gate flagstostr(buffer, 629*0Sstevel@tonic-gate xpes[0].inv, xpes[1].inv, 0, tokens[D_inv]); 630*0Sstevel@tonic-gate flagstostr(buffer, 631*0Sstevel@tonic-gate xpes[0].pc, xpes[1].pc, 0, tokens[D_pc]); 632*0Sstevel@tonic-gate } break; 633*0Sstevel@tonic-gate case CPC_PENTIUM_MMX: 634*0Sstevel@tonic-gate case CPC_PENTIUM: 635*0Sstevel@tonic-gate { 636*0Sstevel@tonic-gate struct xcesr xcesr; 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate unmake_cesr(event->ce_cesr, cpuver, &xcesr); 639*0Sstevel@tonic-gate if ((pic[0] = regtostr(cpuver, 0, xcesr.evsel[0])) == NULL) 640*0Sstevel@tonic-gate return (NULL); 641*0Sstevel@tonic-gate if ((pic[1] = regtostr(cpuver, 1, xcesr.evsel[1])) == NULL) { 642*0Sstevel@tonic-gate free(pic[0]); 643*0Sstevel@tonic-gate return (NULL); 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 646*0Sstevel@tonic-gate tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 647*0Sstevel@tonic-gate free(pic[1]); 648*0Sstevel@tonic-gate free(pic[0]); 649*0Sstevel@tonic-gate flagstostr(buffer, 650*0Sstevel@tonic-gate xcesr.usr[0], xcesr.usr[1], 1, tokens[D_nouser]); 651*0Sstevel@tonic-gate flagstostr(buffer, 652*0Sstevel@tonic-gate xcesr.sys[0], xcesr.sys[1], 0, tokens[D_sys]); 653*0Sstevel@tonic-gate flagstostr(buffer, 654*0Sstevel@tonic-gate xcesr.clk[0], xcesr.clk[1], 0, tokens[D_noedge]); 655*0Sstevel@tonic-gate flagstostr(buffer, 656*0Sstevel@tonic-gate xcesr.pc[0], xcesr.pc[1], 0, tokens[D_pc]); 657*0Sstevel@tonic-gate } break; 658*0Sstevel@tonic-gate default: 659*0Sstevel@tonic-gate return (NULL); 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate return (strdup(buffer)); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* 665*0Sstevel@tonic-gate * Utility operations on events 666*0Sstevel@tonic-gate */ 667*0Sstevel@tonic-gate void 668*0Sstevel@tonic-gate cpc_event_accum(cpc_event_t *accum, cpc_event_t *event) 669*0Sstevel@tonic-gate { 670*0Sstevel@tonic-gate if (accum->ce_hrt < event->ce_hrt) 671*0Sstevel@tonic-gate accum->ce_hrt = event->ce_hrt; 672*0Sstevel@tonic-gate accum->ce_tsc += event->ce_tsc; 673*0Sstevel@tonic-gate accum->ce_pic[0] += event->ce_pic[0]; 674*0Sstevel@tonic-gate accum->ce_pic[1] += event->ce_pic[1]; 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate void 678*0Sstevel@tonic-gate cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right) 679*0Sstevel@tonic-gate { 680*0Sstevel@tonic-gate diff->ce_hrt = left->ce_hrt; 681*0Sstevel@tonic-gate diff->ce_tsc = left->ce_tsc - right->ce_tsc; 682*0Sstevel@tonic-gate diff->ce_pic[0] = left->ce_pic[0] - right->ce_pic[0]; 683*0Sstevel@tonic-gate diff->ce_pic[1] = left->ce_pic[1] - right->ce_pic[1]; 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate /* 687*0Sstevel@tonic-gate * Given a cpc_event_t and cpc_bind_event() flags, 688*0Sstevel@tonic-gate * translate the cpc_event_t into the cpc_set_t format. 689*0Sstevel@tonic-gate * 690*0Sstevel@tonic-gate * Returns NULL on failure. 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate cpc_set_t * 693*0Sstevel@tonic-gate __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags) 694*0Sstevel@tonic-gate { 695*0Sstevel@tonic-gate cpc_set_t *set; 696*0Sstevel@tonic-gate int cpuver = event->ce_cpuver; 697*0Sstevel@tonic-gate char *pic[2]; 698*0Sstevel@tonic-gate int flags[2] = { 0, 0 }; 699*0Sstevel@tonic-gate int i; 700*0Sstevel@tonic-gate int j; 701*0Sstevel@tonic-gate int nattrs; 702*0Sstevel@tonic-gate cpc_attr_t *attr; 703*0Sstevel@tonic-gate int intr; 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate if ((set = cpc_set_create(cpc)) == NULL) { 706*0Sstevel@tonic-gate return (NULL); 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate if (iflags & CPC_BIND_EMT_OVF) 710*0Sstevel@tonic-gate flags[0] = flags[1] = CPC_OVF_NOTIFY_EMT; 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate switch (cpuver) { 713*0Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 714*0Sstevel@tonic-gate case CPC_PENTIUM_PRO: 715*0Sstevel@tonic-gate { 716*0Sstevel@tonic-gate struct xpes xpes[2]; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate for (i = 0; i < 2; i++) { 719*0Sstevel@tonic-gate intr = 0; 720*0Sstevel@tonic-gate nattrs = j = 1; 721*0Sstevel@tonic-gate unmake_pes(event->ce_pes[i], cpuver, &xpes[i]); 722*0Sstevel@tonic-gate if ((pic[i] = regtostr(cpuver, i, 723*0Sstevel@tonic-gate xpes[i].evsel)) == NULL) { 724*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 725*0Sstevel@tonic-gate return (NULL); 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate if (xpes[i].usr == 1) 728*0Sstevel@tonic-gate flags[i] |= CPC_COUNT_USER; 729*0Sstevel@tonic-gate if (xpes[i].sys == 1) 730*0Sstevel@tonic-gate flags[i] |= CPC_COUNT_SYSTEM; 731*0Sstevel@tonic-gate if (xpes[i].irupt == 1) { 732*0Sstevel@tonic-gate nattrs++; 733*0Sstevel@tonic-gate intr = 1; 734*0Sstevel@tonic-gate } 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate if (xpes[i].cmask) 737*0Sstevel@tonic-gate nattrs++; 738*0Sstevel@tonic-gate if (xpes[i].umask) 739*0Sstevel@tonic-gate nattrs++; 740*0Sstevel@tonic-gate if (xpes[i].inv) 741*0Sstevel@tonic-gate nattrs++; 742*0Sstevel@tonic-gate if (xpes[i].pc) 743*0Sstevel@tonic-gate nattrs++; 744*0Sstevel@tonic-gate if (xpes[i].edge == 0) 745*0Sstevel@tonic-gate nattrs++; 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate if ((attr = (cpc_attr_t *)malloc(nattrs * 748*0Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) { 749*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 750*0Sstevel@tonic-gate errno = ENOMEM; 751*0Sstevel@tonic-gate return (NULL); 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate /* 755*0Sstevel@tonic-gate * Ensure that pic[0] in the cpc_event_t is bound to 756*0Sstevel@tonic-gate * physical pic0. 757*0Sstevel@tonic-gate */ 758*0Sstevel@tonic-gate attr[0].ca_name = "picnum"; 759*0Sstevel@tonic-gate attr[0].ca_val = i; 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate if (intr) { 762*0Sstevel@tonic-gate attr[j].ca_name = "int"; 763*0Sstevel@tonic-gate attr[j].ca_val = 1; 764*0Sstevel@tonic-gate j++; 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate if (xpes[i].cmask) { 767*0Sstevel@tonic-gate attr[j].ca_name = "cmask"; 768*0Sstevel@tonic-gate attr[j].ca_val = xpes[i].cmask; 769*0Sstevel@tonic-gate j++; 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate if (xpes[i].umask) { 772*0Sstevel@tonic-gate attr[j].ca_name = "umask"; 773*0Sstevel@tonic-gate attr[j].ca_val = xpes[i].umask; 774*0Sstevel@tonic-gate j++; 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate if (xpes[i].inv) { 777*0Sstevel@tonic-gate attr[j].ca_name = "inv"; 778*0Sstevel@tonic-gate attr[j].ca_val = 1; 779*0Sstevel@tonic-gate j++; 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate if (xpes[i].pc) { 782*0Sstevel@tonic-gate attr[j].ca_name = "pc"; 783*0Sstevel@tonic-gate attr[j].ca_val = 1; 784*0Sstevel@tonic-gate j++; 785*0Sstevel@tonic-gate } 786*0Sstevel@tonic-gate if (xpes[i].edge == 0) { 787*0Sstevel@tonic-gate attr[j].ca_name = "noedge"; 788*0Sstevel@tonic-gate attr[j].ca_val = 1; 789*0Sstevel@tonic-gate j++; 790*0Sstevel@tonic-gate } 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, pic[i], 793*0Sstevel@tonic-gate event->ce_pic[i], flags[i], nattrs, attr) == -1) { 794*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 795*0Sstevel@tonic-gate free(pic[i]); 796*0Sstevel@tonic-gate free(attr); 797*0Sstevel@tonic-gate return (NULL); 798*0Sstevel@tonic-gate } 799*0Sstevel@tonic-gate free(pic[i]); 800*0Sstevel@tonic-gate free(attr); 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate break; 804*0Sstevel@tonic-gate case CPC_PENTIUM_MMX: 805*0Sstevel@tonic-gate case CPC_PENTIUM: 806*0Sstevel@tonic-gate { 807*0Sstevel@tonic-gate struct xcesr xcesr; 808*0Sstevel@tonic-gate unmake_cesr(event->ce_cesr, cpuver, &xcesr); 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate for (i = 0; i < 2; i++) { 811*0Sstevel@tonic-gate nattrs = j = 1; 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate if ((pic[i] = regtostr(cpuver, i, xcesr.evsel[i])) 814*0Sstevel@tonic-gate == NULL) { 815*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 816*0Sstevel@tonic-gate return (NULL); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate if (xcesr.usr[i] == 1) 820*0Sstevel@tonic-gate flags[i] |= CPC_COUNT_USER; 821*0Sstevel@tonic-gate if (xcesr.sys[i] == 1) 822*0Sstevel@tonic-gate flags[i] |= CPC_COUNT_SYSTEM; 823*0Sstevel@tonic-gate if (xcesr.clk[i] == 1) 824*0Sstevel@tonic-gate nattrs++; 825*0Sstevel@tonic-gate if (xcesr.pc[i] == 1) 826*0Sstevel@tonic-gate nattrs++; 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate if ((attr = (cpc_attr_t *)malloc(nattrs * 829*0Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) { 830*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 831*0Sstevel@tonic-gate errno = ENOMEM; 832*0Sstevel@tonic-gate return (NULL); 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate /* 836*0Sstevel@tonic-gate * Ensure that pic[0] in the cpc_event_t is bound to 837*0Sstevel@tonic-gate * physical pic0. 838*0Sstevel@tonic-gate */ 839*0Sstevel@tonic-gate attr[0].ca_name = "picnum"; 840*0Sstevel@tonic-gate attr[0].ca_val = i; 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate if (xcesr.clk[i] == 1) { 843*0Sstevel@tonic-gate attr[j].ca_name = "noedge"; 844*0Sstevel@tonic-gate attr[j].ca_val = 1; 845*0Sstevel@tonic-gate j++; 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate if (xcesr.pc[i] == 1) { 849*0Sstevel@tonic-gate attr[j].ca_name = "pc"; 850*0Sstevel@tonic-gate attr[j].ca_val = 1; 851*0Sstevel@tonic-gate j++; 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, pic[i], 855*0Sstevel@tonic-gate event->ce_pic[i], flags[i], nattrs, attr) == -1) { 856*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 857*0Sstevel@tonic-gate free(pic[i]); 858*0Sstevel@tonic-gate free(attr); 859*0Sstevel@tonic-gate return (NULL); 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate free(pic[i]); 863*0Sstevel@tonic-gate free(attr); 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate break; 867*0Sstevel@tonic-gate default: 868*0Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 869*0Sstevel@tonic-gate return (NULL); 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate return (set); 873*0Sstevel@tonic-gate } 874