17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*23a1cceaSRoger A. Faulkner * Common Development and Distribution License (the "License"). 6*23a1cceaSRoger A. Faulkner * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate 22*23a1cceaSRoger A. Faulkner /* 23*23a1cceaSRoger A. Faulkner * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 24*23a1cceaSRoger A. Faulkner */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Routines to capture processor-dependencies in event specification. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <string.h> 327c478bd9Sstevel@tonic-gate #include <strings.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <libintl.h> 367c478bd9Sstevel@tonic-gate #include <assert.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include "libcpc.h" 407c478bd9Sstevel@tonic-gate #include "libcpc_impl.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * Event specifications for Pentium performance counters are based 447c478bd9Sstevel@tonic-gate * on the content of a getsubopt-like string. 457c478bd9Sstevel@tonic-gate * The string should contain something that looks like this: 467c478bd9Sstevel@tonic-gate * 477c478bd9Sstevel@tonic-gate * pic0=<eventspec>,pic1=<eventspec> 487c478bd9Sstevel@tonic-gate * [,cmask0=<maskspec>][,cmask1=<maskspec>] 497c478bd9Sstevel@tonic-gate * [,umask0=<maskspec>][,umask1=<maskspec>] 507c478bd9Sstevel@tonic-gate * [,inv[0|1]][,noedge[0|1]] 517c478bd9Sstevel@tonic-gate * [,sys[0|1]][,nouser[0|1]] 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * For example: 547c478bd9Sstevel@tonic-gate * pic0=data_mem_refs,pic1=l2_ld,sys 557c478bd9Sstevel@tonic-gate * or 567c478bd9Sstevel@tonic-gate * pic0=l2_ld,pic1=bus_drdy_clocks,umask1=0x20,nouser1 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * By default, user event counting is enabled, system event counting 597c478bd9Sstevel@tonic-gate * is disabled. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * Note that Pentium and Pentium Pro have different event specifications. 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * The two events must be named. The names can be ascii or 647c478bd9Sstevel@tonic-gate * a decimal, octal or hexadecimal number as parsed by strtol(3C). 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * The routine counts the number of errors encountered while parsing 677c478bd9Sstevel@tonic-gate * the string, if no errors are encountered, the event handle is 687c478bd9Sstevel@tonic-gate * returned. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate const char * 727c478bd9Sstevel@tonic-gate cpc_getusage(int cpuver) 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate switch (cpuver) { 757c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 767c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO: 777c478bd9Sstevel@tonic-gate return ("pic0=<event0>,pic1=<event1> " 787c478bd9Sstevel@tonic-gate "[,sys[0|1]] " 797c478bd9Sstevel@tonic-gate "[,nouser[0|1]] " 807c478bd9Sstevel@tonic-gate "[,noedge[0|1]] " 817c478bd9Sstevel@tonic-gate "[,pc[0|1]] " 827c478bd9Sstevel@tonic-gate "[,int[0|1]] " 837c478bd9Sstevel@tonic-gate "[,inv[0|1]] " 847c478bd9Sstevel@tonic-gate "[,cmask[0|1]=<maskspec>] " 857c478bd9Sstevel@tonic-gate "[,umask[0|1]=<maskspec>] "); 867c478bd9Sstevel@tonic-gate case CPC_PENTIUM_MMX: 877c478bd9Sstevel@tonic-gate case CPC_PENTIUM: 887c478bd9Sstevel@tonic-gate return ("pic0=<event0>,pic1=<event1> " 897c478bd9Sstevel@tonic-gate "[,sys[0|1]] " 907c478bd9Sstevel@tonic-gate "[,nouser[0|1]] " 917c478bd9Sstevel@tonic-gate "[,noedge[0|1]] " 927c478bd9Sstevel@tonic-gate "[,pc[0|1]]"); 937c478bd9Sstevel@tonic-gate default: 947c478bd9Sstevel@tonic-gate return (NULL); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate struct keyval { 997c478bd9Sstevel@tonic-gate char *kv_token; 1007c478bd9Sstevel@tonic-gate int (*kv_action)(const char *, 1017c478bd9Sstevel@tonic-gate const struct keyval *, int, char *, uint32_t *); 1027c478bd9Sstevel@tonic-gate uint_t kv_regno; 1037c478bd9Sstevel@tonic-gate uint32_t kv_mask; 1047c478bd9Sstevel@tonic-gate int kv_shift; 1057c478bd9Sstevel@tonic-gate }; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1087c478bd9Sstevel@tonic-gate static int 1097c478bd9Sstevel@tonic-gate eightbits(const char *fn, 1107c478bd9Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate char *eptr = NULL; 1137c478bd9Sstevel@tonic-gate long l; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate if (value == NULL) { 1167c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("missing '%s' value\n"), 1177c478bd9Sstevel@tonic-gate kv->kv_token); 1187c478bd9Sstevel@tonic-gate return (-1); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate l = strtol(value, &eptr, 0); 1217c478bd9Sstevel@tonic-gate if (value == eptr || l < 0 || l > UINT8_MAX) { 1227c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("bad '%s' value\n"), kv->kv_token); 1237c478bd9Sstevel@tonic-gate return (-1); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate bits[kv->kv_regno] |= ((uint8_t)l & kv->kv_mask) << kv->kv_shift; 1267c478bd9Sstevel@tonic-gate return (0); 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate static int 1307c478bd9Sstevel@tonic-gate picbits(const char *fn, 1317c478bd9Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate uint8_t val8; 1347c478bd9Sstevel@tonic-gate uint_t regno; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate if (value == NULL) { 1397c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("missing '%s' value\n"), 1407c478bd9Sstevel@tonic-gate kv->kv_token); 1417c478bd9Sstevel@tonic-gate return (-1); 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) { 1457c478bd9Sstevel@tonic-gate switch (cpuver) { 1467c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 1477c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO: 1487c478bd9Sstevel@tonic-gate assert(kv->kv_regno == regno); 1497c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext( 1507c478bd9Sstevel@tonic-gate "PerfCtr%d cannot measure '%s' on this cpu\n"), 1517c478bd9Sstevel@tonic-gate regno, value); 1527c478bd9Sstevel@tonic-gate break; 1537c478bd9Sstevel@tonic-gate case CPC_PENTIUM_MMX: 1547c478bd9Sstevel@tonic-gate case CPC_PENTIUM: 1557c478bd9Sstevel@tonic-gate assert(kv->kv_regno == 0); 1567c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext( 1577c478bd9Sstevel@tonic-gate "CTR%d cannot measure '%s' on this cpu\n"), 1587c478bd9Sstevel@tonic-gate regno, value); 1597c478bd9Sstevel@tonic-gate break; 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate return (-1); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate bits[kv->kv_regno] |= (val8 & kv->kv_mask) << kv->kv_shift; 1647c478bd9Sstevel@tonic-gate return (0); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1687c478bd9Sstevel@tonic-gate static int 1697c478bd9Sstevel@tonic-gate bitclr(const char *fn, 1707c478bd9Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 1717c478bd9Sstevel@tonic-gate { 1727c478bd9Sstevel@tonic-gate if (value != NULL) { 1737c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 1747c478bd9Sstevel@tonic-gate return (-1); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate bits[kv->kv_regno] &= ~(kv->kv_mask << kv->kv_shift); 1777c478bd9Sstevel@tonic-gate return (0); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /*ARGSUSED2*/ 1817c478bd9Sstevel@tonic-gate static int 1827c478bd9Sstevel@tonic-gate bitset(const char *fn, 1837c478bd9Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate if (value != NULL) { 1867c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 1877c478bd9Sstevel@tonic-gate return (-1); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate bits[kv->kv_regno] |= (kv->kv_mask << kv->kv_shift); 1907c478bd9Sstevel@tonic-gate return (0); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate static int 1947c478bd9Sstevel@tonic-gate nextpair(const char *fn, 1957c478bd9Sstevel@tonic-gate const struct keyval *kv, int cpuver, char *value, uint32_t *bits) 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate int rv; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if (value != NULL) { 2007c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token); 2017c478bd9Sstevel@tonic-gate return (-1); 2027c478bd9Sstevel@tonic-gate } 2037c478bd9Sstevel@tonic-gate kv++; 2047c478bd9Sstevel@tonic-gate if ((rv = kv->kv_action(fn, kv, cpuver, value, bits)) != 0) 2057c478bd9Sstevel@tonic-gate return (rv); 2067c478bd9Sstevel@tonic-gate kv++; 2077c478bd9Sstevel@tonic-gate return (kv->kv_action(fn, kv, cpuver, value, bits)); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * This token table must match the keyval tables below. 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate static char * const tokens[] = { 2157c478bd9Sstevel@tonic-gate #define D_pic0 0 2167c478bd9Sstevel@tonic-gate "pic0", /* takes a valid event name */ 2177c478bd9Sstevel@tonic-gate #define D_pic1 1 2187c478bd9Sstevel@tonic-gate "pic1", /* takes a valid event name */ 2197c478bd9Sstevel@tonic-gate #define D_nouser 2 2207c478bd9Sstevel@tonic-gate "nouser", /* disables user counts */ 2217c478bd9Sstevel@tonic-gate #define D_nouser0 3 2227c478bd9Sstevel@tonic-gate "nouser0", 2237c478bd9Sstevel@tonic-gate #define D_nouser1 4 2247c478bd9Sstevel@tonic-gate "nouser1", 2257c478bd9Sstevel@tonic-gate #define D_sys 5 2267c478bd9Sstevel@tonic-gate "sys", /* enables system counts */ 2277c478bd9Sstevel@tonic-gate #define D_sys0 6 2287c478bd9Sstevel@tonic-gate "sys0", 2297c478bd9Sstevel@tonic-gate #define D_sys1 7 2307c478bd9Sstevel@tonic-gate "sys1", 2317c478bd9Sstevel@tonic-gate #define D_noedge 8 2327c478bd9Sstevel@tonic-gate "noedge", /* disable edge detect */ 2337c478bd9Sstevel@tonic-gate #define D_noedge0 9 2347c478bd9Sstevel@tonic-gate "noedge0", 2357c478bd9Sstevel@tonic-gate #define D_noedge1 10 2367c478bd9Sstevel@tonic-gate "noedge1", 2377c478bd9Sstevel@tonic-gate #define D_pc 11 2387c478bd9Sstevel@tonic-gate "pc", /* sets pin control high */ 2397c478bd9Sstevel@tonic-gate #define D_pc0 12 2407c478bd9Sstevel@tonic-gate "pc0", 2417c478bd9Sstevel@tonic-gate #define D_pc1 13 2427c478bd9Sstevel@tonic-gate "pc1", 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * These additional keywords are for Pentium Pro / Pentium II machines. 2467c478bd9Sstevel@tonic-gate */ 2477c478bd9Sstevel@tonic-gate #define D_int 14 2487c478bd9Sstevel@tonic-gate "int", /* enable interrupt on counter overflow */ 2497c478bd9Sstevel@tonic-gate #define D_int0 15 2507c478bd9Sstevel@tonic-gate "int0", 2517c478bd9Sstevel@tonic-gate #define D_int1 16 2527c478bd9Sstevel@tonic-gate "int1", 2537c478bd9Sstevel@tonic-gate #define D_inv 17 2547c478bd9Sstevel@tonic-gate "inv", /* invert cmask comparison */ 2557c478bd9Sstevel@tonic-gate #define D_inv0 18 2567c478bd9Sstevel@tonic-gate "inv0", 2577c478bd9Sstevel@tonic-gate #define D_inv1 19 2587c478bd9Sstevel@tonic-gate "inv1", 2597c478bd9Sstevel@tonic-gate #define D_umask0 20 2607c478bd9Sstevel@tonic-gate "umask0", /* PerfCtr0 unit mask */ 2617c478bd9Sstevel@tonic-gate #define D_umask1 21 2627c478bd9Sstevel@tonic-gate "umask1", /* PerfCtr1 unit mask */ 2637c478bd9Sstevel@tonic-gate #define D_cmask0 22 2647c478bd9Sstevel@tonic-gate "cmask0", /* PerfCtr0 counter mask */ 2657c478bd9Sstevel@tonic-gate #define D_cmask1 23 2667c478bd9Sstevel@tonic-gate "cmask1", /* PerfCtr1 counter mask */ 2677c478bd9Sstevel@tonic-gate NULL 2687c478bd9Sstevel@tonic-gate }; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate static const struct keyval p6_keyvals[] = { 2717c478bd9Sstevel@tonic-gate { "pic0", picbits, 0, 2727c478bd9Sstevel@tonic-gate CPC_P6_PES_PIC0_MASK, 0 }, 2737c478bd9Sstevel@tonic-gate { "pic1", picbits, 1, 2747c478bd9Sstevel@tonic-gate CPC_P6_PES_PIC1_MASK, 0 }, 2757c478bd9Sstevel@tonic-gate { "nouser", nextpair }, 2767c478bd9Sstevel@tonic-gate { "nouser0", bitclr, 0, 2777c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_USR }, 2787c478bd9Sstevel@tonic-gate { "nouser1", bitclr, 1, 2797c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_USR }, 2807c478bd9Sstevel@tonic-gate { "sys", nextpair }, 2817c478bd9Sstevel@tonic-gate { "sys0", bitset, 0, 2827c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_OS }, 2837c478bd9Sstevel@tonic-gate { "sys1", bitset, 1, 2847c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_OS }, 2857c478bd9Sstevel@tonic-gate { "noedge", nextpair }, 2867c478bd9Sstevel@tonic-gate { "noedge0", bitclr, 0, 2877c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_E }, 2887c478bd9Sstevel@tonic-gate { "noedge1", bitclr, 1, 2897c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_E }, 2907c478bd9Sstevel@tonic-gate { "pc", nextpair }, 2917c478bd9Sstevel@tonic-gate { "pc0", bitset, 0, 2927c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_PC }, 2937c478bd9Sstevel@tonic-gate { "pc1", bitset, 1, 2947c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_PC }, 2957c478bd9Sstevel@tonic-gate { "int", nextpair }, 2967c478bd9Sstevel@tonic-gate { "int0", bitset, 0, 2977c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INT }, 2987c478bd9Sstevel@tonic-gate { "int1", bitset, 1, 2997c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INT }, 3007c478bd9Sstevel@tonic-gate { "inv", nextpair }, 3017c478bd9Sstevel@tonic-gate { "inv0", bitset, 0, 3027c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INV }, 3037c478bd9Sstevel@tonic-gate { "inv1", bitset, 1, 3047c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P6_PES_INV }, 3057c478bd9Sstevel@tonic-gate { "umask0", eightbits, 0, 3067c478bd9Sstevel@tonic-gate CPC_P6_PES_UMASK_MASK, CPC_P6_PES_UMASK_SHIFT }, 3077c478bd9Sstevel@tonic-gate { "umask1", eightbits, 1, 3087c478bd9Sstevel@tonic-gate CPC_P6_PES_UMASK_MASK, CPC_P6_PES_UMASK_SHIFT }, 3097c478bd9Sstevel@tonic-gate { "cmask0", eightbits, 0, 3107c478bd9Sstevel@tonic-gate CPC_P6_PES_CMASK_MASK, CPC_P6_PES_CMASK_SHIFT }, 3117c478bd9Sstevel@tonic-gate { "cmask1", eightbits, 1, 3127c478bd9Sstevel@tonic-gate CPC_P6_PES_CMASK_MASK, CPC_P6_PES_CMASK_SHIFT }, 3137c478bd9Sstevel@tonic-gate }; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * Note that this table -must- be an identically indexed 3177c478bd9Sstevel@tonic-gate * subset of p6_keyvals. 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate static const struct keyval p5_keyvals[] = { 3207c478bd9Sstevel@tonic-gate { "pic0", picbits, 0, 3217c478bd9Sstevel@tonic-gate CPC_P5_CESR_ES0_MASK, CPC_P5_CESR_ES0_SHIFT }, 3227c478bd9Sstevel@tonic-gate { "pic1", picbits, 0, 3237c478bd9Sstevel@tonic-gate CPC_P5_CESR_ES1_MASK, CPC_P5_CESR_ES1_SHIFT }, 3247c478bd9Sstevel@tonic-gate { "nouser", nextpair }, 3257c478bd9Sstevel@tonic-gate { "nouser0", bitclr, 0, 3267c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_USR0 }, 3277c478bd9Sstevel@tonic-gate { "nouser1", bitclr, 0, 3287c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_USR1 }, 3297c478bd9Sstevel@tonic-gate { "sys", nextpair }, 3307c478bd9Sstevel@tonic-gate { "sys0", bitset, 0, 3317c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_OS0 }, 3327c478bd9Sstevel@tonic-gate { "sys1", bitset, 0, 3337c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_OS1 }, 3347c478bd9Sstevel@tonic-gate { "noedge", nextpair }, 3357c478bd9Sstevel@tonic-gate { "noedge0", bitset, 0, 3367c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_CLK0 }, 3377c478bd9Sstevel@tonic-gate { "noedge1", bitset, 0, 3387c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_CLK1 }, 3397c478bd9Sstevel@tonic-gate { "pc", nextpair }, 3407c478bd9Sstevel@tonic-gate { "pc0", bitset, 0, 3417c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_PC0 }, 3427c478bd9Sstevel@tonic-gate { "pc1", bitset, 0, 3437c478bd9Sstevel@tonic-gate UINT32_C(1), CPC_P5_CESR_PC1 }, 3447c478bd9Sstevel@tonic-gate }; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate #if !defined(NDEBUG) 3477c478bd9Sstevel@tonic-gate #pragma init(__tablecheck) 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate static void 3507c478bd9Sstevel@tonic-gate __tablecheck(void) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1; 3537c478bd9Sstevel@tonic-gate uint_t p6_nkeys = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]); 3547c478bd9Sstevel@tonic-gate uint_t p5_nkeys = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]); 3557c478bd9Sstevel@tonic-gate uint_t n; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate assert(ntokens == p6_nkeys); 3587c478bd9Sstevel@tonic-gate for (n = 0; n < ntokens; n++) 3597c478bd9Sstevel@tonic-gate assert(strcmp(tokens[n], p6_keyvals[n].kv_token) == 0); 3607c478bd9Sstevel@tonic-gate assert(p6_nkeys >= p5_nkeys); 3617c478bd9Sstevel@tonic-gate for (n = 0; n < p5_nkeys; n++) 3627c478bd9Sstevel@tonic-gate assert(strcmp(tokens[n], p5_keyvals[n].kv_token) == 0); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate #endif /* !NDEBUG */ 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate int 3687c478bd9Sstevel@tonic-gate cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event) 3697c478bd9Sstevel@tonic-gate { 3707c478bd9Sstevel@tonic-gate static const char fn[] = "strtoevent"; 3717c478bd9Sstevel@tonic-gate char *value; 3727c478bd9Sstevel@tonic-gate char *pic[2]; 3737c478bd9Sstevel@tonic-gate char *opts; 3747c478bd9Sstevel@tonic-gate int errcnt = 0; 3757c478bd9Sstevel@tonic-gate uint_t ntokens; 3767c478bd9Sstevel@tonic-gate const struct keyval *keyvals; 3777c478bd9Sstevel@tonic-gate uint32_t *bits; 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (spec == NULL) 3807c478bd9Sstevel@tonic-gate return (errcnt = 1); 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate bzero(event, sizeof (*event)); 3837c478bd9Sstevel@tonic-gate switch (event->ce_cpuver = cpuver) { 3847c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 3857c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO: 3867c478bd9Sstevel@tonic-gate keyvals = p6_keyvals; 3877c478bd9Sstevel@tonic-gate ntokens = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]); 3887c478bd9Sstevel@tonic-gate bits = &event->ce_pes[0]; 3897c478bd9Sstevel@tonic-gate bits[0] = bits[1] = 3907c478bd9Sstevel@tonic-gate (1u << CPC_P6_PES_USR) | (1u << CPC_P6_PES_E); 3917c478bd9Sstevel@tonic-gate break; 3927c478bd9Sstevel@tonic-gate case CPC_PENTIUM_MMX: 3937c478bd9Sstevel@tonic-gate case CPC_PENTIUM: 3947c478bd9Sstevel@tonic-gate keyvals = p5_keyvals; 3957c478bd9Sstevel@tonic-gate ntokens = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]); 3967c478bd9Sstevel@tonic-gate bits = &event->ce_cesr; 3977c478bd9Sstevel@tonic-gate bits[0] = 3987c478bd9Sstevel@tonic-gate (1u << CPC_P5_CESR_USR0) | (1u << CPC_P5_CESR_USR1); 3997c478bd9Sstevel@tonic-gate break; 4007c478bd9Sstevel@tonic-gate default: 4017c478bd9Sstevel@tonic-gate return (errcnt = 1); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate pic[0] = pic[1] = NULL; 4057c478bd9Sstevel@tonic-gate 406*23a1cceaSRoger A. Faulkner opts = strdupa(spec); 4077c478bd9Sstevel@tonic-gate while (*opts != '\0') { 4087c478bd9Sstevel@tonic-gate const struct keyval *kv; 4097c478bd9Sstevel@tonic-gate int idx = getsubopt(&opts, tokens, &value); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (idx >= 0 && idx < ntokens) { 4127c478bd9Sstevel@tonic-gate kv = &keyvals[idx]; 4137c478bd9Sstevel@tonic-gate if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) { 4147c478bd9Sstevel@tonic-gate errcnt++; 4157c478bd9Sstevel@tonic-gate break; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (idx == D_pic0) { 4197c478bd9Sstevel@tonic-gate if (pic[0] != NULL) { 4207c478bd9Sstevel@tonic-gate __cpc_error(fn, 4217c478bd9Sstevel@tonic-gate "repeated '%s' token\n", 4227c478bd9Sstevel@tonic-gate tokens[idx]); 4237c478bd9Sstevel@tonic-gate errcnt++; 4247c478bd9Sstevel@tonic-gate break; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate pic[0] = value; 4277c478bd9Sstevel@tonic-gate } else if (idx == D_pic1) { 4287c478bd9Sstevel@tonic-gate if (pic[1] != NULL) { 4297c478bd9Sstevel@tonic-gate __cpc_error(fn, 4307c478bd9Sstevel@tonic-gate "repeated '%s' token\n", 4317c478bd9Sstevel@tonic-gate tokens[idx]); 4327c478bd9Sstevel@tonic-gate errcnt++; 4337c478bd9Sstevel@tonic-gate break; 4347c478bd9Sstevel@tonic-gate } 4357c478bd9Sstevel@tonic-gate pic[1] = value; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate } else if (idx == -1) { 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * The token given wasn't recognized. 4407c478bd9Sstevel@tonic-gate * See if it was an implicit pic specification.. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate if (pic[0] == NULL) { 4437c478bd9Sstevel@tonic-gate kv = &keyvals[D_pic0]; 4447c478bd9Sstevel@tonic-gate if (kv->kv_action(fn, 4457c478bd9Sstevel@tonic-gate kv, cpuver, value, bits) != 0) { 4467c478bd9Sstevel@tonic-gate errcnt++; 4477c478bd9Sstevel@tonic-gate break; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate pic[0] = value; 4507c478bd9Sstevel@tonic-gate } else if (pic[1] == NULL) { 4517c478bd9Sstevel@tonic-gate kv = &keyvals[D_pic1]; 4527c478bd9Sstevel@tonic-gate if (kv->kv_action(fn, 4537c478bd9Sstevel@tonic-gate kv, cpuver, value, bits) != 0) { 4547c478bd9Sstevel@tonic-gate errcnt++; 4557c478bd9Sstevel@tonic-gate break; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate pic[1] = value; 4587c478bd9Sstevel@tonic-gate } else { 4597c478bd9Sstevel@tonic-gate __cpc_error(fn, 4607c478bd9Sstevel@tonic-gate gettext("bad token '%s'\n"), value); 4617c478bd9Sstevel@tonic-gate errcnt++; 4627c478bd9Sstevel@tonic-gate break; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate } else { 4657c478bd9Sstevel@tonic-gate if (idx >= 0 && 4667c478bd9Sstevel@tonic-gate idx < sizeof (tokens) / sizeof (tokens[0])) 4677c478bd9Sstevel@tonic-gate __cpc_error(fn, 4687c478bd9Sstevel@tonic-gate gettext("bad token '%s'\n"), tokens[idx]); 4697c478bd9Sstevel@tonic-gate else 4707c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("bad token\n")); 4717c478bd9Sstevel@tonic-gate errcnt++; 4727c478bd9Sstevel@tonic-gate break; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (pic[0] == NULL || pic[1] == NULL) { 4777c478bd9Sstevel@tonic-gate __cpc_error(fn, gettext("two events must be specified\n")); 4787c478bd9Sstevel@tonic-gate errcnt++; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate return (errcnt); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 4857c478bd9Sstevel@tonic-gate * Return a printable description of the control registers. 4867c478bd9Sstevel@tonic-gate * 4877c478bd9Sstevel@tonic-gate * This routine should always succeed (notwithstanding heap problems), 4887c478bd9Sstevel@tonic-gate * but may not be able to correctly decode the registers, if, for 4897c478bd9Sstevel@tonic-gate * example, a new processor is under test. 4907c478bd9Sstevel@tonic-gate * 4917c478bd9Sstevel@tonic-gate * The caller is responsible for free(3c)ing the string returned. 4927c478bd9Sstevel@tonic-gate */ 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate static void 4957c478bd9Sstevel@tonic-gate flagstostr(char *buf, int flag0, int flag1, int defvalue, char *tok) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate buf += strlen(buf); 4987c478bd9Sstevel@tonic-gate if (flag0 != defvalue) { 4997c478bd9Sstevel@tonic-gate if (flag1 != defvalue) 5007c478bd9Sstevel@tonic-gate (void) sprintf(buf, ",%s", tok); 5017c478bd9Sstevel@tonic-gate else 5027c478bd9Sstevel@tonic-gate (void) sprintf(buf, ",%s0", tok); 5037c478bd9Sstevel@tonic-gate } else { 5047c478bd9Sstevel@tonic-gate if (flag1 != defvalue) 5057c478bd9Sstevel@tonic-gate (void) sprintf(buf, ",%s1", tok); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate static void 5107c478bd9Sstevel@tonic-gate masktostr(char *buf, uint8_t bits, char *tok) 5117c478bd9Sstevel@tonic-gate { 5127c478bd9Sstevel@tonic-gate if (bits != 0) { 5137c478bd9Sstevel@tonic-gate buf += strlen(buf); 5147c478bd9Sstevel@tonic-gate (void) sprintf(buf, ",%s=0x%x", tok, bits); 5157c478bd9Sstevel@tonic-gate } 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate static char * 5197c478bd9Sstevel@tonic-gate val8tostr(uint8_t bits) 5207c478bd9Sstevel@tonic-gate { 5217c478bd9Sstevel@tonic-gate char buf[2 + 2 + 1]; /* 0x %2x \0 */ 5227c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "0x%x", bits); 5237c478bd9Sstevel@tonic-gate return (strdup(buf)); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate static char * 5277c478bd9Sstevel@tonic-gate regtostr(int cpuver, int regno, uint8_t bits) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate const char *sname; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL) 5327c478bd9Sstevel@tonic-gate return (strdup(sname)); 5337c478bd9Sstevel@tonic-gate return (val8tostr(bits)); 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate struct xpes { 5377c478bd9Sstevel@tonic-gate uint8_t cmask, umask, evsel; 5387c478bd9Sstevel@tonic-gate int usr, sys, edge, inv, irupt, pc; 5397c478bd9Sstevel@tonic-gate }; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 5427c478bd9Sstevel@tonic-gate static void 5437c478bd9Sstevel@tonic-gate unmake_pes(uint32_t pes, int cpuver, struct xpes *xpes) 5447c478bd9Sstevel@tonic-gate { 5457c478bd9Sstevel@tonic-gate xpes->cmask = (uint8_t)(pes >> CPC_P6_PES_CMASK_SHIFT); 5467c478bd9Sstevel@tonic-gate xpes->pc = (pes >> CPC_P6_PES_PC) & 1u; 5477c478bd9Sstevel@tonic-gate xpes->inv = (pes >> CPC_P6_PES_INV) & 1u; 5487c478bd9Sstevel@tonic-gate xpes->irupt = (pes >> CPC_P6_PES_INT) & 1u; 5497c478bd9Sstevel@tonic-gate xpes->edge = (pes >> CPC_P6_PES_E) & 1u; 5507c478bd9Sstevel@tonic-gate xpes->sys = (pes >> CPC_P6_PES_OS) & 1u; 5517c478bd9Sstevel@tonic-gate xpes->usr = (pes >> CPC_P6_PES_USR) & 1u; 5527c478bd9Sstevel@tonic-gate xpes->umask = (uint8_t)(pes >> CPC_P6_PES_UMASK_SHIFT); 5537c478bd9Sstevel@tonic-gate xpes->evsel = (uint8_t)pes; 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate struct xcesr { 5577c478bd9Sstevel@tonic-gate uint8_t evsel[2]; 5587c478bd9Sstevel@tonic-gate int usr[2], sys[2], clk[2], pc[2]; 5597c478bd9Sstevel@tonic-gate }; 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 5627c478bd9Sstevel@tonic-gate static void 5637c478bd9Sstevel@tonic-gate unmake_cesr(uint32_t cesr, int cpuver, struct xcesr *xcesr) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate xcesr->evsel[0] = (cesr >> CPC_P5_CESR_ES0_SHIFT) & 5667c478bd9Sstevel@tonic-gate CPC_P5_CESR_ES0_MASK; 5677c478bd9Sstevel@tonic-gate xcesr->evsel[1] = (cesr >> CPC_P5_CESR_ES1_SHIFT) & 5687c478bd9Sstevel@tonic-gate CPC_P5_CESR_ES1_MASK; 5697c478bd9Sstevel@tonic-gate xcesr->usr[0] = (cesr >> CPC_P5_CESR_USR0) & 1u; 5707c478bd9Sstevel@tonic-gate xcesr->usr[1] = (cesr >> CPC_P5_CESR_USR1) & 1u; 5717c478bd9Sstevel@tonic-gate xcesr->sys[0] = (cesr >> CPC_P5_CESR_OS0) & 1u; 5727c478bd9Sstevel@tonic-gate xcesr->sys[1] = (cesr >> CPC_P5_CESR_OS1) & 1u; 5737c478bd9Sstevel@tonic-gate xcesr->clk[0] = (cesr >> CPC_P5_CESR_CLK0) & 1u; 5747c478bd9Sstevel@tonic-gate xcesr->clk[1] = (cesr >> CPC_P5_CESR_CLK1) & 1u; 5757c478bd9Sstevel@tonic-gate xcesr->pc[0] = (cesr >> CPC_P5_CESR_PC0) & 1u; 5767c478bd9Sstevel@tonic-gate xcesr->pc[1] = (cesr >> CPC_P5_CESR_PC1) & 1u; 5777c478bd9Sstevel@tonic-gate /* 5787c478bd9Sstevel@tonic-gate * If usr and sys are both disabled, the counter is disabled. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate if (xcesr->usr[0] == 0 && xcesr->sys[0] == 0) 5817c478bd9Sstevel@tonic-gate xcesr->clk[0] = 0; 5827c478bd9Sstevel@tonic-gate if (xcesr->usr[1] == 0 && xcesr->sys[1] == 0) 5837c478bd9Sstevel@tonic-gate xcesr->clk[1] = 0; 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate char * 5877c478bd9Sstevel@tonic-gate cpc_eventtostr(cpc_event_t *event) 5887c478bd9Sstevel@tonic-gate { 5897c478bd9Sstevel@tonic-gate char *pic[2]; 5907c478bd9Sstevel@tonic-gate char buffer[1024]; 5917c478bd9Sstevel@tonic-gate int cpuver = event->ce_cpuver; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate switch (cpuver) { 5947c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 5957c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO: 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate struct xpes xpes[2]; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate unmake_pes(event->ce_pes[0], cpuver, &xpes[0]); 6007c478bd9Sstevel@tonic-gate if ((pic[0] = regtostr(cpuver, 0, xpes[0].evsel)) == NULL) 6017c478bd9Sstevel@tonic-gate return (NULL); 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate unmake_pes(event->ce_pes[1], cpuver, &xpes[1]); 6047c478bd9Sstevel@tonic-gate if ((pic[1] = regtostr(cpuver, 1, xpes[1].evsel)) == NULL) { 6057c478bd9Sstevel@tonic-gate free(pic[0]); 6067c478bd9Sstevel@tonic-gate return (NULL); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 6097c478bd9Sstevel@tonic-gate tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 6107c478bd9Sstevel@tonic-gate free(pic[1]); 6117c478bd9Sstevel@tonic-gate free(pic[0]); 6127c478bd9Sstevel@tonic-gate masktostr(buffer, xpes[0].cmask, tokens[D_cmask0]); 6137c478bd9Sstevel@tonic-gate masktostr(buffer, xpes[1].cmask, tokens[D_cmask1]); 6147c478bd9Sstevel@tonic-gate masktostr(buffer, xpes[0].umask, tokens[D_umask0]); 6157c478bd9Sstevel@tonic-gate masktostr(buffer, xpes[1].umask, tokens[D_umask1]); 6167c478bd9Sstevel@tonic-gate flagstostr(buffer, 6177c478bd9Sstevel@tonic-gate xpes[0].usr, xpes[1].usr, 1, tokens[D_nouser]); 6187c478bd9Sstevel@tonic-gate flagstostr(buffer, 6197c478bd9Sstevel@tonic-gate xpes[0].sys, xpes[1].sys, 0, tokens[D_sys]); 6207c478bd9Sstevel@tonic-gate flagstostr(buffer, 6217c478bd9Sstevel@tonic-gate xpes[0].edge, xpes[1].edge, 1, tokens[D_noedge]); 6227c478bd9Sstevel@tonic-gate flagstostr(buffer, 6237c478bd9Sstevel@tonic-gate xpes[0].irupt, xpes[1].irupt, 0, tokens[D_int]); 6247c478bd9Sstevel@tonic-gate flagstostr(buffer, 6257c478bd9Sstevel@tonic-gate xpes[0].inv, xpes[1].inv, 0, tokens[D_inv]); 6267c478bd9Sstevel@tonic-gate flagstostr(buffer, 6277c478bd9Sstevel@tonic-gate xpes[0].pc, xpes[1].pc, 0, tokens[D_pc]); 628*23a1cceaSRoger A. Faulkner break; 629*23a1cceaSRoger A. Faulkner } 6307c478bd9Sstevel@tonic-gate case CPC_PENTIUM_MMX: 6317c478bd9Sstevel@tonic-gate case CPC_PENTIUM: 6327c478bd9Sstevel@tonic-gate { 6337c478bd9Sstevel@tonic-gate struct xcesr xcesr; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate unmake_cesr(event->ce_cesr, cpuver, &xcesr); 6367c478bd9Sstevel@tonic-gate if ((pic[0] = regtostr(cpuver, 0, xcesr.evsel[0])) == NULL) 6377c478bd9Sstevel@tonic-gate return (NULL); 6387c478bd9Sstevel@tonic-gate if ((pic[1] = regtostr(cpuver, 1, xcesr.evsel[1])) == NULL) { 6397c478bd9Sstevel@tonic-gate free(pic[0]); 6407c478bd9Sstevel@tonic-gate return (NULL); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s", 6437c478bd9Sstevel@tonic-gate tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]); 6447c478bd9Sstevel@tonic-gate free(pic[1]); 6457c478bd9Sstevel@tonic-gate free(pic[0]); 6467c478bd9Sstevel@tonic-gate flagstostr(buffer, 6477c478bd9Sstevel@tonic-gate xcesr.usr[0], xcesr.usr[1], 1, tokens[D_nouser]); 6487c478bd9Sstevel@tonic-gate flagstostr(buffer, 6497c478bd9Sstevel@tonic-gate xcesr.sys[0], xcesr.sys[1], 0, tokens[D_sys]); 6507c478bd9Sstevel@tonic-gate flagstostr(buffer, 6517c478bd9Sstevel@tonic-gate xcesr.clk[0], xcesr.clk[1], 0, tokens[D_noedge]); 6527c478bd9Sstevel@tonic-gate flagstostr(buffer, 6537c478bd9Sstevel@tonic-gate xcesr.pc[0], xcesr.pc[1], 0, tokens[D_pc]); 654*23a1cceaSRoger A. Faulkner break; 655*23a1cceaSRoger A. Faulkner } 6567c478bd9Sstevel@tonic-gate default: 6577c478bd9Sstevel@tonic-gate return (NULL); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate return (strdup(buffer)); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * Utility operations on events 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate void 6667c478bd9Sstevel@tonic-gate cpc_event_accum(cpc_event_t *accum, cpc_event_t *event) 6677c478bd9Sstevel@tonic-gate { 6687c478bd9Sstevel@tonic-gate if (accum->ce_hrt < event->ce_hrt) 6697c478bd9Sstevel@tonic-gate accum->ce_hrt = event->ce_hrt; 6707c478bd9Sstevel@tonic-gate accum->ce_tsc += event->ce_tsc; 6717c478bd9Sstevel@tonic-gate accum->ce_pic[0] += event->ce_pic[0]; 6727c478bd9Sstevel@tonic-gate accum->ce_pic[1] += event->ce_pic[1]; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate void 6767c478bd9Sstevel@tonic-gate cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate diff->ce_hrt = left->ce_hrt; 6797c478bd9Sstevel@tonic-gate diff->ce_tsc = left->ce_tsc - right->ce_tsc; 6807c478bd9Sstevel@tonic-gate diff->ce_pic[0] = left->ce_pic[0] - right->ce_pic[0]; 6817c478bd9Sstevel@tonic-gate diff->ce_pic[1] = left->ce_pic[1] - right->ce_pic[1]; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * Given a cpc_event_t and cpc_bind_event() flags, 6867c478bd9Sstevel@tonic-gate * translate the cpc_event_t into the cpc_set_t format. 6877c478bd9Sstevel@tonic-gate * 6887c478bd9Sstevel@tonic-gate * Returns NULL on failure. 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate cpc_set_t * 6917c478bd9Sstevel@tonic-gate __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags) 6927c478bd9Sstevel@tonic-gate { 6937c478bd9Sstevel@tonic-gate cpc_set_t *set; 6947c478bd9Sstevel@tonic-gate int cpuver = event->ce_cpuver; 6957c478bd9Sstevel@tonic-gate char *pic[2]; 6967c478bd9Sstevel@tonic-gate int flags[2] = { 0, 0 }; 6977c478bd9Sstevel@tonic-gate int i; 6987c478bd9Sstevel@tonic-gate int j; 6997c478bd9Sstevel@tonic-gate int nattrs; 7007c478bd9Sstevel@tonic-gate cpc_attr_t *attr; 7017c478bd9Sstevel@tonic-gate int intr; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate if ((set = cpc_set_create(cpc)) == NULL) { 7047c478bd9Sstevel@tonic-gate return (NULL); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate if (iflags & CPC_BIND_EMT_OVF) 7087c478bd9Sstevel@tonic-gate flags[0] = flags[1] = CPC_OVF_NOTIFY_EMT; 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate switch (cpuver) { 7117c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO_MMX: 7127c478bd9Sstevel@tonic-gate case CPC_PENTIUM_PRO: 7137c478bd9Sstevel@tonic-gate { 7147c478bd9Sstevel@tonic-gate struct xpes xpes[2]; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 7177c478bd9Sstevel@tonic-gate intr = 0; 7187c478bd9Sstevel@tonic-gate nattrs = j = 1; 7197c478bd9Sstevel@tonic-gate unmake_pes(event->ce_pes[i], cpuver, &xpes[i]); 7207c478bd9Sstevel@tonic-gate if ((pic[i] = regtostr(cpuver, i, 7217c478bd9Sstevel@tonic-gate xpes[i].evsel)) == NULL) { 7227c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 7237c478bd9Sstevel@tonic-gate return (NULL); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate if (xpes[i].usr == 1) 7267c478bd9Sstevel@tonic-gate flags[i] |= CPC_COUNT_USER; 7277c478bd9Sstevel@tonic-gate if (xpes[i].sys == 1) 7287c478bd9Sstevel@tonic-gate flags[i] |= CPC_COUNT_SYSTEM; 7297c478bd9Sstevel@tonic-gate if (xpes[i].irupt == 1) { 7307c478bd9Sstevel@tonic-gate nattrs++; 7317c478bd9Sstevel@tonic-gate intr = 1; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate if (xpes[i].cmask) 7357c478bd9Sstevel@tonic-gate nattrs++; 7367c478bd9Sstevel@tonic-gate if (xpes[i].umask) 7377c478bd9Sstevel@tonic-gate nattrs++; 7387c478bd9Sstevel@tonic-gate if (xpes[i].inv) 7397c478bd9Sstevel@tonic-gate nattrs++; 7407c478bd9Sstevel@tonic-gate if (xpes[i].pc) 7417c478bd9Sstevel@tonic-gate nattrs++; 7427c478bd9Sstevel@tonic-gate if (xpes[i].edge == 0) 7437c478bd9Sstevel@tonic-gate nattrs++; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if ((attr = (cpc_attr_t *)malloc(nattrs * 7467c478bd9Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) { 7477c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 7487c478bd9Sstevel@tonic-gate errno = ENOMEM; 7497c478bd9Sstevel@tonic-gate return (NULL); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* 7537c478bd9Sstevel@tonic-gate * Ensure that pic[0] in the cpc_event_t is bound to 7547c478bd9Sstevel@tonic-gate * physical pic0. 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate attr[0].ca_name = "picnum"; 7577c478bd9Sstevel@tonic-gate attr[0].ca_val = i; 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate if (intr) { 7607c478bd9Sstevel@tonic-gate attr[j].ca_name = "int"; 7617c478bd9Sstevel@tonic-gate attr[j].ca_val = 1; 7627c478bd9Sstevel@tonic-gate j++; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate if (xpes[i].cmask) { 7657c478bd9Sstevel@tonic-gate attr[j].ca_name = "cmask"; 7667c478bd9Sstevel@tonic-gate attr[j].ca_val = xpes[i].cmask; 7677c478bd9Sstevel@tonic-gate j++; 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate if (xpes[i].umask) { 7707c478bd9Sstevel@tonic-gate attr[j].ca_name = "umask"; 7717c478bd9Sstevel@tonic-gate attr[j].ca_val = xpes[i].umask; 7727c478bd9Sstevel@tonic-gate j++; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate if (xpes[i].inv) { 7757c478bd9Sstevel@tonic-gate attr[j].ca_name = "inv"; 7767c478bd9Sstevel@tonic-gate attr[j].ca_val = 1; 7777c478bd9Sstevel@tonic-gate j++; 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate if (xpes[i].pc) { 7807c478bd9Sstevel@tonic-gate attr[j].ca_name = "pc"; 7817c478bd9Sstevel@tonic-gate attr[j].ca_val = 1; 7827c478bd9Sstevel@tonic-gate j++; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate if (xpes[i].edge == 0) { 7857c478bd9Sstevel@tonic-gate attr[j].ca_name = "noedge"; 7867c478bd9Sstevel@tonic-gate attr[j].ca_val = 1; 7877c478bd9Sstevel@tonic-gate j++; 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, pic[i], 7917c478bd9Sstevel@tonic-gate event->ce_pic[i], flags[i], nattrs, attr) == -1) { 7927c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 7937c478bd9Sstevel@tonic-gate free(pic[i]); 7947c478bd9Sstevel@tonic-gate free(attr); 7957c478bd9Sstevel@tonic-gate return (NULL); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate free(pic[i]); 7987c478bd9Sstevel@tonic-gate free(attr); 7997c478bd9Sstevel@tonic-gate } 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate break; 8027c478bd9Sstevel@tonic-gate case CPC_PENTIUM_MMX: 8037c478bd9Sstevel@tonic-gate case CPC_PENTIUM: 8047c478bd9Sstevel@tonic-gate { 8057c478bd9Sstevel@tonic-gate struct xcesr xcesr; 8067c478bd9Sstevel@tonic-gate unmake_cesr(event->ce_cesr, cpuver, &xcesr); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) { 8097c478bd9Sstevel@tonic-gate nattrs = j = 1; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate if ((pic[i] = regtostr(cpuver, i, xcesr.evsel[i])) 8127c478bd9Sstevel@tonic-gate == NULL) { 8137c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 8147c478bd9Sstevel@tonic-gate return (NULL); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate if (xcesr.usr[i] == 1) 8187c478bd9Sstevel@tonic-gate flags[i] |= CPC_COUNT_USER; 8197c478bd9Sstevel@tonic-gate if (xcesr.sys[i] == 1) 8207c478bd9Sstevel@tonic-gate flags[i] |= CPC_COUNT_SYSTEM; 8217c478bd9Sstevel@tonic-gate if (xcesr.clk[i] == 1) 8227c478bd9Sstevel@tonic-gate nattrs++; 8237c478bd9Sstevel@tonic-gate if (xcesr.pc[i] == 1) 8247c478bd9Sstevel@tonic-gate nattrs++; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate if ((attr = (cpc_attr_t *)malloc(nattrs * 8277c478bd9Sstevel@tonic-gate sizeof (cpc_attr_t))) == NULL) { 8287c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 8297c478bd9Sstevel@tonic-gate errno = ENOMEM; 8307c478bd9Sstevel@tonic-gate return (NULL); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * Ensure that pic[0] in the cpc_event_t is bound to 8357c478bd9Sstevel@tonic-gate * physical pic0. 8367c478bd9Sstevel@tonic-gate */ 8377c478bd9Sstevel@tonic-gate attr[0].ca_name = "picnum"; 8387c478bd9Sstevel@tonic-gate attr[0].ca_val = i; 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate if (xcesr.clk[i] == 1) { 8417c478bd9Sstevel@tonic-gate attr[j].ca_name = "noedge"; 8427c478bd9Sstevel@tonic-gate attr[j].ca_val = 1; 8437c478bd9Sstevel@tonic-gate j++; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate if (xcesr.pc[i] == 1) { 8477c478bd9Sstevel@tonic-gate attr[j].ca_name = "pc"; 8487c478bd9Sstevel@tonic-gate attr[j].ca_val = 1; 8497c478bd9Sstevel@tonic-gate j++; 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate if (cpc_set_add_request(cpc, set, pic[i], 8537c478bd9Sstevel@tonic-gate event->ce_pic[i], flags[i], nattrs, attr) == -1) { 8547c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 8557c478bd9Sstevel@tonic-gate free(pic[i]); 8567c478bd9Sstevel@tonic-gate free(attr); 8577c478bd9Sstevel@tonic-gate return (NULL); 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate free(pic[i]); 8617c478bd9Sstevel@tonic-gate free(attr); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate break; 8657c478bd9Sstevel@tonic-gate default: 8667c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(cpc, set); 8677c478bd9Sstevel@tonic-gate return (NULL); 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate 8707c478bd9Sstevel@tonic-gate return (set); 8717c478bd9Sstevel@tonic-gate } 872