libpmc.c revision 233628
1145256Sjkoshy/*- 2177107Sjkoshy * Copyright (c) 2003-2008 Joseph Koshy 3145256Sjkoshy * All rights reserved. 4145256Sjkoshy * 5145256Sjkoshy * Redistribution and use in source and binary forms, with or without 6145256Sjkoshy * modification, are permitted provided that the following conditions 7145256Sjkoshy * are met: 8145256Sjkoshy * 1. Redistributions of source code must retain the above copyright 9145256Sjkoshy * notice, this list of conditions and the following disclaimer. 10145256Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11145256Sjkoshy * notice, this list of conditions and the following disclaimer in the 12145256Sjkoshy * documentation and/or other materials provided with the distribution. 13145256Sjkoshy * 14145256Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15145256Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16145256Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17145256Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18145256Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19145256Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20145256Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21145256Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22145256Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23145256Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24145256Sjkoshy * SUCH DAMAGE. 25145256Sjkoshy */ 26145256Sjkoshy 27145256Sjkoshy#include <sys/cdefs.h> 28145256Sjkoshy__FBSDID("$FreeBSD: head/lib/libpmc/libpmc.c 233628 2012-03-28 20:58:30Z fabient $"); 29145256Sjkoshy 30145256Sjkoshy#include <sys/types.h> 31145256Sjkoshy#include <sys/module.h> 32145256Sjkoshy#include <sys/pmc.h> 33145256Sjkoshy#include <sys/syscall.h> 34145256Sjkoshy 35145256Sjkoshy#include <ctype.h> 36145256Sjkoshy#include <errno.h> 37145256Sjkoshy#include <fcntl.h> 38145256Sjkoshy#include <pmc.h> 39145256Sjkoshy#include <stdio.h> 40145256Sjkoshy#include <stdlib.h> 41145256Sjkoshy#include <string.h> 42145256Sjkoshy#include <strings.h> 43145256Sjkoshy#include <unistd.h> 44145256Sjkoshy 45185363Sjkoshy#include "libpmcinternal.h" 46185363Sjkoshy 47145256Sjkoshy/* Function prototypes */ 48145340Smarcel#if defined(__i386__) 49145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 50145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 51147191Sjkoshy#endif 52147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 53185363Sjkoshystatic int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 54185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 55185363Sjkoshystatic int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 56185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 57206089Sfabientstatic int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 58206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 59206089Sfabientstatic int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 60206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 61147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 62145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 63147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 64147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 65147191Sjkoshy#endif 66147191Sjkoshy#if defined(__i386__) 67145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 68145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 69147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 70145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 71145256Sjkoshy#endif 72183725Sjkoshy#if defined(__amd64__) || defined(__i386__) 73183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 74183725Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 75183725Sjkoshy#endif 76200928Srpaulo#if defined(__XSCALE__) 77200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 78200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 79200928Srpaulo#endif 80204635Sgnn#if defined(__mips__) 81233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 82204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 83204635Sgnn#endif /* __mips__ */ 84233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 85233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 86204635Sgnn 87228869Sjhibbits#if defined(__powerpc__) 88228869Sjhibbitsstatic int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec, 89228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 90228869Sjhibbits#endif /* __powerpc__ */ 91204635Sgnn 92145256Sjkoshy#define PMC_CALL(cmd, params) \ 93145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 94145256Sjkoshy 95145256Sjkoshy/* 96145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 97145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 98145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 99145256Sjkoshy * lookup table. 100145256Sjkoshy */ 101145256Sjkoshystruct pmc_event_alias { 102145256Sjkoshy const char *pm_alias; 103145256Sjkoshy const char *pm_spec; 104145256Sjkoshy}; 105145256Sjkoshy 106145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 107145256Sjkoshy 108145256Sjkoshy/* 109183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 110145256Sjkoshy * to integer codes used by the PMC KLD. 111145256Sjkoshy */ 112145256Sjkoshystruct pmc_event_descr { 113145256Sjkoshy const char *pm_ev_name; 114145256Sjkoshy enum pmc_event pm_ev_code; 115145256Sjkoshy}; 116145256Sjkoshy 117183725Sjkoshy/* 118183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 119183725Sjkoshy * event names to event tables and other PMC class data. 120183725Sjkoshy */ 121183725Sjkoshystruct pmc_class_descr { 122183725Sjkoshy const char *pm_evc_name; 123183725Sjkoshy size_t pm_evc_name_size; 124183725Sjkoshy enum pmc_class pm_evc_class; 125183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 126183725Sjkoshy size_t pm_evc_event_table_size; 127183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 128183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 129183725Sjkoshy}; 130183725Sjkoshy 131183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 132183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 133183725Sjkoshy 134183725Sjkoshy#undef __PMC_EV 135183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 136183725Sjkoshy 137183725Sjkoshy/* 138185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 139183725Sjkoshy * 140185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 141183725Sjkoshy */ 142185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 143183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 144183725Sjkoshy { \ 145183725Sjkoshy __PMC_EV_##C() \ 146185363Sjkoshy } 147185363Sjkoshy 148185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 149185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 150185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 151185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 152185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 153185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 154200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 155204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 156233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 157206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 158228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 159185363Sjkoshy 160233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 161233628Sfabient 162185363Sjkoshy#undef __PMC_EV_ALIAS 163185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 164185363Sjkoshy 165185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 166185363Sjkoshy{ 167185363Sjkoshy __PMC_EV_ALIAS_ATOM() 168185363Sjkoshy}; 169185363Sjkoshy 170185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 171185363Sjkoshy{ 172185363Sjkoshy __PMC_EV_ALIAS_CORE() 173185363Sjkoshy}; 174185363Sjkoshy 175185363Sjkoshy 176185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 177185363Sjkoshy{ 178185363Sjkoshy __PMC_EV_ALIAS_CORE2() 179185363Sjkoshy}; 180185363Sjkoshy 181187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 182187761Sjeff{ 183187761Sjeff __PMC_EV_ALIAS_COREI7() 184187761Sjeff}; 185187761Sjeff 186232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 187232366Sdavide{ 188232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 189232366Sdavide}; 190232366Sdavide 191206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 192206089Sfabient{ 193206089Sfabient __PMC_EV_ALIAS_WESTMERE() 194206089Sfabient}; 195206089Sfabient 196206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 197206089Sfabient{ 198206089Sfabient __PMC_EV_ALIAS_COREI7UC() 199206089Sfabient}; 200206089Sfabient 201232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 202232366Sdavide{ 203232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 204232366Sdavide}; 205232366Sdavide 206206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 207206089Sfabient{ 208206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 209206089Sfabient}; 210206089Sfabient 211185363Sjkoshy/* 212185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 213185363Sjkoshy * 214185363Sjkoshy * Map a CPU to the PMC classes it supports. 215185363Sjkoshy */ 216185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 217183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 218183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 219183725Sjkoshy } 220183725Sjkoshy 221233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 222233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 223233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 224233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 225233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 226233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 227233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 228233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 229233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 230233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 231233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 232233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 233233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 234233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 235233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 236233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 237183725Sjkoshy 238183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 239145256Sjkoshy{ 240183725Sjkoshy __PMC_EV_TSC() 241145256Sjkoshy}; 242145256Sjkoshy 243183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 244185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 245185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 246185363Sjkoshy { \ 247185363Sjkoshy .pm_evc_name = #CLASS "-", \ 248185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 249185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 250185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 251183725Sjkoshy .pm_evc_event_table_size = \ 252185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 253185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 254183725Sjkoshy } 255183725Sjkoshy 256185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 257185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 258185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 259185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 260185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 261187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 262232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 263206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 264206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 265206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 266232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 267206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 268185363Sjkoshy#endif 269183725Sjkoshy#if defined(__i386__) 270185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 271183725Sjkoshy#endif 272183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 273185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 274185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 275183725Sjkoshy#endif 276183725Sjkoshy#if defined(__i386__) 277185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 278185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 279183725Sjkoshy#endif 280183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 281185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 282183725Sjkoshy#endif 283200928Srpaulo#if defined(__XSCALE__) 284200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 285200928Srpaulo#endif 286204635Sgnn#if defined(__mips__) 287233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 288233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 289204635Sgnn#endif /* __mips__ */ 290228869Sjhibbits#if defined(__powerpc__) 291228869SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450); 292228869Sjhibbits#endif 293228869Sjhibbits 294233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 295233628Sfabient{ 296233628Sfabient .pm_evc_name = "SOFT-", 297233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 298233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 299233628Sfabient .pm_evc_event_table = NULL, 300233628Sfabient .pm_evc_event_table_size = 0, 301233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 302233628Sfabient}; 303233628Sfabient 304183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 305183725Sjkoshy 306185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 307185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 308185363Sjkoshy 309183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 310183725Sjkoshystatic size_t pmc_mdep_class_list_size; 311183725Sjkoshy 312145256Sjkoshy/* 313145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 314145256Sjkoshy * strings. 315145256Sjkoshy */ 316145256Sjkoshy 317145256Sjkoshystatic const char * pmc_capability_names[] = { 318145256Sjkoshy#undef __PMC_CAP 319145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 320145256Sjkoshy __PMC_CAPS() 321145256Sjkoshy}; 322145256Sjkoshy 323145256Sjkoshystatic const char * pmc_class_names[] = { 324145256Sjkoshy#undef __PMC_CLASS 325145256Sjkoshy#define __PMC_CLASS(C) #C , 326145256Sjkoshy __PMC_CLASSES() 327145256Sjkoshy}; 328145256Sjkoshy 329183725Sjkoshystruct pmc_cputype_map { 330228557Sdim enum pmc_cputype pm_cputype; 331183725Sjkoshy const char *pm_name; 332183725Sjkoshy}; 333183725Sjkoshy 334183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 335145256Sjkoshy#undef __PMC_CPU 336183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 337145256Sjkoshy __PMC_CPUS() 338145256Sjkoshy}; 339145256Sjkoshy 340145256Sjkoshystatic const char * pmc_disposition_names[] = { 341145256Sjkoshy#undef __PMC_DISP 342145256Sjkoshy#define __PMC_DISP(D) #D , 343145256Sjkoshy __PMC_DISPOSITIONS() 344145256Sjkoshy}; 345145256Sjkoshy 346145256Sjkoshystatic const char * pmc_mode_names[] = { 347145256Sjkoshy#undef __PMC_MODE 348145256Sjkoshy#define __PMC_MODE(M,N) #M , 349145256Sjkoshy __PMC_MODES() 350145256Sjkoshy}; 351145256Sjkoshy 352145256Sjkoshystatic const char * pmc_state_names[] = { 353145256Sjkoshy#undef __PMC_STATE 354145256Sjkoshy#define __PMC_STATE(S) #S , 355145256Sjkoshy __PMC_STATES() 356145256Sjkoshy}; 357145256Sjkoshy 358233628Sfabient/* 359233628Sfabient * Filled in by pmc_init(). 360233628Sfabient */ 361233628Sfabientstatic int pmc_syscall = -1; 362233628Sfabientstatic struct pmc_cpuinfo cpu_info; 363233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 364145256Sjkoshy 365145256Sjkoshy/* Event masks for events */ 366145256Sjkoshystruct pmc_masks { 367145256Sjkoshy const char *pm_name; 368145256Sjkoshy const uint32_t pm_value; 369145256Sjkoshy}; 370145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 371206089Sfabient#define NULLMASK { .pm_name = NULL } 372145256Sjkoshy 373147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 374145256Sjkoshystatic int 375145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 376145256Sjkoshy{ 377145256Sjkoshy const struct pmc_masks *pm; 378145256Sjkoshy char *q, *r; 379145256Sjkoshy int c; 380145256Sjkoshy 381145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 382174406Sjkoshy return (-1); 383183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 384145256Sjkoshy if (*++q == '\0') /* no more data */ 385174406Sjkoshy return (-1); 386145256Sjkoshy c = 0; /* count of mask keywords seen */ 387145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 388183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 389183725Sjkoshy pm++) 390145256Sjkoshy ; 391145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 392174406Sjkoshy return (-1); 393145256Sjkoshy *evmask |= pm->pm_value; 394145256Sjkoshy c++; 395145256Sjkoshy } 396174406Sjkoshy return (c); 397145256Sjkoshy} 398145340Smarcel#endif 399145256Sjkoshy 400145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 401145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 402145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 403145256Sjkoshy 404145340Smarcel#if defined(__i386__) 405145256Sjkoshy 406145256Sjkoshy/* 407145256Sjkoshy * AMD K7 (Athlon) CPUs. 408145256Sjkoshy */ 409145256Sjkoshy 410145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 411145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 412145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 413145351Sjkoshy EV_ALIAS("cycles", "tsc"), 414183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 415145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 416145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 417145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 418145351Sjkoshy EV_ALIAS(NULL, NULL) 419145256Sjkoshy}; 420145256Sjkoshy 421145256Sjkoshy#define K7_KW_COUNT "count" 422145256Sjkoshy#define K7_KW_EDGE "edge" 423145256Sjkoshy#define K7_KW_INV "inv" 424145256Sjkoshy#define K7_KW_OS "os" 425145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 426145256Sjkoshy#define K7_KW_USR "usr" 427145256Sjkoshy 428145256Sjkoshystatic int 429145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 430145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 431145256Sjkoshy{ 432183107Sjkoshy char *e, *p, *q; 433183107Sjkoshy int c, has_unitmask; 434145256Sjkoshy uint32_t count, unitmask; 435145256Sjkoshy 436147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 437183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 438145256Sjkoshy 439145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 440145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 441145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 442145256Sjkoshy has_unitmask = 1; 443147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 444145256Sjkoshy } else 445145256Sjkoshy unitmask = has_unitmask = 0; 446145256Sjkoshy 447145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 448145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 449145256Sjkoshy q = strchr(p, '='); 450145256Sjkoshy if (*++q == '\0') /* skip '=' */ 451174406Sjkoshy return (-1); 452145256Sjkoshy 453145256Sjkoshy count = strtol(q, &e, 0); 454145256Sjkoshy if (e == q || *e != '\0') 455174406Sjkoshy return (-1); 456145256Sjkoshy 457145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 458147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 459147191Sjkoshy AMD_PMC_TO_COUNTER(count); 460145256Sjkoshy 461145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 462145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 463145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 464145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 465145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 466145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 467145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 468145256Sjkoshy if (has_unitmask == 0) 469174406Sjkoshy return (-1); 470145256Sjkoshy unitmask = 0; 471145256Sjkoshy q = strchr(p, '='); 472145256Sjkoshy if (*++q == '\0') /* skip '=' */ 473174406Sjkoshy return (-1); 474145256Sjkoshy 475145256Sjkoshy while ((c = tolower(*q++)) != 0) 476145256Sjkoshy if (c == 'm') 477147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 478145256Sjkoshy else if (c == 'o') 479147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 480145256Sjkoshy else if (c == 'e') 481147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 482145256Sjkoshy else if (c == 's') 483147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 484145256Sjkoshy else if (c == 'i') 485147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 486145256Sjkoshy else if (c == '+') 487145256Sjkoshy continue; 488145256Sjkoshy else 489174406Sjkoshy return (-1); 490145256Sjkoshy 491145256Sjkoshy if (unitmask == 0) 492174406Sjkoshy return (-1); 493145256Sjkoshy 494145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 495145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 496145256Sjkoshy } else 497174406Sjkoshy return (-1); 498145256Sjkoshy } 499145256Sjkoshy 500145256Sjkoshy if (has_unitmask) { 501145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 502147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 503147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 504145256Sjkoshy } 505145256Sjkoshy 506174406Sjkoshy return (0); 507145256Sjkoshy 508145256Sjkoshy} 509145256Sjkoshy 510147191Sjkoshy#endif 511147191Sjkoshy 512147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 513147191Sjkoshy 514145256Sjkoshy/* 515185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 516185363Sjkoshy */ 517185363Sjkoshy 518185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 519185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 520185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 521185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 522185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 523185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 524185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 525185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 526185363Sjkoshy EV_ALIAS(NULL, NULL) 527185363Sjkoshy}; 528185363Sjkoshy 529185363Sjkoshy/* 530185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 531185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 532198433Sjkoshy * 533198433Sjkoshy * We map aliases to events on the fixed-function counters if these 534198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 535198433Sjkoshy * counters. 536185363Sjkoshy */ 537185363Sjkoshy 538185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 539185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 540185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 541185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 542185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 543185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 544185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 545185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 546185363Sjkoshy EV_ALIAS(NULL, NULL) 547185363Sjkoshy}; 548185363Sjkoshy 549198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 550198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 551198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 552198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 553198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 554198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 555198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 556198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 557198433Sjkoshy EV_ALIAS(NULL, NULL) 558198433Sjkoshy}; 559198433Sjkoshy 560198433Sjkoshy#define atom_aliases core2_aliases 561198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 562198433Sjkoshy#define corei7_aliases core2_aliases 563198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 564232366Sdavide#define sandybridge_aliases core2_aliases 565232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 566206089Sfabient#define westmere_aliases core2_aliases 567206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 568198433Sjkoshy 569185363Sjkoshy#define IAF_KW_OS "os" 570185363Sjkoshy#define IAF_KW_USR "usr" 571185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 572185363Sjkoshy 573185363Sjkoshy/* 574185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 575185363Sjkoshy */ 576185363Sjkoshystatic int 577185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 578185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 579185363Sjkoshy{ 580185363Sjkoshy char *p; 581185363Sjkoshy 582185363Sjkoshy (void) pe; 583185363Sjkoshy 584185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 585185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 586185363Sjkoshy 587185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 588185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 589185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 590185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 591185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 592185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 593185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 594185363Sjkoshy else 595185363Sjkoshy return (-1); 596185363Sjkoshy } 597185363Sjkoshy 598185363Sjkoshy return (0); 599185363Sjkoshy} 600185363Sjkoshy 601185363Sjkoshy/* 602185363Sjkoshy * Core/Core2 support. 603185363Sjkoshy */ 604185363Sjkoshy 605185363Sjkoshy#define IAP_KW_AGENT "agent" 606185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 607185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 608185363Sjkoshy#define IAP_KW_CMASK "cmask" 609185363Sjkoshy#define IAP_KW_CORE "core" 610185363Sjkoshy#define IAP_KW_EDGE "edge" 611185363Sjkoshy#define IAP_KW_INV "inv" 612185363Sjkoshy#define IAP_KW_OS "os" 613185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 614185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 615185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 616185363Sjkoshy#define IAP_KW_TRANSITION "trans" 617185363Sjkoshy#define IAP_KW_USR "usr" 618206089Sfabient#define IAP_KW_RSP "rsp" 619185363Sjkoshy 620185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 621185363Sjkoshy PMCMASK(all, (0x3 << 14)), 622185363Sjkoshy PMCMASK(this, (0x1 << 14)), 623185363Sjkoshy NULLMASK 624185363Sjkoshy}; 625185363Sjkoshy 626185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 627185363Sjkoshy PMCMASK(this, 0), 628185363Sjkoshy PMCMASK(any, (0x1 << 13)), 629185363Sjkoshy NULLMASK 630185363Sjkoshy}; 631185363Sjkoshy 632185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 633185363Sjkoshy PMCMASK(both, (0x3 << 12)), 634185363Sjkoshy PMCMASK(only, (0x1 << 12)), 635185363Sjkoshy PMCMASK(exclude, 0), 636185363Sjkoshy NULLMASK 637185363Sjkoshy}; 638185363Sjkoshy 639185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 640185363Sjkoshy PMCMASK(i, (1 << 8)), 641185363Sjkoshy PMCMASK(s, (1 << 9)), 642185363Sjkoshy PMCMASK(e, (1 << 10)), 643185363Sjkoshy PMCMASK(m, (1 << 11)), 644185363Sjkoshy NULLMASK 645185363Sjkoshy}; 646185363Sjkoshy 647185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 648185363Sjkoshy PMCMASK(clean, (1 << 8)), 649185363Sjkoshy PMCMASK(hit, (1 << 9)), 650185363Sjkoshy PMCMASK(hitm, (1 << 11)), 651185363Sjkoshy NULLMASK 652185363Sjkoshy}; 653185363Sjkoshy 654185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 655185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 656185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 657185363Sjkoshy NULLMASK 658185363Sjkoshy}; 659185363Sjkoshy 660185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 661185363Sjkoshy PMCMASK(any, 0x00), 662185363Sjkoshy PMCMASK(frequency, 0x10), 663185363Sjkoshy NULLMASK 664185363Sjkoshy}; 665185363Sjkoshy 666206089Sfabientstatic struct pmc_masks iap_rsp_mask[] = { 667206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 668206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 669206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 670206089Sfabient PMCMASK(WB, (1 << 3)), 671206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 672206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 673206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 674206089Sfabient PMCMASK(OTHER, (1 << 7)), 675206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 676206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 677206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 678206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 679206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 680206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 681206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 682206089Sfabient NULLMASK 683206089Sfabient}; 684206089Sfabient 685185363Sjkoshystatic int 686185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 687185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 688185363Sjkoshy{ 689185363Sjkoshy char *e, *p, *q; 690206089Sfabient uint32_t cachestate, evmask, rsp; 691185363Sjkoshy int count, n; 692185363Sjkoshy 693185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 694185363Sjkoshy PMC_CAP_QUALIFIER); 695185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 696185363Sjkoshy 697206089Sfabient cachestate = evmask = rsp = 0; 698185363Sjkoshy 699185363Sjkoshy /* Parse additional modifiers if present */ 700185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 701185363Sjkoshy 702185363Sjkoshy n = 0; 703185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 704185363Sjkoshy q = strchr(p, '='); 705185363Sjkoshy if (*++q == '\0') /* skip '=' */ 706185363Sjkoshy return (-1); 707185363Sjkoshy count = strtol(q, &e, 0); 708185363Sjkoshy if (e == q || *e != '\0') 709185363Sjkoshy return (-1); 710185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 711185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 712185363Sjkoshy IAP_CMASK(count); 713185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 714185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 715185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 716185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 717185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 718185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 719185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 720185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 721185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 722185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 723193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 724185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 725185363Sjkoshy if (n != 1) 726185363Sjkoshy return (-1); 727193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 728185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 729185363Sjkoshy if (n != 1) 730185363Sjkoshy return (-1); 731193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 732185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 733185363Sjkoshy if (n != 1) 734185363Sjkoshy return (-1); 735193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 736185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 737185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 738193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 739185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 740185363Sjkoshy if (n != 1) 741185363Sjkoshy return (-1); 742185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 743185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 744206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 745193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 746185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 747185363Sjkoshy &evmask); 748193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 749185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 750185363Sjkoshy &evmask); 751185363Sjkoshy } else 752185363Sjkoshy return (-1); 753206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 754206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 755206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 756206089Sfabient n = pmc_parse_mask(iap_rsp_mask, p, &rsp); 757206089Sfabient } else 758206089Sfabient return (-1); 759185363Sjkoshy } else 760185363Sjkoshy return (-1); 761185363Sjkoshy 762185363Sjkoshy if (n < 0) /* Parsing failed. */ 763185363Sjkoshy return (-1); 764185363Sjkoshy } 765185363Sjkoshy 766185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 767185363Sjkoshy 768185363Sjkoshy /* 769185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 770185363Sjkoshy * specified by the user, use a sensible default. 771185363Sjkoshy */ 772185363Sjkoshy switch (pe) { 773185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 774185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 775185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 776185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 777185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 778185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 779185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 780185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 781185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 782185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 783185363Sjkoshy if (cachestate == 0) 784185363Sjkoshy cachestate = (0xF << 8); 785207482Srstone break; 786207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 787207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 788207482Srstone * Atom processor 789207482Srstone */ 790207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 791207482Srstone cachestate = (0xF << 8); 792207482Srstone break; 793185363Sjkoshy default: 794185363Sjkoshy break; 795185363Sjkoshy } 796185363Sjkoshy 797185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 798206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 799185363Sjkoshy 800185363Sjkoshy return (0); 801185363Sjkoshy} 802185363Sjkoshy 803185363Sjkoshy/* 804206089Sfabient * Intel Uncore. 805206089Sfabient */ 806206089Sfabient 807206089Sfabientstatic int 808206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 809206089Sfabient struct pmc_op_pmcallocate *pmc_config) 810206089Sfabient{ 811206089Sfabient (void) pe; 812206089Sfabient (void) ctrspec; 813206089Sfabient 814206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 815206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 816206089Sfabient 817206089Sfabient return (0); 818206089Sfabient} 819206089Sfabient 820206089Sfabient#define UCP_KW_CMASK "cmask" 821206089Sfabient#define UCP_KW_EDGE "edge" 822206089Sfabient#define UCP_KW_INV "inv" 823206089Sfabient 824206089Sfabientstatic int 825206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 826206089Sfabient struct pmc_op_pmcallocate *pmc_config) 827206089Sfabient{ 828206089Sfabient char *e, *p, *q; 829206089Sfabient int count, n; 830206089Sfabient 831206089Sfabient (void) pe; 832206089Sfabient 833206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 834206089Sfabient PMC_CAP_QUALIFIER); 835206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 836206089Sfabient 837206089Sfabient /* Parse additional modifiers if present */ 838206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 839206089Sfabient 840206089Sfabient n = 0; 841206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 842206089Sfabient q = strchr(p, '='); 843206089Sfabient if (*++q == '\0') /* skip '=' */ 844206089Sfabient return (-1); 845206089Sfabient count = strtol(q, &e, 0); 846206089Sfabient if (e == q || *e != '\0') 847206089Sfabient return (-1); 848206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 849206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 850206089Sfabient UCP_CMASK(count); 851206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 852206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 853206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 854206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 855206089Sfabient } else 856206089Sfabient return (-1); 857206089Sfabient 858206089Sfabient if (n < 0) /* Parsing failed. */ 859206089Sfabient return (-1); 860206089Sfabient } 861206089Sfabient 862206089Sfabient return (0); 863206089Sfabient} 864206089Sfabient 865206089Sfabient/* 866147191Sjkoshy * AMD K8 PMCs. 867147191Sjkoshy * 868147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 869147191Sjkoshy * events. 870147191Sjkoshy */ 871147191Sjkoshy 872147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 873147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 874147191Sjkoshy EV_ALIAS("branch-mispredicts", 875147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 876147191Sjkoshy EV_ALIAS("cycles", "tsc"), 877147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 878147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 879183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 880147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 881155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 882147191Sjkoshy EV_ALIAS(NULL, NULL) 883147191Sjkoshy}; 884147191Sjkoshy 885147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 886147191Sjkoshy 887147191Sjkoshy/* 888147191Sjkoshy * Parsing tables 889147191Sjkoshy */ 890147191Sjkoshy 891147191Sjkoshy/* fp dispatched fpu ops */ 892147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 893147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 894147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 895147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 896147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 897147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 898147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 899147191Sjkoshy NULLMASK 900147191Sjkoshy}; 901147191Sjkoshy 902147191Sjkoshy/* ls segment register loads */ 903147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 904147191Sjkoshy __K8MASK(es, 0), 905147191Sjkoshy __K8MASK(cs, 1), 906147191Sjkoshy __K8MASK(ss, 2), 907147191Sjkoshy __K8MASK(ds, 3), 908147191Sjkoshy __K8MASK(fs, 4), 909147191Sjkoshy __K8MASK(gs, 5), 910147191Sjkoshy __K8MASK(hs, 6), 911147191Sjkoshy NULLMASK 912147191Sjkoshy}; 913147191Sjkoshy 914147191Sjkoshy/* ls locked operation */ 915147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 916147191Sjkoshy __K8MASK(locked-instructions, 0), 917147191Sjkoshy __K8MASK(cycles-in-request, 1), 918147191Sjkoshy __K8MASK(cycles-to-complete, 2), 919147191Sjkoshy NULLMASK 920147191Sjkoshy}; 921147191Sjkoshy 922147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 923147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 924147191Sjkoshy __K8MASK(invalid, 0), 925147191Sjkoshy __K8MASK(shared, 1), 926147191Sjkoshy __K8MASK(exclusive, 2), 927147191Sjkoshy __K8MASK(owner, 3), 928147191Sjkoshy __K8MASK(modified, 4), 929147191Sjkoshy NULLMASK 930147191Sjkoshy}; 931147191Sjkoshy 932147191Sjkoshy/* dc one bit ecc error */ 933147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 934147191Sjkoshy __K8MASK(scrubber, 0), 935147191Sjkoshy __K8MASK(piggyback, 1), 936147191Sjkoshy NULLMASK 937147191Sjkoshy}; 938147191Sjkoshy 939147191Sjkoshy/* dc dispatched prefetch instructions */ 940147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 941147191Sjkoshy __K8MASK(load, 0), 942147191Sjkoshy __K8MASK(store, 1), 943147191Sjkoshy __K8MASK(nta, 2), 944147191Sjkoshy NULLMASK 945147191Sjkoshy}; 946147191Sjkoshy 947147191Sjkoshy/* dc dcache accesses by locks */ 948147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 949147191Sjkoshy __K8MASK(accesses, 0), 950147191Sjkoshy __K8MASK(misses, 1), 951147191Sjkoshy NULLMASK 952147191Sjkoshy}; 953147191Sjkoshy 954147191Sjkoshy/* bu internal l2 request */ 955147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 956147191Sjkoshy __K8MASK(ic-fill, 0), 957147191Sjkoshy __K8MASK(dc-fill, 1), 958147191Sjkoshy __K8MASK(tlb-reload, 2), 959147191Sjkoshy __K8MASK(tag-snoop, 3), 960147191Sjkoshy __K8MASK(cancelled, 4), 961147191Sjkoshy NULLMASK 962147191Sjkoshy}; 963147191Sjkoshy 964147191Sjkoshy/* bu fill request l2 miss */ 965147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 966147191Sjkoshy __K8MASK(ic-fill, 0), 967147191Sjkoshy __K8MASK(dc-fill, 1), 968147191Sjkoshy __K8MASK(tlb-reload, 2), 969147191Sjkoshy NULLMASK 970147191Sjkoshy}; 971147191Sjkoshy 972147191Sjkoshy/* bu fill into l2 */ 973147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 974147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 975147191Sjkoshy __K8MASK(victim-from-l2, 1), 976147191Sjkoshy NULLMASK 977147191Sjkoshy}; 978147191Sjkoshy 979147191Sjkoshy/* fr retired fpu instructions */ 980147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 981147191Sjkoshy __K8MASK(x87, 0), 982147191Sjkoshy __K8MASK(mmx-3dnow, 1), 983147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 984147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 985147191Sjkoshy NULLMASK 986147191Sjkoshy}; 987147191Sjkoshy 988147191Sjkoshy/* fr retired fastpath double op instructions */ 989147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 990147191Sjkoshy __K8MASK(low-op-pos-0, 0), 991147191Sjkoshy __K8MASK(low-op-pos-1, 1), 992147191Sjkoshy __K8MASK(low-op-pos-2, 2), 993147191Sjkoshy NULLMASK 994147191Sjkoshy}; 995147191Sjkoshy 996147191Sjkoshy/* fr fpu exceptions */ 997147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 998147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 999147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1000147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1001147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1002147191Sjkoshy NULLMASK 1003147191Sjkoshy}; 1004147191Sjkoshy 1005147191Sjkoshy/* nb memory controller page access event */ 1006147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1007147191Sjkoshy __K8MASK(page-hit, 0), 1008147191Sjkoshy __K8MASK(page-miss, 1), 1009147191Sjkoshy __K8MASK(page-conflict, 2), 1010147191Sjkoshy NULLMASK 1011147191Sjkoshy}; 1012147191Sjkoshy 1013147191Sjkoshy/* nb memory controller turnaround */ 1014147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1015147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1016147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1017147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1018147191Sjkoshy NULLMASK 1019147191Sjkoshy}; 1020147191Sjkoshy 1021147191Sjkoshy/* nb memory controller bypass saturation */ 1022147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1023147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1024147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1025147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1026147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1027147191Sjkoshy NULLMASK 1028147191Sjkoshy}; 1029147191Sjkoshy 1030147191Sjkoshy/* nb sized commands */ 1031147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1032147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1033147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1034147191Sjkoshy __K8MASK(postwrszbyte, 2), 1035147191Sjkoshy __K8MASK(postwrszdword, 3), 1036147191Sjkoshy __K8MASK(rdszbyte, 4), 1037147191Sjkoshy __K8MASK(rdszdword, 5), 1038147191Sjkoshy __K8MASK(rdmodwr, 6), 1039147191Sjkoshy NULLMASK 1040147191Sjkoshy}; 1041147191Sjkoshy 1042147191Sjkoshy/* nb probe result */ 1043147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1044147191Sjkoshy __K8MASK(probe-miss, 0), 1045147191Sjkoshy __K8MASK(probe-hit, 1), 1046147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1047147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1048147191Sjkoshy NULLMASK 1049147191Sjkoshy}; 1050147191Sjkoshy 1051147191Sjkoshy/* nb hypertransport bus bandwidth */ 1052147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1053147191Sjkoshy __K8MASK(command, 0), 1054183107Sjkoshy __K8MASK(data, 1), 1055147191Sjkoshy __K8MASK(buffer-release, 2), 1056147191Sjkoshy __K8MASK(nop, 3), 1057147191Sjkoshy NULLMASK 1058147191Sjkoshy}; 1059147191Sjkoshy 1060147191Sjkoshy#undef __K8MASK 1061147191Sjkoshy 1062147191Sjkoshy#define K8_KW_COUNT "count" 1063147191Sjkoshy#define K8_KW_EDGE "edge" 1064147191Sjkoshy#define K8_KW_INV "inv" 1065147191Sjkoshy#define K8_KW_MASK "mask" 1066147191Sjkoshy#define K8_KW_OS "os" 1067147191Sjkoshy#define K8_KW_USR "usr" 1068147191Sjkoshy 1069147191Sjkoshystatic int 1070147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1071147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1072147191Sjkoshy{ 1073183107Sjkoshy char *e, *p, *q; 1074183107Sjkoshy int n; 1075147191Sjkoshy uint32_t count, evmask; 1076147191Sjkoshy const struct pmc_masks *pm, *pmask; 1077147191Sjkoshy 1078183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1079147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1080147191Sjkoshy 1081147191Sjkoshy pmask = NULL; 1082147191Sjkoshy evmask = 0; 1083147191Sjkoshy 1084147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1085147191Sjkoshy 1086147191Sjkoshy /* setup parsing tables */ 1087147191Sjkoshy switch (pe) { 1088147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1089147191Sjkoshy __K8SETMASK(fdfo); 1090147191Sjkoshy break; 1091147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1092147191Sjkoshy __K8SETMASK(lsrl); 1093147191Sjkoshy break; 1094147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1095147191Sjkoshy __K8SETMASK(llo); 1096147191Sjkoshy break; 1097147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1098147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1099147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1100147191Sjkoshy __K8SETMASK(dc); 1101147191Sjkoshy break; 1102147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1103147191Sjkoshy __K8SETMASK(dobee); 1104147191Sjkoshy break; 1105147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1106147191Sjkoshy __K8SETMASK(ddpi); 1107147191Sjkoshy break; 1108147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1109147191Sjkoshy __K8SETMASK(dabl); 1110147191Sjkoshy break; 1111147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1112147191Sjkoshy __K8SETMASK(bilr); 1113147191Sjkoshy break; 1114147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1115147191Sjkoshy __K8SETMASK(bfrlm); 1116147191Sjkoshy break; 1117147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1118147191Sjkoshy __K8SETMASK(bfil); 1119147191Sjkoshy break; 1120147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1121147191Sjkoshy __K8SETMASK(frfi); 1122147191Sjkoshy break; 1123147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1124147191Sjkoshy __K8SETMASK(frfdoi); 1125147191Sjkoshy break; 1126147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1127147191Sjkoshy __K8SETMASK(ffe); 1128147191Sjkoshy break; 1129147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1130147191Sjkoshy __K8SETMASK(nmcpae); 1131147191Sjkoshy break; 1132147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1133147191Sjkoshy __K8SETMASK(nmct); 1134147191Sjkoshy break; 1135147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1136147191Sjkoshy __K8SETMASK(nmcbs); 1137147191Sjkoshy break; 1138147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1139147191Sjkoshy __K8SETMASK(nsc); 1140147191Sjkoshy break; 1141147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1142147191Sjkoshy __K8SETMASK(npr); 1143147191Sjkoshy break; 1144147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1145147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1146147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1147147191Sjkoshy __K8SETMASK(nhbb); 1148147191Sjkoshy break; 1149147191Sjkoshy 1150147191Sjkoshy default: 1151147191Sjkoshy break; /* no options defined */ 1152147191Sjkoshy } 1153147191Sjkoshy 1154147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1155147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1156147191Sjkoshy q = strchr(p, '='); 1157147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1158174406Sjkoshy return (-1); 1159147191Sjkoshy 1160147191Sjkoshy count = strtol(q, &e, 0); 1161147191Sjkoshy if (e == q || *e != '\0') 1162174406Sjkoshy return (-1); 1163147191Sjkoshy 1164147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1165147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1166147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1167147191Sjkoshy 1168147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1169147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1170147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1171147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1172147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1173147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1174174406Sjkoshy return (-1); 1175147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1176147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1177147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1178147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1179147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1180147191Sjkoshy } else 1181174406Sjkoshy return (-1); 1182147191Sjkoshy } 1183147191Sjkoshy 1184147191Sjkoshy /* other post processing */ 1185147191Sjkoshy switch (pe) { 1186147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1187147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1188147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1189147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1190147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1191147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1192147191Sjkoshy /* XXX only available in rev B and later */ 1193147191Sjkoshy break; 1194147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1195147191Sjkoshy /* XXX only available in rev C and later */ 1196147191Sjkoshy break; 1197147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1198147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1199147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1200174406Sjkoshy return (-1); 1201147191Sjkoshy if (evmask == 0) { 1202147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1203147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1204147191Sjkoshy } 1205147191Sjkoshy break; 1206147191Sjkoshy default: 1207147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1208147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1209147191Sjkoshy evmask |= pm->pm_value; 1210147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1211147191Sjkoshy } 1212147191Sjkoshy } 1213147191Sjkoshy 1214147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1215147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1216147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1217147191Sjkoshy 1218174406Sjkoshy return (0); 1219147191Sjkoshy} 1220147191Sjkoshy 1221147191Sjkoshy#endif 1222147191Sjkoshy 1223147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1224147191Sjkoshy 1225147191Sjkoshy/* 1226145256Sjkoshy * Intel P4 PMCs 1227145256Sjkoshy */ 1228145256Sjkoshy 1229145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1230145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1231145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1232145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1233145351Sjkoshy EV_ALIAS("instructions", 1234145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1235155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1236145256Sjkoshy EV_ALIAS(NULL, NULL) 1237145256Sjkoshy}; 1238145256Sjkoshy 1239145256Sjkoshy#define P4_KW_ACTIVE "active" 1240145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1241145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1242145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1243145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1244145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1245145256Sjkoshy#define P4_KW_CASCADE "cascade" 1246145256Sjkoshy#define P4_KW_EDGE "edge" 1247145256Sjkoshy#define P4_KW_INV "complement" 1248145256Sjkoshy#define P4_KW_OS "os" 1249145256Sjkoshy#define P4_KW_MASK "mask" 1250145256Sjkoshy#define P4_KW_PRECISE "precise" 1251145256Sjkoshy#define P4_KW_TAG "tag" 1252145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1253145256Sjkoshy#define P4_KW_USR "usr" 1254145256Sjkoshy 1255145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1256145256Sjkoshy 1257145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1258145256Sjkoshy __P4MASK(dd, 0), 1259145256Sjkoshy __P4MASK(db, 1), 1260145256Sjkoshy __P4MASK(di, 2), 1261145256Sjkoshy __P4MASK(bd, 3), 1262145256Sjkoshy __P4MASK(bb, 4), 1263145256Sjkoshy __P4MASK(bi, 5), 1264145256Sjkoshy __P4MASK(id, 6), 1265145256Sjkoshy __P4MASK(ib, 7), 1266145256Sjkoshy NULLMASK 1267145256Sjkoshy}; 1268145256Sjkoshy 1269145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1270145256Sjkoshy __P4MASK(tcmiss, 0), 1271145256Sjkoshy NULLMASK, 1272145256Sjkoshy}; 1273145256Sjkoshy 1274145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1275145256Sjkoshy __P4MASK(hit, 0), 1276145256Sjkoshy __P4MASK(miss, 1), 1277145256Sjkoshy __P4MASK(hit-uc, 2), 1278145256Sjkoshy NULLMASK 1279145256Sjkoshy}; 1280145256Sjkoshy 1281145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1282145256Sjkoshy __P4MASK(st-rb-full, 2), 1283145256Sjkoshy __P4MASK(64k-conf, 3), 1284145256Sjkoshy NULLMASK 1285145256Sjkoshy}; 1286145256Sjkoshy 1287145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1288145256Sjkoshy __P4MASK(lsc, 0), 1289145256Sjkoshy __P4MASK(ssc, 1), 1290145256Sjkoshy NULLMASK 1291145256Sjkoshy}; 1292145256Sjkoshy 1293145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1294145256Sjkoshy __P4MASK(split-ld, 1), 1295145256Sjkoshy NULLMASK 1296145256Sjkoshy}; 1297145256Sjkoshy 1298145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1299145256Sjkoshy __P4MASK(split-st, 1), 1300145256Sjkoshy NULLMASK 1301145256Sjkoshy}; 1302145256Sjkoshy 1303145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1304145256Sjkoshy __P4MASK(no-sta, 1), 1305145256Sjkoshy __P4MASK(no-std, 3), 1306145256Sjkoshy __P4MASK(partial-data, 4), 1307145256Sjkoshy __P4MASK(unalgn-addr, 5), 1308145256Sjkoshy NULLMASK 1309145256Sjkoshy}; 1310145256Sjkoshy 1311145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1312145256Sjkoshy __P4MASK(dtmiss, 0), 1313145256Sjkoshy __P4MASK(itmiss, 1), 1314145256Sjkoshy NULLMASK 1315145256Sjkoshy}; 1316145256Sjkoshy 1317145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1318145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1319145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1320145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1321145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1322145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1323145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1324145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1325145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1326145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1327145256Sjkoshy NULLMASK 1328145256Sjkoshy}; 1329145256Sjkoshy 1330145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1331145256Sjkoshy __P4MASK(all-read, 5), 1332145256Sjkoshy __P4MASK(all-write, 6), 1333145256Sjkoshy __P4MASK(mem-uc, 7), 1334145256Sjkoshy __P4MASK(mem-wc, 8), 1335145256Sjkoshy __P4MASK(mem-wt, 9), 1336145256Sjkoshy __P4MASK(mem-wp, 10), 1337145256Sjkoshy __P4MASK(mem-wb, 11), 1338145256Sjkoshy __P4MASK(own, 13), 1339145256Sjkoshy __P4MASK(other, 14), 1340145256Sjkoshy __P4MASK(prefetch, 15), 1341145256Sjkoshy NULLMASK 1342145256Sjkoshy}; 1343145256Sjkoshy 1344145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1345145256Sjkoshy __P4MASK(all-read, 5), 1346145256Sjkoshy __P4MASK(all-write, 6), 1347145256Sjkoshy __P4MASK(mem-uc, 7), 1348145256Sjkoshy __P4MASK(mem-wc, 8), 1349145256Sjkoshy __P4MASK(mem-wt, 9), 1350145256Sjkoshy __P4MASK(mem-wp, 10), 1351145256Sjkoshy __P4MASK(mem-wb, 11), 1352145256Sjkoshy __P4MASK(own, 13), 1353145256Sjkoshy __P4MASK(other, 14), 1354145256Sjkoshy __P4MASK(prefetch, 15), 1355145256Sjkoshy NULLMASK 1356145256Sjkoshy}; 1357145256Sjkoshy 1358145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1359145256Sjkoshy __P4MASK(drdy-drv, 0), 1360145256Sjkoshy __P4MASK(drdy-own, 1), 1361145256Sjkoshy __P4MASK(drdy-other, 2), 1362145256Sjkoshy __P4MASK(dbsy-drv, 3), 1363145256Sjkoshy __P4MASK(dbsy-own, 4), 1364145256Sjkoshy __P4MASK(dbsy-other, 5), 1365145256Sjkoshy NULLMASK 1366145256Sjkoshy}; 1367145256Sjkoshy 1368145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1369145256Sjkoshy __P4MASK(req-type0, 0), 1370145256Sjkoshy __P4MASK(req-type1, 1), 1371145256Sjkoshy __P4MASK(req-len0, 2), 1372145256Sjkoshy __P4MASK(req-len1, 3), 1373145256Sjkoshy __P4MASK(req-io-type, 5), 1374145256Sjkoshy __P4MASK(req-lock-type, 6), 1375145256Sjkoshy __P4MASK(req-cache-type, 7), 1376145256Sjkoshy __P4MASK(req-split-type, 8), 1377145256Sjkoshy __P4MASK(req-dem-type, 9), 1378145256Sjkoshy __P4MASK(req-ord-type, 10), 1379145256Sjkoshy __P4MASK(mem-type0, 11), 1380145256Sjkoshy __P4MASK(mem-type1, 12), 1381145256Sjkoshy __P4MASK(mem-type2, 13), 1382145256Sjkoshy NULLMASK 1383145256Sjkoshy}; 1384145256Sjkoshy 1385145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1386145256Sjkoshy __P4MASK(all, 15), 1387145256Sjkoshy NULLMASK 1388145256Sjkoshy}; 1389145256Sjkoshy 1390145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1391145256Sjkoshy __P4MASK(all, 15), 1392145256Sjkoshy NULLMASK 1393145256Sjkoshy}; 1394145256Sjkoshy 1395145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1396145256Sjkoshy __P4MASK(all, 15), 1397145256Sjkoshy NULLMASK 1398145256Sjkoshy}; 1399145256Sjkoshy 1400145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1401145256Sjkoshy __P4MASK(all, 15), 1402145256Sjkoshy NULLMASK 1403145256Sjkoshy}; 1404145256Sjkoshy 1405145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1406145256Sjkoshy __P4MASK(all, 15), 1407145256Sjkoshy NULLMASK 1408145256Sjkoshy}; 1409145256Sjkoshy 1410145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1411145256Sjkoshy __P4MASK(all, 15), 1412145256Sjkoshy NULLMASK 1413145256Sjkoshy}; 1414145256Sjkoshy 1415145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1416145256Sjkoshy __P4MASK(all, 15), 1417145256Sjkoshy NULLMASK 1418145256Sjkoshy}; 1419145256Sjkoshy 1420145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1421145256Sjkoshy __P4MASK(all, 15), 1422145256Sjkoshy NULLMASK 1423145256Sjkoshy}; 1424145256Sjkoshy 1425145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1426145256Sjkoshy __P4MASK(allp0, 3), 1427145256Sjkoshy __P4MASK(allp2, 4), 1428145256Sjkoshy NULLMASK 1429145256Sjkoshy}; 1430145256Sjkoshy 1431145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1432145256Sjkoshy __P4MASK(running, 0), 1433145256Sjkoshy NULLMASK 1434145256Sjkoshy}; 1435145256Sjkoshy 1436145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1437145256Sjkoshy __P4MASK(cisc, 0), 1438145256Sjkoshy NULLMASK 1439145256Sjkoshy}; 1440145256Sjkoshy 1441145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1442145256Sjkoshy __P4MASK(from-tc-build, 0), 1443145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1444145256Sjkoshy __P4MASK(from-rom, 2), 1445145256Sjkoshy NULLMASK 1446145256Sjkoshy}; 1447145256Sjkoshy 1448145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1449145351Sjkoshy /* retired mispred branch type */ 1450145256Sjkoshy __P4MASK(conditional, 1), 1451145256Sjkoshy __P4MASK(call, 2), 1452145256Sjkoshy __P4MASK(return, 3), 1453145256Sjkoshy __P4MASK(indirect, 4), 1454145256Sjkoshy NULLMASK 1455145256Sjkoshy}; 1456145256Sjkoshy 1457145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1458145256Sjkoshy __P4MASK(conditional, 1), 1459145256Sjkoshy __P4MASK(call, 2), 1460145256Sjkoshy __P4MASK(retired, 3), 1461145256Sjkoshy __P4MASK(indirect, 4), 1462145256Sjkoshy NULLMASK 1463145256Sjkoshy}; 1464145256Sjkoshy 1465145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1466145256Sjkoshy __P4MASK(sbfull, 5), 1467145256Sjkoshy NULLMASK 1468145256Sjkoshy}; 1469145256Sjkoshy 1470145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1471145256Sjkoshy __P4MASK(wcb-evicts, 0), 1472145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1473145256Sjkoshy NULLMASK 1474145256Sjkoshy}; 1475145256Sjkoshy 1476145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1477145256Sjkoshy __P4MASK(nbogus, 0), 1478145256Sjkoshy __P4MASK(bogus, 1), 1479145256Sjkoshy NULLMASK 1480145256Sjkoshy}; 1481145256Sjkoshy 1482145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1483145256Sjkoshy __P4MASK(nbogus0, 0), 1484145256Sjkoshy __P4MASK(nbogus1, 1), 1485145256Sjkoshy __P4MASK(nbogus2, 2), 1486145256Sjkoshy __P4MASK(nbogus3, 3), 1487145256Sjkoshy __P4MASK(bogus0, 4), 1488145256Sjkoshy __P4MASK(bogus1, 5), 1489145256Sjkoshy __P4MASK(bogus2, 6), 1490145256Sjkoshy __P4MASK(bogus3, 7), 1491145256Sjkoshy NULLMASK 1492145256Sjkoshy}; 1493145256Sjkoshy 1494145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1495145256Sjkoshy __P4MASK(nbogus, 0), 1496145256Sjkoshy __P4MASK(bogus, 1), 1497145256Sjkoshy NULLMASK 1498145256Sjkoshy}; 1499145256Sjkoshy 1500145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1501145256Sjkoshy __P4MASK(nbogusntag, 0), 1502145256Sjkoshy __P4MASK(nbogustag, 1), 1503145256Sjkoshy __P4MASK(bogusntag, 2), 1504145256Sjkoshy __P4MASK(bogustag, 3), 1505145256Sjkoshy NULLMASK 1506145256Sjkoshy}; 1507145256Sjkoshy 1508145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1509145256Sjkoshy __P4MASK(nbogus, 0), 1510145256Sjkoshy __P4MASK(bogus, 1), 1511145256Sjkoshy NULLMASK 1512145256Sjkoshy}; 1513145256Sjkoshy 1514145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1515145256Sjkoshy __P4MASK(tagloads, 1), 1516145256Sjkoshy __P4MASK(tagstores, 2), 1517145256Sjkoshy NULLMASK 1518145256Sjkoshy}; 1519145256Sjkoshy 1520145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1521145256Sjkoshy __P4MASK(mmnp, 0), 1522145256Sjkoshy __P4MASK(mmnm, 1), 1523145256Sjkoshy __P4MASK(mmtp, 2), 1524145256Sjkoshy __P4MASK(mmtm, 3), 1525145256Sjkoshy NULLMASK 1526145256Sjkoshy}; 1527145256Sjkoshy 1528145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1529145256Sjkoshy __P4MASK(nbogus, 0), 1530145256Sjkoshy NULLMASK 1531145256Sjkoshy}; 1532145256Sjkoshy 1533145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1534145256Sjkoshy __P4MASK(fpsu, 0), 1535145256Sjkoshy __P4MASK(fpso, 1), 1536145256Sjkoshy __P4MASK(poao, 2), 1537145256Sjkoshy __P4MASK(poau, 3), 1538145256Sjkoshy __P4MASK(prea, 4), 1539145256Sjkoshy NULLMASK 1540145256Sjkoshy}; 1541145256Sjkoshy 1542145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1543145256Sjkoshy __P4MASK(clear, 0), 1544145256Sjkoshy __P4MASK(moclear, 2), 1545145256Sjkoshy __P4MASK(smclear, 3), 1546145256Sjkoshy NULLMASK 1547145256Sjkoshy}; 1548145256Sjkoshy 1549145256Sjkoshy/* P4 event parser */ 1550145256Sjkoshystatic int 1551145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1552145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1553145256Sjkoshy{ 1554145256Sjkoshy 1555145256Sjkoshy char *e, *p, *q; 1556145256Sjkoshy int count, has_tag, has_busreqtype, n; 1557145256Sjkoshy uint32_t evmask, cccractivemask; 1558145256Sjkoshy const struct pmc_masks *pm, *pmask; 1559145256Sjkoshy 1560183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1561147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1562147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1563145256Sjkoshy 1564145256Sjkoshy pmask = NULL; 1565145256Sjkoshy evmask = 0; 1566145256Sjkoshy cccractivemask = 0x3; 1567145256Sjkoshy has_tag = has_busreqtype = 0; 1568145256Sjkoshy 1569145256Sjkoshy#define __P4SETMASK(M) do { \ 1570183107Sjkoshy pmask = p4_mask_##M; \ 1571145256Sjkoshy} while (0) 1572145256Sjkoshy 1573145256Sjkoshy switch (pe) { 1574145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1575145256Sjkoshy __P4SETMASK(tcdm); 1576145256Sjkoshy break; 1577145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1578145256Sjkoshy __P4SETMASK(bfr); 1579145256Sjkoshy break; 1580145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1581145256Sjkoshy __P4SETMASK(ir); 1582145256Sjkoshy break; 1583145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1584145256Sjkoshy __P4SETMASK(memcan); 1585145256Sjkoshy break; 1586145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1587145256Sjkoshy __P4SETMASK(memcomp); 1588145256Sjkoshy break; 1589145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1590145256Sjkoshy __P4SETMASK(lpr); 1591145256Sjkoshy break; 1592145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1593145256Sjkoshy __P4SETMASK(spr); 1594145256Sjkoshy break; 1595145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1596145256Sjkoshy __P4SETMASK(mlr); 1597145256Sjkoshy break; 1598145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1599145256Sjkoshy __P4SETMASK(pwt); 1600145256Sjkoshy break; 1601145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1602145256Sjkoshy __P4SETMASK(bcr); 1603145256Sjkoshy break; 1604145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1605145256Sjkoshy __P4SETMASK(ia); 1606145256Sjkoshy has_busreqtype = 1; 1607145256Sjkoshy break; 1608145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1609145256Sjkoshy __P4SETMASK(iae); 1610145256Sjkoshy has_busreqtype = 1; 1611145256Sjkoshy break; 1612145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1613145256Sjkoshy __P4SETMASK(fda); 1614145256Sjkoshy break; 1615145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1616145256Sjkoshy __P4SETMASK(ba); 1617145256Sjkoshy break; 1618145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1619145256Sjkoshy __P4SETMASK(sia); 1620145256Sjkoshy break; 1621145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1622145256Sjkoshy __P4SETMASK(psu); 1623145256Sjkoshy break; 1624145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1625145256Sjkoshy __P4SETMASK(pdu); 1626145256Sjkoshy break; 1627145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1628145256Sjkoshy __P4SETMASK(ssu); 1629145256Sjkoshy break; 1630145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1631145256Sjkoshy __P4SETMASK(sdu); 1632145256Sjkoshy break; 1633145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1634145256Sjkoshy __P4SETMASK(64bmu); 1635145256Sjkoshy break; 1636145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1637145256Sjkoshy __P4SETMASK(128bmu); 1638145256Sjkoshy break; 1639145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1640145256Sjkoshy __P4SETMASK(xfu); 1641145256Sjkoshy break; 1642145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1643145256Sjkoshy __P4SETMASK(xsmu); 1644145256Sjkoshy break; 1645145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1646145256Sjkoshy __P4SETMASK(gpe); 1647145256Sjkoshy break; 1648145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1649145256Sjkoshy __P4SETMASK(tmx); 1650145256Sjkoshy break; 1651145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1652145256Sjkoshy __P4SETMASK(uqw); 1653145256Sjkoshy break; 1654145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1655145256Sjkoshy __P4SETMASK(rmbt); 1656145256Sjkoshy break; 1657145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1658145256Sjkoshy __P4SETMASK(rbt); 1659145256Sjkoshy break; 1660145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1661145256Sjkoshy __P4SETMASK(rs); 1662145256Sjkoshy break; 1663145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1664145256Sjkoshy __P4SETMASK(wb); 1665145256Sjkoshy break; 1666145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1667145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1668145256Sjkoshy case PMC_EV_P4_BNR: 1669145256Sjkoshy case PMC_EV_P4_SNOOP: 1670145256Sjkoshy case PMC_EV_P4_RESPONSE: 1671145256Sjkoshy break; 1672145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1673145256Sjkoshy __P4SETMASK(fee); 1674145256Sjkoshy break; 1675145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1676145256Sjkoshy __P4SETMASK(ee); 1677145256Sjkoshy break; 1678145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1679145256Sjkoshy __P4SETMASK(re); 1680145256Sjkoshy break; 1681145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1682145256Sjkoshy __P4SETMASK(insret); 1683145256Sjkoshy break; 1684145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1685145256Sjkoshy __P4SETMASK(ur); 1686145256Sjkoshy break; 1687145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1688145256Sjkoshy __P4SETMASK(ut); 1689145256Sjkoshy break; 1690145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1691145256Sjkoshy __P4SETMASK(br); 1692145256Sjkoshy break; 1693145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1694145256Sjkoshy __P4SETMASK(mbr); 1695145256Sjkoshy break; 1696145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1697145256Sjkoshy __P4SETMASK(xa); 1698145256Sjkoshy break; 1699145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1700145256Sjkoshy __P4SETMASK(machclr); 1701145256Sjkoshy break; 1702145256Sjkoshy default: 1703174406Sjkoshy return (-1); 1704145256Sjkoshy } 1705145256Sjkoshy 1706145256Sjkoshy /* process additional flags */ 1707145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1708145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1709145256Sjkoshy q = strchr(p, '='); 1710145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1711174406Sjkoshy return (-1); 1712145256Sjkoshy 1713183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1714145256Sjkoshy cccractivemask = 0x0; 1715183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1716145256Sjkoshy cccractivemask = 0x1; 1717183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1718145256Sjkoshy cccractivemask = 0x2; 1719183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1720145256Sjkoshy cccractivemask = 0x3; 1721145256Sjkoshy else 1722174406Sjkoshy return (-1); 1723145256Sjkoshy 1724145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1725145256Sjkoshy if (has_busreqtype == 0) 1726174406Sjkoshy return (-1); 1727145256Sjkoshy 1728145256Sjkoshy q = strchr(p, '='); 1729145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1730174406Sjkoshy return (-1); 1731145256Sjkoshy 1732145256Sjkoshy count = strtol(q, &e, 0); 1733145256Sjkoshy if (e == q || *e != '\0') 1734174406Sjkoshy return (-1); 1735145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1736145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1737145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1738145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1739145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1740145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1741145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1742145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1743145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1744174406Sjkoshy return (-1); 1745145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1746145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1747145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1748145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1749145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1750145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1751145256Sjkoshy if (has_tag == 0) 1752174406Sjkoshy return (-1); 1753145256Sjkoshy 1754145256Sjkoshy q = strchr(p, '='); 1755145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1756174406Sjkoshy return (-1); 1757145256Sjkoshy 1758145256Sjkoshy count = strtol(q, &e, 0); 1759145256Sjkoshy if (e == q || *e != '\0') 1760174406Sjkoshy return (-1); 1761145256Sjkoshy 1762145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1763147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1764145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1765145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1766145256Sjkoshy q = strchr(p, '='); 1767145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1768174406Sjkoshy return (-1); 1769145256Sjkoshy 1770145256Sjkoshy count = strtol(q, &e, 0); 1771145256Sjkoshy if (e == q || *e != '\0') 1772174406Sjkoshy return (-1); 1773145256Sjkoshy 1774145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1775147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1776147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1777147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1778147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1779145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1780145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1781145256Sjkoshy else 1782174406Sjkoshy return (-1); 1783145256Sjkoshy } 1784145256Sjkoshy 1785145256Sjkoshy /* other post processing */ 1786145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1787145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1788145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1789145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1790145256Sjkoshy 1791145256Sjkoshy /* fill in thread activity mask */ 1792147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1793145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1794145256Sjkoshy 1795145256Sjkoshy if (evmask) 1796145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1797145256Sjkoshy 1798145256Sjkoshy switch (pe) { 1799145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1800145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1801145256Sjkoshy (evmask & 0x18) == 0x18) 1802174406Sjkoshy return (-1); /* can't have own+other bits together */ 1803145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1804145256Sjkoshy evmask = 0x1D; 1805145256Sjkoshy break; 1806145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1807145256Sjkoshy /* only one bit is allowed to be set */ 1808145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1809174406Sjkoshy return (-1); 1810145256Sjkoshy if (evmask == 0) { 1811183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1812145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1813145256Sjkoshy } 1814145256Sjkoshy break; 1815145256Sjkoshy default: 1816145256Sjkoshy if (evmask == 0 && pmask) { 1817145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1818145256Sjkoshy evmask |= pm->pm_value; 1819145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1820145256Sjkoshy } 1821145256Sjkoshy } 1822145256Sjkoshy 1823147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1824147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1825145256Sjkoshy 1826174406Sjkoshy return (0); 1827145256Sjkoshy} 1828145256Sjkoshy 1829147759Sjkoshy#endif 1830147759Sjkoshy 1831147759Sjkoshy#if defined(__i386__) 1832147759Sjkoshy 1833145256Sjkoshy/* 1834147191Sjkoshy * Pentium style PMCs 1835147191Sjkoshy */ 1836147191Sjkoshy 1837147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1838183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1839183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1840183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1841183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1842183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1843183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1844183105Sjkoshy EV_ALIAS("unhalted-cycles", 1845183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1846147191Sjkoshy EV_ALIAS(NULL, NULL) 1847147191Sjkoshy}; 1848147191Sjkoshy 1849147191Sjkoshystatic int 1850147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1851147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1852147191Sjkoshy{ 1853174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1854147191Sjkoshy} 1855147191Sjkoshy 1856147191Sjkoshy/* 1857145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1858145256Sjkoshy * and Pentium M CPUs. 1859145256Sjkoshy */ 1860145256Sjkoshy 1861145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1862145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1863145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1864145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1865145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1866168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1867145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1868145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1869155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1870145351Sjkoshy EV_ALIAS(NULL, NULL) 1871145256Sjkoshy}; 1872145256Sjkoshy 1873145256Sjkoshy#define P6_KW_CMASK "cmask" 1874145256Sjkoshy#define P6_KW_EDGE "edge" 1875145256Sjkoshy#define P6_KW_INV "inv" 1876145256Sjkoshy#define P6_KW_OS "os" 1877145256Sjkoshy#define P6_KW_UMASK "umask" 1878145256Sjkoshy#define P6_KW_USR "usr" 1879145256Sjkoshy 1880145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1881145256Sjkoshy PMCMASK(m, 0x01), 1882145256Sjkoshy PMCMASK(e, 0x02), 1883145256Sjkoshy PMCMASK(s, 0x04), 1884145256Sjkoshy PMCMASK(i, 0x08), 1885145256Sjkoshy NULLMASK 1886145256Sjkoshy}; 1887145256Sjkoshy 1888145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1889145256Sjkoshy PMCMASK(m, 0x01), 1890145256Sjkoshy PMCMASK(e, 0x02), 1891145256Sjkoshy PMCMASK(s, 0x04), 1892145256Sjkoshy PMCMASK(i, 0x08), 1893145256Sjkoshy PMCMASK(nonhw, 0x00), 1894145256Sjkoshy PMCMASK(hw, 0x10), 1895145256Sjkoshy PMCMASK(both, 0x30), 1896145256Sjkoshy NULLMASK 1897145256Sjkoshy}; 1898145256Sjkoshy 1899145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1900145256Sjkoshy PMCMASK(nonhw, 0x00), 1901145256Sjkoshy PMCMASK(hw, 0x10), 1902145256Sjkoshy PMCMASK(both, 0x30), 1903145256Sjkoshy NULLMASK 1904145256Sjkoshy}; 1905145256Sjkoshy 1906145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1907145256Sjkoshy PMCMASK(self, 0x00), 1908145256Sjkoshy PMCMASK(any, 0x20), 1909145256Sjkoshy NULLMASK 1910145256Sjkoshy}; 1911145256Sjkoshy 1912145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1913145256Sjkoshy PMCMASK(nta, 0x00), 1914145256Sjkoshy PMCMASK(t1, 0x01), 1915145256Sjkoshy PMCMASK(t2, 0x02), 1916145256Sjkoshy PMCMASK(wos, 0x03), 1917145256Sjkoshy NULLMASK 1918145256Sjkoshy}; 1919145256Sjkoshy 1920145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1921145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1922145256Sjkoshy PMCMASK(scalar, 0x01), 1923145256Sjkoshy NULLMASK 1924145256Sjkoshy}; 1925145256Sjkoshy 1926145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1927145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1928145256Sjkoshy PMCMASK(packed-shift, 0x02), 1929145256Sjkoshy PMCMASK(pack, 0x04), 1930145256Sjkoshy PMCMASK(unpack, 0x08), 1931145256Sjkoshy PMCMASK(packed-logical, 0x10), 1932145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1933145256Sjkoshy NULLMASK 1934145256Sjkoshy}; 1935145256Sjkoshy 1936145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1937145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1938145256Sjkoshy PMCMASK(fptommx, 0x01), 1939145256Sjkoshy NULLMASK 1940145256Sjkoshy}; 1941145256Sjkoshy 1942145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1943145256Sjkoshy PMCMASK(es, 0x01), 1944145256Sjkoshy PMCMASK(ds, 0x02), 1945145256Sjkoshy PMCMASK(fs, 0x04), 1946145256Sjkoshy PMCMASK(gs, 0x08), 1947145256Sjkoshy NULLMASK 1948145256Sjkoshy}; 1949145256Sjkoshy 1950145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1951145256Sjkoshy PMCMASK(all, 0x00), 1952145256Sjkoshy PMCMASK(freq, 0x02), 1953145256Sjkoshy NULLMASK 1954145256Sjkoshy}; 1955145256Sjkoshy 1956145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1957145256Sjkoshy PMCMASK(all, 0x00), 1958145256Sjkoshy PMCMASK(loadop, 0x01), 1959145256Sjkoshy PMCMASK(stdsta, 0x02), 1960145256Sjkoshy NULLMASK 1961145256Sjkoshy}; 1962145256Sjkoshy 1963145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1964145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1965145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1966145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1967145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1968145256Sjkoshy NULLMASK 1969145256Sjkoshy}; 1970145256Sjkoshy 1971145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1972145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1973145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1974145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1975145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1976145256Sjkoshy NULLMASK 1977145256Sjkoshy}; 1978145256Sjkoshy 1979145256Sjkoshy/* P6 event parser */ 1980145256Sjkoshystatic int 1981145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1982145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1983145256Sjkoshy{ 1984145256Sjkoshy char *e, *p, *q; 1985145256Sjkoshy uint32_t evmask; 1986145256Sjkoshy int count, n; 1987145256Sjkoshy const struct pmc_masks *pm, *pmask; 1988145256Sjkoshy 1989183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1990147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1991145256Sjkoshy 1992145256Sjkoshy evmask = 0; 1993145256Sjkoshy 1994145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1995145256Sjkoshy 1996145256Sjkoshy switch(pe) { 1997183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1998145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1999145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2000145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2001145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2002145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2003145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2004145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2005145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2006145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2007145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2008145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2009145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2010145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2011145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2012145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2013145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2014145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2015145256Sjkoshy P6MASKSET(any); break; 2016145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2017145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2018145256Sjkoshy P6MASKSET(ekp); break; 2019145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2020145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2021145256Sjkoshy P6MASKSET(pps); break; 2022145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2023145256Sjkoshy P6MASKSET(mite); break; 2024145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2025145256Sjkoshy P6MASKSET(fmt); break; 2026145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2027145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2028145256Sjkoshy P6MASKSET(sr); break; 2029145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2030145256Sjkoshy P6MASKSET(eet); break; 2031145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2032145256Sjkoshy P6MASKSET(efur); break; 2033145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2034145256Sjkoshy P6MASKSET(essir); break; 2035145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2036145256Sjkoshy P6MASKSET(esscir); break; 2037145256Sjkoshy default: 2038145256Sjkoshy pmask = NULL; 2039145256Sjkoshy break; 2040145256Sjkoshy } 2041145256Sjkoshy 2042145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2043145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2044145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2045145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2046145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2047145256Sjkoshy P6MASKSET(mesihw); 2048145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2049145256Sjkoshy P6MASKSET(hw); 2050145256Sjkoshy } 2051145256Sjkoshy 2052145256Sjkoshy /* Parse additional modifiers if present */ 2053145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2054145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2055145256Sjkoshy q = strchr(p, '='); 2056145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2057174406Sjkoshy return (-1); 2058145256Sjkoshy count = strtol(q, &e, 0); 2059145256Sjkoshy if (e == q || *e != '\0') 2060174406Sjkoshy return (-1); 2061145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2062147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2063147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2064145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2065145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2066145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2067145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2068145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2069145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2070145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2071145256Sjkoshy evmask = 0; 2072145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2073174406Sjkoshy return (-1); 2074145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2075145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2076145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2077145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2078145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2079145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2080145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2081145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2082145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2083145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2084145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2085145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2086145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2087145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2088145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2089145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2090145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2091145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2092145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2093145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2094145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2095145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2096145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2097174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2098174406Sjkoshy return (-1); 2099145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2100145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2101145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2102145256Sjkoshy } else 2103174406Sjkoshy return (-1); 2104145256Sjkoshy } 2105145256Sjkoshy 2106145256Sjkoshy /* post processing */ 2107145256Sjkoshy switch (pe) { 2108145256Sjkoshy 2109145256Sjkoshy /* 2110145256Sjkoshy * The following events default to an evmask of 0 2111145256Sjkoshy */ 2112145256Sjkoshy 2113145256Sjkoshy /* default => 'self' */ 2114145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2115145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2116145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2117145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2118145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2119145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2120145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2121145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2122145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2123145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2124145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2125145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2126145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2127145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2128145256Sjkoshy 2129145256Sjkoshy /* default => 'nta' */ 2130145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2131145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2132145256Sjkoshy 2133145256Sjkoshy /* default => 'packed and scalar' */ 2134145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2135145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2136145256Sjkoshy 2137145256Sjkoshy /* default => 'mmx to fp transitions' */ 2138145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2139145256Sjkoshy 2140145256Sjkoshy /* default => 'SSE Packed Single' */ 2141145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2142145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2143145256Sjkoshy 2144145256Sjkoshy /* default => 'all fused micro-ops' */ 2145145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2146145256Sjkoshy 2147145256Sjkoshy /* default => 'all transitions' */ 2148145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2149145256Sjkoshy break; 2150145256Sjkoshy 2151145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2152145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2153145256Sjkoshy break; 2154145256Sjkoshy 2155145256Sjkoshy default: 2156145256Sjkoshy /* 2157145256Sjkoshy * For all other events, set the default event mask 2158145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2159145256Sjkoshy */ 2160145256Sjkoshy if (evmask == 0 && pmask) { 2161145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2162145256Sjkoshy evmask |= pm->pm_value; 2163145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2164145256Sjkoshy } 2165145256Sjkoshy 2166145256Sjkoshy break; 2167145256Sjkoshy } 2168145256Sjkoshy 2169145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2170147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2171147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2172145256Sjkoshy 2173174406Sjkoshy return (0); 2174145256Sjkoshy} 2175145256Sjkoshy 2176147191Sjkoshy#endif 2177147191Sjkoshy 2178183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2179183725Sjkoshystatic int 2180183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2181183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2182183725Sjkoshy{ 2183183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2184183725Sjkoshy return (-1); 2185183725Sjkoshy 2186183725Sjkoshy /* TSC events must be unqualified. */ 2187183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2188183725Sjkoshy return (-1); 2189183725Sjkoshy 2190183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2191183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2192183725Sjkoshy 2193183725Sjkoshy return (0); 2194183725Sjkoshy} 2195183725Sjkoshy#endif 2196183725Sjkoshy 2197233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2198233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2199233628Sfabient EV_ALIAS(NULL, NULL) 2200233628Sfabient}; 2201233628Sfabient 2202233628Sfabientstatic int 2203233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2204233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2205233628Sfabient{ 2206233628Sfabient (void)ctrspec; 2207233628Sfabient (void)pmc_config; 2208233628Sfabient 2209233628Sfabient if (pe < PMC_EV_SOFT_FIRST || pe > PMC_EV_SOFT_LAST) 2210233628Sfabient return (-1); 2211233628Sfabient 2212233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2213233628Sfabient return (0); 2214233628Sfabient} 2215233628Sfabient 2216200928Srpaulo#if defined(__XSCALE__) 2217200928Srpaulo 2218200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2219200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2220200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2221200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2222200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2223200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2224200928Srpaulo EV_ALIAS(NULL, NULL) 2225200928Srpaulo}; 2226200928Srpaulostatic int 2227200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2228200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2229200928Srpaulo{ 2230200928Srpaulo switch (pe) { 2231200928Srpaulo default: 2232200928Srpaulo break; 2233200928Srpaulo } 2234200928Srpaulo 2235200928Srpaulo return (0); 2236200928Srpaulo} 2237200928Srpaulo#endif 2238200928Srpaulo 2239204635Sgnn#if defined(__mips__) 2240204635Sgnn 2241204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2242204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2243204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2244204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2245204635Sgnn EV_ALIAS(NULL, NULL) 2246204635Sgnn}; 2247204635Sgnn 2248233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2249233335Sgonzo EV_ALIAS("instructions", "RET"), 2250233335Sgonzo EV_ALIAS("branches", "BR"), 2251233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2252233335Sgonzo EV_ALIAS(NULL, NULL) 2253233335Sgonzo}; 2254233335Sgonzo 2255233320Sgonzo#define MIPS_KW_OS "os" 2256233320Sgonzo#define MIPS_KW_USR "usr" 2257233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2258204635Sgnn 2259204635Sgnnstatic int 2260233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2261204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2262204635Sgnn{ 2263204635Sgnn char *p; 2264204635Sgnn 2265204635Sgnn (void) pe; 2266204635Sgnn 2267204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2268204635Sgnn 2269204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2270233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2271204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2272233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2273204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2274233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2275204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2276204635Sgnn else 2277204635Sgnn return (-1); 2278204635Sgnn } 2279204635Sgnn 2280204635Sgnn return (0); 2281204635Sgnn} 2282233320Sgonzo 2283204635Sgnn#endif /* __mips__ */ 2284204635Sgnn 2285228869Sjhibbits#if defined(__powerpc__) 2286204635Sgnn 2287228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2288228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2289228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2290228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2291228869Sjhibbits EV_ALIAS(NULL, NULL) 2292228869Sjhibbits}; 2293228869Sjhibbits 2294228869Sjhibbits#define PPC7450_KW_OS "os" 2295228869Sjhibbits#define PPC7450_KW_USR "usr" 2296228869Sjhibbits#define PPC7450_KW_ANYTHREAD "anythread" 2297228869Sjhibbits 2298228869Sjhibbitsstatic int 2299228869Sjhibbitsppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2300228869Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2301228869Sjhibbits{ 2302228869Sjhibbits char *p; 2303228869Sjhibbits 2304228869Sjhibbits (void) pe; 2305228869Sjhibbits 2306228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2307228869Sjhibbits 2308228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2309228869Sjhibbits if (KWMATCH(p, PPC7450_KW_OS)) 2310228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2311228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_USR)) 2312228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2313228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_ANYTHREAD)) 2314228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2315228869Sjhibbits else 2316228869Sjhibbits return (-1); 2317228869Sjhibbits } 2318228869Sjhibbits 2319228869Sjhibbits return (0); 2320228869Sjhibbits} 2321228869Sjhibbits#endif /* __powerpc__ */ 2322228869Sjhibbits 2323228869Sjhibbits 2324145256Sjkoshy/* 2325183725Sjkoshy * Match an event name `name' with its canonical form. 2326183725Sjkoshy * 2327185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2328185363Sjkoshy * hyphen characters are considered to match each other. 2329185363Sjkoshy * 2330183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2331183725Sjkoshy */ 2332183725Sjkoshy 2333183725Sjkoshystatic int 2334183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2335183725Sjkoshy{ 2336183725Sjkoshy int cc, nc; 2337183725Sjkoshy const unsigned char *c, *n; 2338183725Sjkoshy 2339183725Sjkoshy c = (const unsigned char *) canonicalname; 2340183725Sjkoshy n = (const unsigned char *) name; 2341183725Sjkoshy 2342183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2343183725Sjkoshy 2344185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2345185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2346183725Sjkoshy continue; 2347183725Sjkoshy 2348185363Sjkoshy if (toupper(nc) == toupper(cc)) 2349183725Sjkoshy continue; 2350183725Sjkoshy 2351185363Sjkoshy 2352183725Sjkoshy return (0); 2353183725Sjkoshy } 2354183725Sjkoshy 2355183725Sjkoshy if (*n == '\0' && *c == '\0') 2356183725Sjkoshy return (1); 2357183725Sjkoshy 2358183725Sjkoshy return (0); 2359183725Sjkoshy} 2360183725Sjkoshy 2361183725Sjkoshy/* 2362183725Sjkoshy * Match an event name against all the event named supported by a 2363183725Sjkoshy * PMC class. 2364183725Sjkoshy * 2365183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2366183725Sjkoshy */ 2367183725Sjkoshystatic const struct pmc_event_descr * 2368183725Sjkoshypmc_match_event_class(const char *name, 2369183725Sjkoshy const struct pmc_class_descr *pcd) 2370183725Sjkoshy{ 2371183725Sjkoshy size_t n; 2372183725Sjkoshy const struct pmc_event_descr *ev; 2373185363Sjkoshy 2374183725Sjkoshy ev = pcd->pm_evc_event_table; 2375183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2376183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2377183725Sjkoshy return (ev); 2378183725Sjkoshy 2379183725Sjkoshy return (NULL); 2380183725Sjkoshy} 2381183725Sjkoshy 2382183725Sjkoshystatic int 2383183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2384183725Sjkoshy{ 2385183725Sjkoshy size_t n; 2386183725Sjkoshy 2387183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2388183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2389183725Sjkoshy return (1); 2390183725Sjkoshy return (0); 2391183725Sjkoshy} 2392183725Sjkoshy 2393183725Sjkoshy/* 2394147191Sjkoshy * API entry points 2395145256Sjkoshy */ 2396145256Sjkoshy 2397147191Sjkoshyint 2398147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2399147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2400145256Sjkoshy{ 2401183725Sjkoshy size_t n; 2402147191Sjkoshy int retval; 2403147191Sjkoshy char *r, *spec_copy; 2404147191Sjkoshy const char *ctrname; 2405183725Sjkoshy const struct pmc_event_descr *ev; 2406183725Sjkoshy const struct pmc_event_alias *alias; 2407147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2408183725Sjkoshy const struct pmc_class_descr *pcd; 2409145256Sjkoshy 2410147191Sjkoshy spec_copy = NULL; 2411147191Sjkoshy retval = -1; 2412145256Sjkoshy 2413147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2414147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2415147191Sjkoshy errno = EINVAL; 2416147191Sjkoshy goto out; 2417147191Sjkoshy } 2418145256Sjkoshy 2419147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2420147191Sjkoshy if (pmc_mdep_event_aliases) 2421183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2422183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2423183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2424147191Sjkoshy break; 2425147191Sjkoshy } 2426145256Sjkoshy 2427147191Sjkoshy if (spec_copy == NULL) 2428147191Sjkoshy spec_copy = strdup(ctrspec); 2429145256Sjkoshy 2430147191Sjkoshy r = spec_copy; 2431147191Sjkoshy ctrname = strsep(&r, ","); 2432145256Sjkoshy 2433183725Sjkoshy /* 2434183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2435183725Sjkoshy * search for the event to the specified PMC class. 2436183725Sjkoshy */ 2437183725Sjkoshy ev = NULL; 2438185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2439185363Sjkoshy pcd = pmc_class_table[n]; 2440183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2441183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2442183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2443183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2444183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2445183725Sjkoshy errno = EINVAL; 2446183725Sjkoshy goto out; 2447183725Sjkoshy } 2448147191Sjkoshy break; 2449183725Sjkoshy } 2450183725Sjkoshy } 2451145256Sjkoshy 2452183725Sjkoshy /* 2453183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2454183725Sjkoshy * classes. 2455183725Sjkoshy */ 2456185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2457185363Sjkoshy pcd = pmc_class_table[n]; 2458183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2459183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2460183725Sjkoshy } 2461183725Sjkoshy 2462183725Sjkoshy if (ev == NULL) { 2463147191Sjkoshy errno = EINVAL; 2464147191Sjkoshy goto out; 2465147191Sjkoshy } 2466145256Sjkoshy 2467147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2468183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2469183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2470147191Sjkoshy pmc_config.pm_cpu = cpu; 2471147191Sjkoshy pmc_config.pm_mode = mode; 2472147191Sjkoshy pmc_config.pm_flags = flags; 2473145256Sjkoshy 2474147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2475147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2476145256Sjkoshy 2477183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2478147191Sjkoshy errno = EINVAL; 2479147191Sjkoshy goto out; 2480147191Sjkoshy } 2481145256Sjkoshy 2482147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2483147191Sjkoshy goto out; 2484145256Sjkoshy 2485147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2486145256Sjkoshy 2487147191Sjkoshy retval = 0; 2488145256Sjkoshy 2489147191Sjkoshy out: 2490147191Sjkoshy if (spec_copy) 2491147191Sjkoshy free(spec_copy); 2492145256Sjkoshy 2493174406Sjkoshy return (retval); 2494147191Sjkoshy} 2495145256Sjkoshy 2496147191Sjkoshyint 2497147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2498147191Sjkoshy{ 2499147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2500145256Sjkoshy 2501147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2502147191Sjkoshy pmc_attach_args.pm_pid = pid; 2503145256Sjkoshy 2504174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2505147191Sjkoshy} 2506145256Sjkoshy 2507147191Sjkoshyint 2508147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2509147191Sjkoshy{ 2510147191Sjkoshy unsigned int i; 2511147191Sjkoshy enum pmc_class cl; 2512145256Sjkoshy 2513147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2514147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2515147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2516147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2517174406Sjkoshy return (0); 2518147191Sjkoshy } 2519177107Sjkoshy errno = EINVAL; 2520177107Sjkoshy return (-1); 2521147191Sjkoshy} 2522145256Sjkoshy 2523147191Sjkoshyint 2524147191Sjkoshypmc_configure_logfile(int fd) 2525147191Sjkoshy{ 2526147191Sjkoshy struct pmc_op_configurelog cla; 2527145256Sjkoshy 2528147191Sjkoshy cla.pm_logfd = fd; 2529147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2530174406Sjkoshy return (-1); 2531174406Sjkoshy return (0); 2532147191Sjkoshy} 2533145256Sjkoshy 2534147191Sjkoshyint 2535147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2536147191Sjkoshy{ 2537147191Sjkoshy if (pmc_syscall == -1) { 2538147191Sjkoshy errno = ENXIO; 2539174406Sjkoshy return (-1); 2540147191Sjkoshy } 2541145256Sjkoshy 2542147219Sjkoshy *pci = &cpu_info; 2543174406Sjkoshy return (0); 2544147191Sjkoshy} 2545145256Sjkoshy 2546147191Sjkoshyint 2547147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2548147191Sjkoshy{ 2549147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2550145256Sjkoshy 2551147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2552147191Sjkoshy pmc_detach_args.pm_pid = pid; 2553174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2554147191Sjkoshy} 2555147191Sjkoshy 2556147191Sjkoshyint 2557147191Sjkoshypmc_disable(int cpu, int pmc) 2558145256Sjkoshy{ 2559147191Sjkoshy struct pmc_op_pmcadmin ssa; 2560145256Sjkoshy 2561147191Sjkoshy ssa.pm_cpu = cpu; 2562147191Sjkoshy ssa.pm_pmc = pmc; 2563147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2564174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2565147191Sjkoshy} 2566145256Sjkoshy 2567147191Sjkoshyint 2568147191Sjkoshypmc_enable(int cpu, int pmc) 2569147191Sjkoshy{ 2570147191Sjkoshy struct pmc_op_pmcadmin ssa; 2571145256Sjkoshy 2572147191Sjkoshy ssa.pm_cpu = cpu; 2573147191Sjkoshy ssa.pm_pmc = pmc; 2574147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2575174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2576147191Sjkoshy} 2577145256Sjkoshy 2578147191Sjkoshy/* 2579147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2580147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2581147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2582147191Sjkoshy * the number of event name pointers returned. 2583147191Sjkoshy * 2584147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2585147191Sjkoshy * is responsible for freeing this space when done. 2586147191Sjkoshy */ 2587147191Sjkoshyint 2588147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2589147191Sjkoshy int *nevents) 2590147191Sjkoshy{ 2591147191Sjkoshy int count; 2592147191Sjkoshy const char **names; 2593147191Sjkoshy const struct pmc_event_descr *ev; 2594147191Sjkoshy 2595147191Sjkoshy switch (cl) 2596147191Sjkoshy { 2597185363Sjkoshy case PMC_CLASS_IAF: 2598185363Sjkoshy ev = iaf_event_table; 2599185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2600185363Sjkoshy break; 2601185363Sjkoshy case PMC_CLASS_IAP: 2602185363Sjkoshy /* 2603185363Sjkoshy * Return the most appropriate set of event name 2604185363Sjkoshy * spellings for the current CPU. 2605185363Sjkoshy */ 2606185363Sjkoshy switch (cpu_info.pm_cputype) { 2607185363Sjkoshy default: 2608185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2609185363Sjkoshy ev = atom_event_table; 2610185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2611185363Sjkoshy break; 2612185363Sjkoshy case PMC_CPU_INTEL_CORE: 2613185363Sjkoshy ev = core_event_table; 2614185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2615185363Sjkoshy break; 2616185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2617185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2618185363Sjkoshy ev = core2_event_table; 2619185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2620185363Sjkoshy break; 2621187761Sjeff case PMC_CPU_INTEL_COREI7: 2622187761Sjeff ev = corei7_event_table; 2623187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2624187761Sjeff break; 2625232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2626232366Sdavide ev = sandybridge_event_table; 2627232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2628232366Sdavide break; 2629206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2630206089Sfabient ev = westmere_event_table; 2631206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2632206089Sfabient break; 2633185363Sjkoshy } 2634185363Sjkoshy break; 2635206089Sfabient case PMC_CLASS_UCF: 2636206089Sfabient ev = ucf_event_table; 2637206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2638206089Sfabient break; 2639206089Sfabient case PMC_CLASS_UCP: 2640206089Sfabient /* 2641206089Sfabient * Return the most appropriate set of event name 2642206089Sfabient * spellings for the current CPU. 2643206089Sfabient */ 2644206089Sfabient switch (cpu_info.pm_cputype) { 2645206089Sfabient default: 2646206089Sfabient case PMC_CPU_INTEL_COREI7: 2647206089Sfabient ev = corei7uc_event_table; 2648206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2649206089Sfabient break; 2650232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2651232366Sdavide ev = sandybridgeuc_event_table; 2652232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2653232366Sdavide break; 2654206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2655206089Sfabient ev = westmereuc_event_table; 2656206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2657206089Sfabient break; 2658206089Sfabient } 2659206089Sfabient break; 2660147191Sjkoshy case PMC_CLASS_TSC: 2661183725Sjkoshy ev = tsc_event_table; 2662183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2663145256Sjkoshy break; 2664147191Sjkoshy case PMC_CLASS_K7: 2665183725Sjkoshy ev = k7_event_table; 2666183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2667145256Sjkoshy break; 2668147191Sjkoshy case PMC_CLASS_K8: 2669183725Sjkoshy ev = k8_event_table; 2670183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2671145256Sjkoshy break; 2672183725Sjkoshy case PMC_CLASS_P4: 2673183725Sjkoshy ev = p4_event_table; 2674183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2675183725Sjkoshy break; 2676147191Sjkoshy case PMC_CLASS_P5: 2677183725Sjkoshy ev = p5_event_table; 2678183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2679145256Sjkoshy break; 2680147191Sjkoshy case PMC_CLASS_P6: 2681183725Sjkoshy ev = p6_event_table; 2682183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2683145256Sjkoshy break; 2684200928Srpaulo case PMC_CLASS_XSCALE: 2685200928Srpaulo ev = xscale_event_table; 2686200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2687200928Srpaulo break; 2688204635Sgnn case PMC_CLASS_MIPS24K: 2689204635Sgnn ev = mips24k_event_table; 2690204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2691204635Sgnn break; 2692233335Sgonzo case PMC_CLASS_OCTEON: 2693233335Sgonzo ev = octeon_event_table; 2694233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2695233335Sgonzo break; 2696228869Sjhibbits case PMC_CLASS_PPC7450: 2697228869Sjhibbits ev = ppc7450_event_table; 2698228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2699228869Sjhibbits break; 2700233628Sfabient case PMC_CLASS_SOFT: 2701233628Sfabient ev = soft_event_table; 2702233628Sfabient count = soft_event_info.pm_nevent; 2703233628Sfabient break; 2704145256Sjkoshy default: 2705147191Sjkoshy errno = EINVAL; 2706174406Sjkoshy return (-1); 2707145256Sjkoshy } 2708145256Sjkoshy 2709147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2710174406Sjkoshy return (-1); 2711145256Sjkoshy 2712147191Sjkoshy *eventnames = names; 2713147191Sjkoshy *nevents = count; 2714145256Sjkoshy 2715147191Sjkoshy for (;count--; ev++, names++) 2716147191Sjkoshy *names = ev->pm_ev_name; 2717233628Sfabient 2718174406Sjkoshy return (0); 2719147191Sjkoshy} 2720145256Sjkoshy 2721147191Sjkoshyint 2722147191Sjkoshypmc_flush_logfile(void) 2723147191Sjkoshy{ 2724174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2725147191Sjkoshy} 2726145256Sjkoshy 2727147191Sjkoshyint 2728226514Sfabientpmc_close_logfile(void) 2729226514Sfabient{ 2730226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2731226514Sfabient} 2732226514Sfabient 2733226514Sfabientint 2734147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2735147191Sjkoshy{ 2736147191Sjkoshy struct pmc_op_getdriverstats gms; 2737145256Sjkoshy 2738147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2739174406Sjkoshy return (-1); 2740145256Sjkoshy 2741147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2742147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2743147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2744147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2745147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2746147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2747147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2748147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2749147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2750174406Sjkoshy return (0); 2751147191Sjkoshy} 2752145256Sjkoshy 2753147191Sjkoshyint 2754147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2755147191Sjkoshy{ 2756147191Sjkoshy struct pmc_op_getmsr gm; 2757147191Sjkoshy 2758147191Sjkoshy gm.pm_pmcid = pmc; 2759147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2760174406Sjkoshy return (-1); 2761147191Sjkoshy *msr = gm.pm_msr; 2762174406Sjkoshy return (0); 2763145256Sjkoshy} 2764145256Sjkoshy 2765145256Sjkoshyint 2766145256Sjkoshypmc_init(void) 2767145256Sjkoshy{ 2768145256Sjkoshy int error, pmc_mod_id; 2769147219Sjkoshy unsigned int n; 2770145256Sjkoshy uint32_t abi_version; 2771145256Sjkoshy struct module_stat pmc_modstat; 2772147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2773198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2774198433Sjkoshy int cpu_has_iaf_counters; 2775198433Sjkoshy unsigned int t; 2776198433Sjkoshy#endif 2777145256Sjkoshy 2778145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2779174406Sjkoshy return (0); 2780145256Sjkoshy 2781145256Sjkoshy /* retrieve the system call number from the KLD */ 2782145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2783174406Sjkoshy return (-1); 2784145256Sjkoshy 2785145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2786145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2787174406Sjkoshy return (-1); 2788145256Sjkoshy 2789145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2790145256Sjkoshy 2791147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2792147191Sjkoshy abi_version = PMC_VERSION; 2793145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2794145256Sjkoshy return (pmc_syscall = -1); 2795145256Sjkoshy 2796147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2797147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2798145256Sjkoshy errno = EPROGMISMATCH; 2799145256Sjkoshy return (pmc_syscall = -1); 2800145256Sjkoshy } 2801145256Sjkoshy 2802147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2803145256Sjkoshy return (pmc_syscall = -1); 2804145256Sjkoshy 2805147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2806147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2807147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2808147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2809147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2810147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2811147219Sjkoshy 2812185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2813185363Sjkoshy sizeof(struct pmc_class_descr *)); 2814185363Sjkoshy 2815185363Sjkoshy if (pmc_class_table == NULL) 2816185363Sjkoshy return (-1); 2817185363Sjkoshy 2818198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2819198433Sjkoshy pmc_class_table[n] = NULL; 2820185363Sjkoshy 2821185363Sjkoshy /* 2822233628Sfabient * Get soft events list. 2823233628Sfabient */ 2824233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 2825233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 2826233628Sfabient return (pmc_syscall = -1); 2827233628Sfabient 2828233628Sfabient /* Map soft events to static list. */ 2829233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 2830233628Sfabient soft_event_table[n].pm_ev_name = 2831233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 2832233628Sfabient soft_event_table[n].pm_ev_code = 2833233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 2834233628Sfabient } 2835233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 2836233628Sfabient soft_event_info.pm_nevent; 2837233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 2838233628Sfabient soft_event_table; 2839233628Sfabient 2840233628Sfabient /* 2841185363Sjkoshy * Fill in the class table. 2842185363Sjkoshy */ 2843185363Sjkoshy n = 0; 2844233628Sfabient 2845233628Sfabient /* Fill soft events information. */ 2846233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 2847185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2848233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 2849233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 2850198433Sjkoshy 2851198433Sjkoshy /* 2852198433Sjkoshy * Check if this CPU has fixed function counters. 2853198433Sjkoshy */ 2854198433Sjkoshy cpu_has_iaf_counters = 0; 2855198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2856212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 2857212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 2858198433Sjkoshy cpu_has_iaf_counters = 1; 2859185363Sjkoshy#endif 2860185363Sjkoshy 2861183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2862183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2863183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2864183725Sjkoshy pmc_mdep_class_list_size = \ 2865183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2866183725Sjkoshy } while (0) 2867183725Sjkoshy 2868198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 2869198433Sjkoshy PMC_MDEP_INIT(C); \ 2870212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 2871212224Sfabient if (!cpu_has_iaf_counters) \ 2872198433Sjkoshy pmc_mdep_event_aliases = \ 2873198433Sjkoshy C##_aliases_without_iaf; \ 2874198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 2875198433Sjkoshy } while (0) 2876198433Sjkoshy 2877183725Sjkoshy /* Configure the event name parser. */ 2878145256Sjkoshy switch (cpu_info.pm_cputype) { 2879145340Smarcel#if defined(__i386__) 2880145256Sjkoshy case PMC_CPU_AMD_K7: 2881183725Sjkoshy PMC_MDEP_INIT(k7); 2882185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 2883145256Sjkoshy break; 2884145256Sjkoshy case PMC_CPU_INTEL_P5: 2885183725Sjkoshy PMC_MDEP_INIT(p5); 2886185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 2887145256Sjkoshy break; 2888145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 2889145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 2890145256Sjkoshy case PMC_CPU_INTEL_PIII: 2891145256Sjkoshy case PMC_CPU_INTEL_PM: 2892183725Sjkoshy PMC_MDEP_INIT(p6); 2893185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 2894145256Sjkoshy break; 2895147759Sjkoshy#endif 2896147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 2897183725Sjkoshy case PMC_CPU_AMD_K8: 2898183725Sjkoshy PMC_MDEP_INIT(k8); 2899185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 2900183725Sjkoshy break; 2901185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2902198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 2903185363Sjkoshy break; 2904185363Sjkoshy case PMC_CPU_INTEL_CORE: 2905185363Sjkoshy PMC_MDEP_INIT(core); 2906202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 2907185363Sjkoshy break; 2908185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2909185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2910198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 2911185363Sjkoshy break; 2912187761Sjeff case PMC_CPU_INTEL_COREI7: 2913206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2914206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 2915198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 2916187761Sjeff break; 2917232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2918232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 2919232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 2920232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 2921232366Sdavide break; 2922206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2923206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2924206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 2925206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 2926206089Sfabient break; 2927145256Sjkoshy case PMC_CPU_INTEL_PIV: 2928183725Sjkoshy PMC_MDEP_INIT(p4); 2929185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 2930145256Sjkoshy break; 2931145256Sjkoshy#endif 2932233628Sfabient case PMC_CPU_GENERIC: 2933233628Sfabient PMC_MDEP_INIT(generic); 2934233628Sfabient break; 2935200928Srpaulo#if defined(__XSCALE__) 2936200928Srpaulo case PMC_CPU_INTEL_XSCALE: 2937200928Srpaulo PMC_MDEP_INIT(xscale); 2938200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 2939200928Srpaulo break; 2940200928Srpaulo#endif 2941204635Sgnn#if defined(__mips__) 2942204635Sgnn case PMC_CPU_MIPS_24K: 2943204635Sgnn PMC_MDEP_INIT(mips24k); 2944204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 2945204635Sgnn break; 2946233335Sgonzo case PMC_CPU_MIPS_OCTEON: 2947233335Sgonzo PMC_MDEP_INIT(octeon); 2948233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 2949233335Sgonzo break; 2950204635Sgnn#endif /* __mips__ */ 2951228869Sjhibbits#if defined(__powerpc__) 2952228869Sjhibbits case PMC_CPU_PPC_7450: 2953228869Sjhibbits PMC_MDEP_INIT(ppc7450); 2954228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 2955228869Sjhibbits break; 2956228869Sjhibbits#endif 2957145256Sjkoshy default: 2958145256Sjkoshy /* 2959145256Sjkoshy * Some kind of CPU this version of the library knows nothing 2960145256Sjkoshy * about. This shouldn't happen since the abi version check 2961145256Sjkoshy * should have caught this. 2962145256Sjkoshy */ 2963145256Sjkoshy errno = ENXIO; 2964145256Sjkoshy return (pmc_syscall = -1); 2965145256Sjkoshy } 2966145256Sjkoshy 2967174406Sjkoshy return (0); 2968145256Sjkoshy} 2969145256Sjkoshy 2970147191Sjkoshyconst char * 2971147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 2972145256Sjkoshy{ 2973147191Sjkoshy int i; 2974145256Sjkoshy 2975147191Sjkoshy /* 2976147191Sjkoshy * 'cap' should have a single bit set and should be in 2977147191Sjkoshy * range. 2978147191Sjkoshy */ 2979147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 2980147191Sjkoshy cap > PMC_CAP_LAST) { 2981145256Sjkoshy errno = EINVAL; 2982174406Sjkoshy return (NULL); 2983145256Sjkoshy } 2984145256Sjkoshy 2985147191Sjkoshy i = ffs(cap); 2986174406Sjkoshy return (pmc_capability_names[i - 1]); 2987147191Sjkoshy} 2988145256Sjkoshy 2989147191Sjkoshyconst char * 2990147191Sjkoshypmc_name_of_class(enum pmc_class pc) 2991147191Sjkoshy{ 2992147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 2993147191Sjkoshy pc <= PMC_CLASS_LAST) 2994174406Sjkoshy return (pmc_class_names[pc]); 2995145256Sjkoshy 2996147191Sjkoshy errno = EINVAL; 2997174406Sjkoshy return (NULL); 2998147191Sjkoshy} 2999145256Sjkoshy 3000147191Sjkoshyconst char * 3001147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3002147191Sjkoshy{ 3003183725Sjkoshy size_t n; 3004183725Sjkoshy 3005183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3006183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3007183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3008183725Sjkoshy 3009147191Sjkoshy errno = EINVAL; 3010174406Sjkoshy return (NULL); 3011147191Sjkoshy} 3012145256Sjkoshy 3013147191Sjkoshyconst char * 3014147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3015147191Sjkoshy{ 3016147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3017147191Sjkoshy pd <= PMC_DISP_LAST) 3018174406Sjkoshy return (pmc_disposition_names[pd]); 3019145256Sjkoshy 3020147191Sjkoshy errno = EINVAL; 3021174406Sjkoshy return (NULL); 3022147191Sjkoshy} 3023145256Sjkoshy 3024147191Sjkoshyconst char * 3025185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3026147191Sjkoshy{ 3027183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3028145256Sjkoshy 3029183725Sjkoshy ev = evfence = NULL; 3030185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3031185363Sjkoshy ev = iaf_event_table; 3032185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3033185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3034185363Sjkoshy switch (cpu) { 3035185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3036185363Sjkoshy ev = atom_event_table; 3037185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3038185363Sjkoshy break; 3039185363Sjkoshy case PMC_CPU_INTEL_CORE: 3040185363Sjkoshy ev = core_event_table; 3041185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3042185363Sjkoshy break; 3043185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3044185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3045185363Sjkoshy ev = core2_event_table; 3046185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3047185363Sjkoshy break; 3048187761Sjeff case PMC_CPU_INTEL_COREI7: 3049187761Sjeff ev = corei7_event_table; 3050187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3051187761Sjeff break; 3052232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3053232366Sdavide ev = sandybridge_event_table; 3054232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3055232366Sdavide break; 3056206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3057206089Sfabient ev = westmere_event_table; 3058206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3059206089Sfabient break; 3060185363Sjkoshy default: /* Unknown CPU type. */ 3061185363Sjkoshy break; 3062185363Sjkoshy } 3063206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3064206089Sfabient ev = ucf_event_table; 3065206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3066206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3067206089Sfabient switch (cpu) { 3068206089Sfabient case PMC_CPU_INTEL_COREI7: 3069206089Sfabient ev = corei7uc_event_table; 3070206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3071206089Sfabient break; 3072232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3073232366Sdavide ev = sandybridgeuc_event_table; 3074232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3075232366Sdavide break; 3076206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3077206089Sfabient ev = westmereuc_event_table; 3078206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3079206089Sfabient break; 3080206089Sfabient default: /* Unknown CPU type. */ 3081206089Sfabient break; 3082206089Sfabient } 3083206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3084183725Sjkoshy ev = k7_event_table; 3085183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3086183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3087183725Sjkoshy ev = k8_event_table; 3088183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3089183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3090183725Sjkoshy ev = p4_event_table; 3091183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3092183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3093183725Sjkoshy ev = p5_event_table; 3094183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3095183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3096183725Sjkoshy ev = p6_event_table; 3097183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3098200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3099200928Srpaulo ev = xscale_event_table; 3100200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3101204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3102204635Sgnn ev = mips24k_event_table; 3103233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3104233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3105233335Sgonzo ev = octeon_event_table; 3106233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3107228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3108228869Sjhibbits ev = ppc7450_event_table; 3109233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3110183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3111183725Sjkoshy ev = tsc_event_table; 3112183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3113233628Sfabient } else if (pe >= PMC_EV_SOFT_FIRST && pe <= PMC_EV_SOFT_LAST) { 3114233628Sfabient ev = soft_event_table; 3115233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3116183725Sjkoshy } 3117183725Sjkoshy 3118183725Sjkoshy for (; ev != evfence; ev++) 3119183725Sjkoshy if (pe == ev->pm_ev_code) 3120183725Sjkoshy return (ev->pm_ev_name); 3121183725Sjkoshy 3122185363Sjkoshy return (NULL); 3123185363Sjkoshy} 3124185363Sjkoshy 3125185363Sjkoshyconst char * 3126185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3127185363Sjkoshy{ 3128185363Sjkoshy const char *n; 3129185363Sjkoshy 3130185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3131185363Sjkoshy return (n); 3132185363Sjkoshy 3133147191Sjkoshy errno = EINVAL; 3134174406Sjkoshy return (NULL); 3135147191Sjkoshy} 3136145256Sjkoshy 3137147191Sjkoshyconst char * 3138147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3139147191Sjkoshy{ 3140147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3141147191Sjkoshy pm <= PMC_MODE_LAST) 3142174406Sjkoshy return (pmc_mode_names[pm]); 3143145256Sjkoshy 3144147191Sjkoshy errno = EINVAL; 3145174406Sjkoshy return (NULL); 3146147191Sjkoshy} 3147145256Sjkoshy 3148147191Sjkoshyconst char * 3149147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3150147191Sjkoshy{ 3151147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3152147191Sjkoshy ps <= PMC_STATE_LAST) 3153174406Sjkoshy return (pmc_state_names[ps]); 3154145256Sjkoshy 3155147191Sjkoshy errno = EINVAL; 3156174406Sjkoshy return (NULL); 3157145256Sjkoshy} 3158145256Sjkoshy 3159145256Sjkoshyint 3160147191Sjkoshypmc_ncpu(void) 3161145256Sjkoshy{ 3162147191Sjkoshy if (pmc_syscall == -1) { 3163147191Sjkoshy errno = ENXIO; 3164174406Sjkoshy return (-1); 3165147191Sjkoshy } 3166145256Sjkoshy 3167174406Sjkoshy return (cpu_info.pm_ncpu); 3168145256Sjkoshy} 3169145256Sjkoshy 3170145256Sjkoshyint 3171147191Sjkoshypmc_npmc(int cpu) 3172145256Sjkoshy{ 3173147191Sjkoshy if (pmc_syscall == -1) { 3174147191Sjkoshy errno = ENXIO; 3175174406Sjkoshy return (-1); 3176147191Sjkoshy } 3177145256Sjkoshy 3178147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3179147191Sjkoshy errno = EINVAL; 3180174406Sjkoshy return (-1); 3181147191Sjkoshy } 3182145256Sjkoshy 3183174406Sjkoshy return (cpu_info.pm_npmc); 3184145256Sjkoshy} 3185145256Sjkoshy 3186145256Sjkoshyint 3187147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3188145256Sjkoshy{ 3189147191Sjkoshy int nbytes, npmc; 3190147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3191145256Sjkoshy 3192147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3193174406Sjkoshy return (-1); 3194145256Sjkoshy 3195147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3196147191Sjkoshy npmc * sizeof(struct pmc_info); 3197145256Sjkoshy 3198147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3199174406Sjkoshy return (-1); 3200145256Sjkoshy 3201147191Sjkoshy pmci->pm_cpu = cpu; 3202145256Sjkoshy 3203147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3204147191Sjkoshy free(pmci); 3205174406Sjkoshy return (-1); 3206147191Sjkoshy } 3207145256Sjkoshy 3208147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3209147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3210174406Sjkoshy return (0); 3211145256Sjkoshy} 3212145256Sjkoshy 3213145256Sjkoshyint 3214145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3215145256Sjkoshy{ 3216145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3217145256Sjkoshy 3218145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3219145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3220145256Sjkoshy pmc_read_op.pm_value = -1; 3221145256Sjkoshy 3222145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3223174406Sjkoshy return (-1); 3224145256Sjkoshy 3225145256Sjkoshy *value = pmc_read_op.pm_value; 3226174406Sjkoshy return (0); 3227145256Sjkoshy} 3228145256Sjkoshy 3229145256Sjkoshyint 3230147191Sjkoshypmc_release(pmc_id_t pmc) 3231145256Sjkoshy{ 3232147191Sjkoshy struct pmc_op_simple pmc_release_args; 3233145256Sjkoshy 3234147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3235174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3236145256Sjkoshy} 3237145256Sjkoshy 3238145256Sjkoshyint 3239145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3240145256Sjkoshy{ 3241145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3242145256Sjkoshy 3243145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3244145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3245145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3246145256Sjkoshy 3247145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3248174406Sjkoshy return (-1); 3249145256Sjkoshy 3250145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3251174406Sjkoshy return (0); 3252145256Sjkoshy} 3253145256Sjkoshy 3254145256Sjkoshyint 3255145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3256145256Sjkoshy{ 3257145256Sjkoshy struct pmc_op_pmcsetcount sc; 3258145256Sjkoshy 3259145256Sjkoshy sc.pm_pmcid = pmc; 3260145256Sjkoshy sc.pm_count = value; 3261145256Sjkoshy 3262145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3263174406Sjkoshy return (-1); 3264174406Sjkoshy return (0); 3265145256Sjkoshy} 3266145256Sjkoshy 3267145256Sjkoshyint 3268147191Sjkoshypmc_start(pmc_id_t pmc) 3269145256Sjkoshy{ 3270147191Sjkoshy struct pmc_op_simple pmc_start_args; 3271145256Sjkoshy 3272147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3273174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3274145256Sjkoshy} 3275145256Sjkoshy 3276145256Sjkoshyint 3277147191Sjkoshypmc_stop(pmc_id_t pmc) 3278145256Sjkoshy{ 3279147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3280145256Sjkoshy 3281147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3282174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3283145256Sjkoshy} 3284145256Sjkoshy 3285145256Sjkoshyint 3286145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3287145774Sjkoshy{ 3288145774Sjkoshy unsigned int i; 3289145774Sjkoshy enum pmc_class cl; 3290145774Sjkoshy 3291145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3292145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3293145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3294145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3295174406Sjkoshy return (0); 3296145774Sjkoshy } 3297177107Sjkoshy errno = EINVAL; 3298177107Sjkoshy return (-1); 3299145774Sjkoshy} 3300145774Sjkoshy 3301145774Sjkoshyint 3302147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3303145774Sjkoshy{ 3304147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3305145774Sjkoshy 3306147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3307147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3308147191Sjkoshy pmc_write_op.pm_value = value; 3309174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3310145256Sjkoshy} 3311145256Sjkoshy 3312145256Sjkoshyint 3313147191Sjkoshypmc_writelog(uint32_t userdata) 3314145256Sjkoshy{ 3315147191Sjkoshy struct pmc_op_writelog wl; 3316145256Sjkoshy 3317147191Sjkoshy wl.pm_userdata = userdata; 3318174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3319145256Sjkoshy} 3320