libpmc.c revision 263446
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 263446 2014-03-20 20:51:08Z hiren $"); 29145256Sjkoshy 30145256Sjkoshy#include <sys/types.h> 31261342Sjhibbits#include <sys/param.h> 32145256Sjkoshy#include <sys/module.h> 33145256Sjkoshy#include <sys/pmc.h> 34145256Sjkoshy#include <sys/syscall.h> 35145256Sjkoshy 36145256Sjkoshy#include <ctype.h> 37145256Sjkoshy#include <errno.h> 38145256Sjkoshy#include <fcntl.h> 39145256Sjkoshy#include <pmc.h> 40145256Sjkoshy#include <stdio.h> 41145256Sjkoshy#include <stdlib.h> 42145256Sjkoshy#include <string.h> 43145256Sjkoshy#include <strings.h> 44145256Sjkoshy#include <unistd.h> 45145256Sjkoshy 46185363Sjkoshy#include "libpmcinternal.h" 47185363Sjkoshy 48145256Sjkoshy/* Function prototypes */ 49145340Smarcel#if defined(__i386__) 50145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 51145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 52147191Sjkoshy#endif 53147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 54185363Sjkoshystatic int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 55185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 56185363Sjkoshystatic int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 57185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 58206089Sfabientstatic int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 59206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 60206089Sfabientstatic int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 61206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 62147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 63145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 64147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 65147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 66147191Sjkoshy#endif 67147191Sjkoshy#if defined(__i386__) 68145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 69145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 70147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 71145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 72145256Sjkoshy#endif 73183725Sjkoshy#if defined(__amd64__) || defined(__i386__) 74183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 75183725Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 76183725Sjkoshy#endif 77200928Srpaulo#if defined(__XSCALE__) 78200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 79200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 80200928Srpaulo#endif 81204635Sgnn#if defined(__mips__) 82233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 83204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 84204635Sgnn#endif /* __mips__ */ 85233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 86233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 87204635Sgnn 88228869Sjhibbits#if defined(__powerpc__) 89261342Sjhibbitsstatic int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec, 90228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 91228869Sjhibbits#endif /* __powerpc__ */ 92204635Sgnn 93145256Sjkoshy#define PMC_CALL(cmd, params) \ 94145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 95145256Sjkoshy 96145256Sjkoshy/* 97145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 98145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 99145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 100145256Sjkoshy * lookup table. 101145256Sjkoshy */ 102145256Sjkoshystruct pmc_event_alias { 103145256Sjkoshy const char *pm_alias; 104145256Sjkoshy const char *pm_spec; 105145256Sjkoshy}; 106145256Sjkoshy 107145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 108145256Sjkoshy 109145256Sjkoshy/* 110183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 111145256Sjkoshy * to integer codes used by the PMC KLD. 112145256Sjkoshy */ 113145256Sjkoshystruct pmc_event_descr { 114145256Sjkoshy const char *pm_ev_name; 115145256Sjkoshy enum pmc_event pm_ev_code; 116145256Sjkoshy}; 117145256Sjkoshy 118183725Sjkoshy/* 119183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 120183725Sjkoshy * event names to event tables and other PMC class data. 121183725Sjkoshy */ 122183725Sjkoshystruct pmc_class_descr { 123183725Sjkoshy const char *pm_evc_name; 124183725Sjkoshy size_t pm_evc_name_size; 125183725Sjkoshy enum pmc_class pm_evc_class; 126183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 127183725Sjkoshy size_t pm_evc_event_table_size; 128183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 129183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 130183725Sjkoshy}; 131183725Sjkoshy 132183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 133183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 134183725Sjkoshy 135183725Sjkoshy#undef __PMC_EV 136183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 137183725Sjkoshy 138183725Sjkoshy/* 139185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 140183725Sjkoshy * 141185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 142183725Sjkoshy */ 143185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 144183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 145183725Sjkoshy { \ 146183725Sjkoshy __PMC_EV_##C() \ 147185363Sjkoshy } 148185363Sjkoshy 149185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 150185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 151185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 152185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 153185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 154185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 155200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 156204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 157233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 158206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 159228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 160261342SjhibbitsPMC_CLASSDEP_TABLE(ppc970, PPC970); 161185363Sjkoshy 162233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 163233628Sfabient 164185363Sjkoshy#undef __PMC_EV_ALIAS 165185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 166185363Sjkoshy 167185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 168185363Sjkoshy{ 169185363Sjkoshy __PMC_EV_ALIAS_ATOM() 170185363Sjkoshy}; 171185363Sjkoshy 172263446Shirenstatic const struct pmc_event_descr atom_silvermont_event_table[] = 173263446Shiren{ 174263446Shiren __PMC_EV_ALIAS_ATOM_SILVERMONT() 175263446Shiren}; 176263446Shiren 177185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 178185363Sjkoshy{ 179185363Sjkoshy __PMC_EV_ALIAS_CORE() 180185363Sjkoshy}; 181185363Sjkoshy 182185363Sjkoshy 183185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 184185363Sjkoshy{ 185185363Sjkoshy __PMC_EV_ALIAS_CORE2() 186185363Sjkoshy}; 187185363Sjkoshy 188187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 189187761Sjeff{ 190187761Sjeff __PMC_EV_ALIAS_COREI7() 191187761Sjeff}; 192187761Sjeff 193248842Ssbrunostatic const struct pmc_event_descr haswell_event_table[] = 194248842Ssbruno{ 195248842Ssbruno __PMC_EV_ALIAS_HASWELL() 196248842Ssbruno}; 197248842Ssbruno 198240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] = 199240164Sfabient{ 200240164Sfabient __PMC_EV_ALIAS_IVYBRIDGE() 201240164Sfabient}; 202240164Sfabient 203246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] = 204246166Ssbruno{ 205246166Ssbruno __PMC_EV_ALIAS_IVYBRIDGE_XEON() 206246166Ssbruno}; 207246166Ssbruno 208232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 209232366Sdavide{ 210232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 211232366Sdavide}; 212232366Sdavide 213241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 214241738Ssbruno{ 215241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 216241738Ssbruno}; 217241738Ssbruno 218206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 219206089Sfabient{ 220206089Sfabient __PMC_EV_ALIAS_WESTMERE() 221206089Sfabient}; 222206089Sfabient 223206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 224206089Sfabient{ 225206089Sfabient __PMC_EV_ALIAS_COREI7UC() 226206089Sfabient}; 227206089Sfabient 228248842Ssbrunostatic const struct pmc_event_descr haswelluc_event_table[] = 229248842Ssbruno{ 230248842Ssbruno __PMC_EV_ALIAS_HASWELLUC() 231248842Ssbruno}; 232248842Ssbruno 233232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 234232366Sdavide{ 235232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 236232366Sdavide}; 237232366Sdavide 238206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 239206089Sfabient{ 240206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 241206089Sfabient}; 242206089Sfabient 243185363Sjkoshy/* 244185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 245185363Sjkoshy * 246185363Sjkoshy * Map a CPU to the PMC classes it supports. 247185363Sjkoshy */ 248185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 249183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 250183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 251183725Sjkoshy } 252183725Sjkoshy 253233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 254263446ShirenPMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 255233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 256233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 257233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 258248842SsbrunoPMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 259240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 260246166SsbrunoPMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 261233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 262241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 263233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 264233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 265233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 266233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 267233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 268233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 269233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 270233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 271233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 272233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 273261342SjhibbitsPMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970); 274233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 275183725Sjkoshy 276183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 277145256Sjkoshy{ 278183725Sjkoshy __PMC_EV_TSC() 279145256Sjkoshy}; 280145256Sjkoshy 281183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 282185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 283185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 284185363Sjkoshy { \ 285185363Sjkoshy .pm_evc_name = #CLASS "-", \ 286185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 287185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 288185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 289183725Sjkoshy .pm_evc_event_table_size = \ 290185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 291185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 292183725Sjkoshy } 293183725Sjkoshy 294185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 295185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 296185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 297263446ShirenPMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap); 298185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 299185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 300187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 301248842SsbrunoPMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap); 302240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 303246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); 304232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 305241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 306206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 307206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 308206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 309248842SsbrunoPMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp); 310232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 311206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 312185363Sjkoshy#endif 313183725Sjkoshy#if defined(__i386__) 314185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 315183725Sjkoshy#endif 316183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 317185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 318185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 319183725Sjkoshy#endif 320183725Sjkoshy#if defined(__i386__) 321185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 322185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 323183725Sjkoshy#endif 324183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 325185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 326183725Sjkoshy#endif 327200928Srpaulo#if defined(__XSCALE__) 328200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 329200928Srpaulo#endif 330204635Sgnn#if defined(__mips__) 331233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 332233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 333204635Sgnn#endif /* __mips__ */ 334228869Sjhibbits#if defined(__powerpc__) 335261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc); 336261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc); 337228869Sjhibbits#endif 338228869Sjhibbits 339233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 340233628Sfabient{ 341233628Sfabient .pm_evc_name = "SOFT-", 342233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 343233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 344233628Sfabient .pm_evc_event_table = NULL, 345233628Sfabient .pm_evc_event_table_size = 0, 346233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 347233628Sfabient}; 348233628Sfabient 349183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 350183725Sjkoshy 351185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 352185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 353185363Sjkoshy 354183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 355183725Sjkoshystatic size_t pmc_mdep_class_list_size; 356183725Sjkoshy 357145256Sjkoshy/* 358145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 359145256Sjkoshy * strings. 360145256Sjkoshy */ 361145256Sjkoshy 362145256Sjkoshystatic const char * pmc_capability_names[] = { 363145256Sjkoshy#undef __PMC_CAP 364145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 365145256Sjkoshy __PMC_CAPS() 366145256Sjkoshy}; 367145256Sjkoshy 368145256Sjkoshystatic const char * pmc_class_names[] = { 369145256Sjkoshy#undef __PMC_CLASS 370145256Sjkoshy#define __PMC_CLASS(C) #C , 371145256Sjkoshy __PMC_CLASSES() 372145256Sjkoshy}; 373145256Sjkoshy 374183725Sjkoshystruct pmc_cputype_map { 375228557Sdim enum pmc_cputype pm_cputype; 376183725Sjkoshy const char *pm_name; 377183725Sjkoshy}; 378183725Sjkoshy 379183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 380145256Sjkoshy#undef __PMC_CPU 381183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 382145256Sjkoshy __PMC_CPUS() 383145256Sjkoshy}; 384145256Sjkoshy 385145256Sjkoshystatic const char * pmc_disposition_names[] = { 386145256Sjkoshy#undef __PMC_DISP 387145256Sjkoshy#define __PMC_DISP(D) #D , 388145256Sjkoshy __PMC_DISPOSITIONS() 389145256Sjkoshy}; 390145256Sjkoshy 391145256Sjkoshystatic const char * pmc_mode_names[] = { 392145256Sjkoshy#undef __PMC_MODE 393145256Sjkoshy#define __PMC_MODE(M,N) #M , 394145256Sjkoshy __PMC_MODES() 395145256Sjkoshy}; 396145256Sjkoshy 397145256Sjkoshystatic const char * pmc_state_names[] = { 398145256Sjkoshy#undef __PMC_STATE 399145256Sjkoshy#define __PMC_STATE(S) #S , 400145256Sjkoshy __PMC_STATES() 401145256Sjkoshy}; 402145256Sjkoshy 403233628Sfabient/* 404233628Sfabient * Filled in by pmc_init(). 405233628Sfabient */ 406233628Sfabientstatic int pmc_syscall = -1; 407233628Sfabientstatic struct pmc_cpuinfo cpu_info; 408233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 409145256Sjkoshy 410145256Sjkoshy/* Event masks for events */ 411145256Sjkoshystruct pmc_masks { 412145256Sjkoshy const char *pm_name; 413240164Sfabient const uint64_t pm_value; 414145256Sjkoshy}; 415145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 416206089Sfabient#define NULLMASK { .pm_name = NULL } 417145256Sjkoshy 418147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 419145256Sjkoshystatic int 420240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 421145256Sjkoshy{ 422145256Sjkoshy const struct pmc_masks *pm; 423145256Sjkoshy char *q, *r; 424145256Sjkoshy int c; 425145256Sjkoshy 426145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 427174406Sjkoshy return (-1); 428183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 429145256Sjkoshy if (*++q == '\0') /* no more data */ 430174406Sjkoshy return (-1); 431145256Sjkoshy c = 0; /* count of mask keywords seen */ 432145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 433183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 434183725Sjkoshy pm++) 435145256Sjkoshy ; 436145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 437174406Sjkoshy return (-1); 438145256Sjkoshy *evmask |= pm->pm_value; 439145256Sjkoshy c++; 440145256Sjkoshy } 441174406Sjkoshy return (c); 442145256Sjkoshy} 443145340Smarcel#endif 444145256Sjkoshy 445145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 446145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 447145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 448145256Sjkoshy 449145340Smarcel#if defined(__i386__) 450145256Sjkoshy 451145256Sjkoshy/* 452145256Sjkoshy * AMD K7 (Athlon) CPUs. 453145256Sjkoshy */ 454145256Sjkoshy 455145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 456145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 457145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 458145351Sjkoshy EV_ALIAS("cycles", "tsc"), 459183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 460145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 461145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 462145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 463145351Sjkoshy EV_ALIAS(NULL, NULL) 464145256Sjkoshy}; 465145256Sjkoshy 466145256Sjkoshy#define K7_KW_COUNT "count" 467145256Sjkoshy#define K7_KW_EDGE "edge" 468145256Sjkoshy#define K7_KW_INV "inv" 469145256Sjkoshy#define K7_KW_OS "os" 470145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 471145256Sjkoshy#define K7_KW_USR "usr" 472145256Sjkoshy 473145256Sjkoshystatic int 474145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 475145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 476145256Sjkoshy{ 477183107Sjkoshy char *e, *p, *q; 478183107Sjkoshy int c, has_unitmask; 479145256Sjkoshy uint32_t count, unitmask; 480145256Sjkoshy 481147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 482183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 483145256Sjkoshy 484145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 485145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 486145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 487145256Sjkoshy has_unitmask = 1; 488147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 489145256Sjkoshy } else 490145256Sjkoshy unitmask = has_unitmask = 0; 491145256Sjkoshy 492145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 493145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 494145256Sjkoshy q = strchr(p, '='); 495145256Sjkoshy if (*++q == '\0') /* skip '=' */ 496174406Sjkoshy return (-1); 497145256Sjkoshy 498145256Sjkoshy count = strtol(q, &e, 0); 499145256Sjkoshy if (e == q || *e != '\0') 500174406Sjkoshy return (-1); 501145256Sjkoshy 502145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 503147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 504147191Sjkoshy AMD_PMC_TO_COUNTER(count); 505145256Sjkoshy 506145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 507145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 508145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 509145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 510145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 511145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 512145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 513145256Sjkoshy if (has_unitmask == 0) 514174406Sjkoshy return (-1); 515145256Sjkoshy unitmask = 0; 516145256Sjkoshy q = strchr(p, '='); 517145256Sjkoshy if (*++q == '\0') /* skip '=' */ 518174406Sjkoshy return (-1); 519145256Sjkoshy 520145256Sjkoshy while ((c = tolower(*q++)) != 0) 521145256Sjkoshy if (c == 'm') 522147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 523145256Sjkoshy else if (c == 'o') 524147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 525145256Sjkoshy else if (c == 'e') 526147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 527145256Sjkoshy else if (c == 's') 528147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 529145256Sjkoshy else if (c == 'i') 530147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 531145256Sjkoshy else if (c == '+') 532145256Sjkoshy continue; 533145256Sjkoshy else 534174406Sjkoshy return (-1); 535145256Sjkoshy 536145256Sjkoshy if (unitmask == 0) 537174406Sjkoshy return (-1); 538145256Sjkoshy 539145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 540145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 541145256Sjkoshy } else 542174406Sjkoshy return (-1); 543145256Sjkoshy } 544145256Sjkoshy 545145256Sjkoshy if (has_unitmask) { 546145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 547147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 548147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 549145256Sjkoshy } 550145256Sjkoshy 551174406Sjkoshy return (0); 552145256Sjkoshy 553145256Sjkoshy} 554145256Sjkoshy 555147191Sjkoshy#endif 556147191Sjkoshy 557147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 558147191Sjkoshy 559145256Sjkoshy/* 560185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 561185363Sjkoshy */ 562185363Sjkoshy 563185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 564185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 565185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 566185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 567185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 568185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 569185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 570185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 571185363Sjkoshy EV_ALIAS(NULL, NULL) 572185363Sjkoshy}; 573185363Sjkoshy 574185363Sjkoshy/* 575185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 576185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 577198433Sjkoshy * 578198433Sjkoshy * We map aliases to events on the fixed-function counters if these 579198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 580198433Sjkoshy * counters. 581185363Sjkoshy */ 582185363Sjkoshy 583185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 584185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 585185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 586185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 587185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 588185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 589185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 590185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 591185363Sjkoshy EV_ALIAS(NULL, NULL) 592185363Sjkoshy}; 593185363Sjkoshy 594198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 595198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 596198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 597198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 598198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 599198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 600198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 601198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 602198433Sjkoshy EV_ALIAS(NULL, NULL) 603198433Sjkoshy}; 604198433Sjkoshy 605198433Sjkoshy#define atom_aliases core2_aliases 606198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 607263446Shiren#define atom_silvermont_aliases core2_aliases 608263446Shiren#define atom_silvermont_aliases_without_iaf core2_aliases_without_iaf 609198433Sjkoshy#define corei7_aliases core2_aliases 610198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 611248842Ssbruno#define haswell_aliases core2_aliases 612248842Ssbruno#define haswell_aliases_without_iaf core2_aliases_without_iaf 613240164Sfabient#define ivybridge_aliases core2_aliases 614240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 615246166Ssbruno#define ivybridge_xeon_aliases core2_aliases 616246166Ssbruno#define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 617232366Sdavide#define sandybridge_aliases core2_aliases 618232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 619241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 620241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 621206089Sfabient#define westmere_aliases core2_aliases 622206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 623198433Sjkoshy 624185363Sjkoshy#define IAF_KW_OS "os" 625185363Sjkoshy#define IAF_KW_USR "usr" 626185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 627185363Sjkoshy 628185363Sjkoshy/* 629185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 630185363Sjkoshy */ 631185363Sjkoshystatic int 632185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 633185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 634185363Sjkoshy{ 635185363Sjkoshy char *p; 636185363Sjkoshy 637185363Sjkoshy (void) pe; 638185363Sjkoshy 639185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 640185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 641185363Sjkoshy 642185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 643185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 644185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 645185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 646185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 647185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 648185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 649185363Sjkoshy else 650185363Sjkoshy return (-1); 651185363Sjkoshy } 652185363Sjkoshy 653185363Sjkoshy return (0); 654185363Sjkoshy} 655185363Sjkoshy 656185363Sjkoshy/* 657185363Sjkoshy * Core/Core2 support. 658185363Sjkoshy */ 659185363Sjkoshy 660185363Sjkoshy#define IAP_KW_AGENT "agent" 661185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 662185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 663185363Sjkoshy#define IAP_KW_CMASK "cmask" 664185363Sjkoshy#define IAP_KW_CORE "core" 665185363Sjkoshy#define IAP_KW_EDGE "edge" 666185363Sjkoshy#define IAP_KW_INV "inv" 667185363Sjkoshy#define IAP_KW_OS "os" 668185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 669185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 670185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 671185363Sjkoshy#define IAP_KW_TRANSITION "trans" 672185363Sjkoshy#define IAP_KW_USR "usr" 673206089Sfabient#define IAP_KW_RSP "rsp" 674185363Sjkoshy 675185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 676185363Sjkoshy PMCMASK(all, (0x3 << 14)), 677185363Sjkoshy PMCMASK(this, (0x1 << 14)), 678185363Sjkoshy NULLMASK 679185363Sjkoshy}; 680185363Sjkoshy 681185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 682185363Sjkoshy PMCMASK(this, 0), 683185363Sjkoshy PMCMASK(any, (0x1 << 13)), 684185363Sjkoshy NULLMASK 685185363Sjkoshy}; 686185363Sjkoshy 687185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 688185363Sjkoshy PMCMASK(both, (0x3 << 12)), 689185363Sjkoshy PMCMASK(only, (0x1 << 12)), 690185363Sjkoshy PMCMASK(exclude, 0), 691185363Sjkoshy NULLMASK 692185363Sjkoshy}; 693185363Sjkoshy 694185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 695185363Sjkoshy PMCMASK(i, (1 << 8)), 696185363Sjkoshy PMCMASK(s, (1 << 9)), 697185363Sjkoshy PMCMASK(e, (1 << 10)), 698185363Sjkoshy PMCMASK(m, (1 << 11)), 699185363Sjkoshy NULLMASK 700185363Sjkoshy}; 701185363Sjkoshy 702185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 703185363Sjkoshy PMCMASK(clean, (1 << 8)), 704185363Sjkoshy PMCMASK(hit, (1 << 9)), 705185363Sjkoshy PMCMASK(hitm, (1 << 11)), 706185363Sjkoshy NULLMASK 707185363Sjkoshy}; 708185363Sjkoshy 709185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 710185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 711185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 712185363Sjkoshy NULLMASK 713185363Sjkoshy}; 714185363Sjkoshy 715185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 716185363Sjkoshy PMCMASK(any, 0x00), 717185363Sjkoshy PMCMASK(frequency, 0x10), 718185363Sjkoshy NULLMASK 719185363Sjkoshy}; 720185363Sjkoshy 721240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 722206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 723206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 724206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 725206089Sfabient PMCMASK(WB, (1 << 3)), 726206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 727206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 728206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 729206089Sfabient PMCMASK(OTHER, (1 << 7)), 730206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 731206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 732206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 733206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 734206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 735206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 736206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 737206089Sfabient NULLMASK 738206089Sfabient}; 739206089Sfabient 740241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 741240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 742240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 743240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 744240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 745240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 746240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 747240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 748240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 749240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 750240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 751240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 752240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 753240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 754240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 755240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 756240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 757240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 758240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 759240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 760240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 761241974Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 762240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 763240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 764240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 765240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 766240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 767240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 768240164Sfabient NULLMASK 769240164Sfabient}; 770240164Sfabient 771248842Ssbrunostatic struct pmc_masks iap_rsp_mask_haswell[] = { 772248842Ssbruno PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 773248842Ssbruno PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 774248842Ssbruno PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 775248842Ssbruno PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 776248842Ssbruno PMCMASK(REQ_PF_RFO, (1ULL << 5)), 777248842Ssbruno PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 778248842Ssbruno PMCMASK(REQ_OTHER, (1ULL << 15)), 779248842Ssbruno PMCMASK(RES_ANY, (1ULL << 16)), 780248842Ssbruno PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 781248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 782248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 783248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 784248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 785248842Ssbruno PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 786248842Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 787248842Ssbruno PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 788248842Ssbruno PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 789248842Ssbruno PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 790248842Ssbruno PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 791248842Ssbruno PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 792248842Ssbruno PMCMASK(RES_NON_DRAM, (1ULL << 37)), 793248842Ssbruno NULLMASK 794248842Ssbruno}; 795248842Ssbruno 796185363Sjkoshystatic int 797185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 798185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 799185363Sjkoshy{ 800185363Sjkoshy char *e, *p, *q; 801240164Sfabient uint64_t cachestate, evmask, rsp; 802185363Sjkoshy int count, n; 803185363Sjkoshy 804185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 805185363Sjkoshy PMC_CAP_QUALIFIER); 806185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 807185363Sjkoshy 808206089Sfabient cachestate = evmask = rsp = 0; 809185363Sjkoshy 810185363Sjkoshy /* Parse additional modifiers if present */ 811185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 812185363Sjkoshy 813185363Sjkoshy n = 0; 814185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 815185363Sjkoshy q = strchr(p, '='); 816185363Sjkoshy if (*++q == '\0') /* skip '=' */ 817185363Sjkoshy return (-1); 818185363Sjkoshy count = strtol(q, &e, 0); 819185363Sjkoshy if (e == q || *e != '\0') 820185363Sjkoshy return (-1); 821185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 822185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 823185363Sjkoshy IAP_CMASK(count); 824185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 825185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 826185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 827185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 828185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 829185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 830185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 831185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 832185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 833185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 834193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 835185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 836185363Sjkoshy if (n != 1) 837185363Sjkoshy return (-1); 838193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 839185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 840185363Sjkoshy if (n != 1) 841185363Sjkoshy return (-1); 842193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 843185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 844185363Sjkoshy if (n != 1) 845185363Sjkoshy return (-1); 846193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 847185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 848185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 849193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 850185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 851185363Sjkoshy if (n != 1) 852185363Sjkoshy return (-1); 853185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 854263446Shiren cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT || 855185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 856206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 857193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 858185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 859185363Sjkoshy &evmask); 860193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 861185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 862185363Sjkoshy &evmask); 863185363Sjkoshy } else 864185363Sjkoshy return (-1); 865206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 866206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 867206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 868240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 869206089Sfabient } else 870206089Sfabient return (-1); 871240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 872241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 873246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || 874246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { 875240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 876241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 877240164Sfabient } else 878240164Sfabient return (-1); 879248842Ssbruno } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL) { 880248842Ssbruno if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 881248842Ssbruno n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); 882248842Ssbruno } else 883248842Ssbruno return (-1); 884185363Sjkoshy } else 885185363Sjkoshy return (-1); 886185363Sjkoshy 887185363Sjkoshy if (n < 0) /* Parsing failed. */ 888185363Sjkoshy return (-1); 889185363Sjkoshy } 890185363Sjkoshy 891185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 892185363Sjkoshy 893185363Sjkoshy /* 894185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 895185363Sjkoshy * specified by the user, use a sensible default. 896185363Sjkoshy */ 897185363Sjkoshy switch (pe) { 898185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 899185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 900185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 901185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 902185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 903185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 904185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 905185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 906185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 907185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 908185363Sjkoshy if (cachestate == 0) 909185363Sjkoshy cachestate = (0xF << 8); 910207482Srstone break; 911207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 912207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 913207482Srstone * Atom processor 914207482Srstone */ 915207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 916207482Srstone cachestate = (0xF << 8); 917207482Srstone break; 918185363Sjkoshy default: 919185363Sjkoshy break; 920185363Sjkoshy } 921185363Sjkoshy 922185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 923206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 924185363Sjkoshy 925185363Sjkoshy return (0); 926185363Sjkoshy} 927185363Sjkoshy 928185363Sjkoshy/* 929206089Sfabient * Intel Uncore. 930206089Sfabient */ 931206089Sfabient 932206089Sfabientstatic int 933206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 934206089Sfabient struct pmc_op_pmcallocate *pmc_config) 935206089Sfabient{ 936206089Sfabient (void) pe; 937206089Sfabient (void) ctrspec; 938206089Sfabient 939206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 940206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 941206089Sfabient 942206089Sfabient return (0); 943206089Sfabient} 944206089Sfabient 945206089Sfabient#define UCP_KW_CMASK "cmask" 946206089Sfabient#define UCP_KW_EDGE "edge" 947206089Sfabient#define UCP_KW_INV "inv" 948206089Sfabient 949206089Sfabientstatic int 950206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 951206089Sfabient struct pmc_op_pmcallocate *pmc_config) 952206089Sfabient{ 953206089Sfabient char *e, *p, *q; 954206089Sfabient int count, n; 955206089Sfabient 956206089Sfabient (void) pe; 957206089Sfabient 958206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 959206089Sfabient PMC_CAP_QUALIFIER); 960206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 961206089Sfabient 962206089Sfabient /* Parse additional modifiers if present */ 963206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 964206089Sfabient 965206089Sfabient n = 0; 966206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 967206089Sfabient q = strchr(p, '='); 968206089Sfabient if (*++q == '\0') /* skip '=' */ 969206089Sfabient return (-1); 970206089Sfabient count = strtol(q, &e, 0); 971206089Sfabient if (e == q || *e != '\0') 972206089Sfabient return (-1); 973206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 974206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 975206089Sfabient UCP_CMASK(count); 976206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 977206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 978206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 979206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 980206089Sfabient } else 981206089Sfabient return (-1); 982206089Sfabient 983206089Sfabient if (n < 0) /* Parsing failed. */ 984206089Sfabient return (-1); 985206089Sfabient } 986206089Sfabient 987206089Sfabient return (0); 988206089Sfabient} 989206089Sfabient 990206089Sfabient/* 991147191Sjkoshy * AMD K8 PMCs. 992147191Sjkoshy * 993147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 994147191Sjkoshy * events. 995147191Sjkoshy */ 996147191Sjkoshy 997147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 998147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 999147191Sjkoshy EV_ALIAS("branch-mispredicts", 1000147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 1001147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1002147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 1003147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 1004183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 1005147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 1006155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 1007147191Sjkoshy EV_ALIAS(NULL, NULL) 1008147191Sjkoshy}; 1009147191Sjkoshy 1010147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 1011147191Sjkoshy 1012147191Sjkoshy/* 1013147191Sjkoshy * Parsing tables 1014147191Sjkoshy */ 1015147191Sjkoshy 1016147191Sjkoshy/* fp dispatched fpu ops */ 1017147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 1018147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 1019147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 1020147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 1021147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 1022147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 1023147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 1024147191Sjkoshy NULLMASK 1025147191Sjkoshy}; 1026147191Sjkoshy 1027147191Sjkoshy/* ls segment register loads */ 1028147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 1029147191Sjkoshy __K8MASK(es, 0), 1030147191Sjkoshy __K8MASK(cs, 1), 1031147191Sjkoshy __K8MASK(ss, 2), 1032147191Sjkoshy __K8MASK(ds, 3), 1033147191Sjkoshy __K8MASK(fs, 4), 1034147191Sjkoshy __K8MASK(gs, 5), 1035147191Sjkoshy __K8MASK(hs, 6), 1036147191Sjkoshy NULLMASK 1037147191Sjkoshy}; 1038147191Sjkoshy 1039147191Sjkoshy/* ls locked operation */ 1040147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 1041147191Sjkoshy __K8MASK(locked-instructions, 0), 1042147191Sjkoshy __K8MASK(cycles-in-request, 1), 1043147191Sjkoshy __K8MASK(cycles-to-complete, 2), 1044147191Sjkoshy NULLMASK 1045147191Sjkoshy}; 1046147191Sjkoshy 1047147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 1048147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 1049147191Sjkoshy __K8MASK(invalid, 0), 1050147191Sjkoshy __K8MASK(shared, 1), 1051147191Sjkoshy __K8MASK(exclusive, 2), 1052147191Sjkoshy __K8MASK(owner, 3), 1053147191Sjkoshy __K8MASK(modified, 4), 1054147191Sjkoshy NULLMASK 1055147191Sjkoshy}; 1056147191Sjkoshy 1057147191Sjkoshy/* dc one bit ecc error */ 1058147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1059147191Sjkoshy __K8MASK(scrubber, 0), 1060147191Sjkoshy __K8MASK(piggyback, 1), 1061147191Sjkoshy NULLMASK 1062147191Sjkoshy}; 1063147191Sjkoshy 1064147191Sjkoshy/* dc dispatched prefetch instructions */ 1065147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1066147191Sjkoshy __K8MASK(load, 0), 1067147191Sjkoshy __K8MASK(store, 1), 1068147191Sjkoshy __K8MASK(nta, 2), 1069147191Sjkoshy NULLMASK 1070147191Sjkoshy}; 1071147191Sjkoshy 1072147191Sjkoshy/* dc dcache accesses by locks */ 1073147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1074147191Sjkoshy __K8MASK(accesses, 0), 1075147191Sjkoshy __K8MASK(misses, 1), 1076147191Sjkoshy NULLMASK 1077147191Sjkoshy}; 1078147191Sjkoshy 1079147191Sjkoshy/* bu internal l2 request */ 1080147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1081147191Sjkoshy __K8MASK(ic-fill, 0), 1082147191Sjkoshy __K8MASK(dc-fill, 1), 1083147191Sjkoshy __K8MASK(tlb-reload, 2), 1084147191Sjkoshy __K8MASK(tag-snoop, 3), 1085147191Sjkoshy __K8MASK(cancelled, 4), 1086147191Sjkoshy NULLMASK 1087147191Sjkoshy}; 1088147191Sjkoshy 1089147191Sjkoshy/* bu fill request l2 miss */ 1090147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1091147191Sjkoshy __K8MASK(ic-fill, 0), 1092147191Sjkoshy __K8MASK(dc-fill, 1), 1093147191Sjkoshy __K8MASK(tlb-reload, 2), 1094147191Sjkoshy NULLMASK 1095147191Sjkoshy}; 1096147191Sjkoshy 1097147191Sjkoshy/* bu fill into l2 */ 1098147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1099147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1100147191Sjkoshy __K8MASK(victim-from-l2, 1), 1101147191Sjkoshy NULLMASK 1102147191Sjkoshy}; 1103147191Sjkoshy 1104147191Sjkoshy/* fr retired fpu instructions */ 1105147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1106147191Sjkoshy __K8MASK(x87, 0), 1107147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1108147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1109147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1110147191Sjkoshy NULLMASK 1111147191Sjkoshy}; 1112147191Sjkoshy 1113147191Sjkoshy/* fr retired fastpath double op instructions */ 1114147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1115147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1116147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1117147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1118147191Sjkoshy NULLMASK 1119147191Sjkoshy}; 1120147191Sjkoshy 1121147191Sjkoshy/* fr fpu exceptions */ 1122147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1123147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1124147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1125147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1126147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1127147191Sjkoshy NULLMASK 1128147191Sjkoshy}; 1129147191Sjkoshy 1130147191Sjkoshy/* nb memory controller page access event */ 1131147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1132147191Sjkoshy __K8MASK(page-hit, 0), 1133147191Sjkoshy __K8MASK(page-miss, 1), 1134147191Sjkoshy __K8MASK(page-conflict, 2), 1135147191Sjkoshy NULLMASK 1136147191Sjkoshy}; 1137147191Sjkoshy 1138147191Sjkoshy/* nb memory controller turnaround */ 1139147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1140147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1141147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1142147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1143147191Sjkoshy NULLMASK 1144147191Sjkoshy}; 1145147191Sjkoshy 1146147191Sjkoshy/* nb memory controller bypass saturation */ 1147147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1148147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1149147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1150147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1151147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1152147191Sjkoshy NULLMASK 1153147191Sjkoshy}; 1154147191Sjkoshy 1155147191Sjkoshy/* nb sized commands */ 1156147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1157147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1158147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1159147191Sjkoshy __K8MASK(postwrszbyte, 2), 1160147191Sjkoshy __K8MASK(postwrszdword, 3), 1161147191Sjkoshy __K8MASK(rdszbyte, 4), 1162147191Sjkoshy __K8MASK(rdszdword, 5), 1163147191Sjkoshy __K8MASK(rdmodwr, 6), 1164147191Sjkoshy NULLMASK 1165147191Sjkoshy}; 1166147191Sjkoshy 1167147191Sjkoshy/* nb probe result */ 1168147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1169147191Sjkoshy __K8MASK(probe-miss, 0), 1170147191Sjkoshy __K8MASK(probe-hit, 1), 1171147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1172147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1173147191Sjkoshy NULLMASK 1174147191Sjkoshy}; 1175147191Sjkoshy 1176147191Sjkoshy/* nb hypertransport bus bandwidth */ 1177147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1178147191Sjkoshy __K8MASK(command, 0), 1179183107Sjkoshy __K8MASK(data, 1), 1180147191Sjkoshy __K8MASK(buffer-release, 2), 1181147191Sjkoshy __K8MASK(nop, 3), 1182147191Sjkoshy NULLMASK 1183147191Sjkoshy}; 1184147191Sjkoshy 1185147191Sjkoshy#undef __K8MASK 1186147191Sjkoshy 1187147191Sjkoshy#define K8_KW_COUNT "count" 1188147191Sjkoshy#define K8_KW_EDGE "edge" 1189147191Sjkoshy#define K8_KW_INV "inv" 1190147191Sjkoshy#define K8_KW_MASK "mask" 1191147191Sjkoshy#define K8_KW_OS "os" 1192147191Sjkoshy#define K8_KW_USR "usr" 1193147191Sjkoshy 1194147191Sjkoshystatic int 1195147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1196147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1197147191Sjkoshy{ 1198183107Sjkoshy char *e, *p, *q; 1199183107Sjkoshy int n; 1200240164Sfabient uint32_t count; 1201240164Sfabient uint64_t evmask; 1202147191Sjkoshy const struct pmc_masks *pm, *pmask; 1203147191Sjkoshy 1204183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1205147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1206147191Sjkoshy 1207147191Sjkoshy pmask = NULL; 1208147191Sjkoshy evmask = 0; 1209147191Sjkoshy 1210147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1211147191Sjkoshy 1212147191Sjkoshy /* setup parsing tables */ 1213147191Sjkoshy switch (pe) { 1214147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1215147191Sjkoshy __K8SETMASK(fdfo); 1216147191Sjkoshy break; 1217147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1218147191Sjkoshy __K8SETMASK(lsrl); 1219147191Sjkoshy break; 1220147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1221147191Sjkoshy __K8SETMASK(llo); 1222147191Sjkoshy break; 1223147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1224147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1225147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1226147191Sjkoshy __K8SETMASK(dc); 1227147191Sjkoshy break; 1228147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1229147191Sjkoshy __K8SETMASK(dobee); 1230147191Sjkoshy break; 1231147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1232147191Sjkoshy __K8SETMASK(ddpi); 1233147191Sjkoshy break; 1234147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1235147191Sjkoshy __K8SETMASK(dabl); 1236147191Sjkoshy break; 1237147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1238147191Sjkoshy __K8SETMASK(bilr); 1239147191Sjkoshy break; 1240147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1241147191Sjkoshy __K8SETMASK(bfrlm); 1242147191Sjkoshy break; 1243147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1244147191Sjkoshy __K8SETMASK(bfil); 1245147191Sjkoshy break; 1246147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1247147191Sjkoshy __K8SETMASK(frfi); 1248147191Sjkoshy break; 1249147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1250147191Sjkoshy __K8SETMASK(frfdoi); 1251147191Sjkoshy break; 1252147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1253147191Sjkoshy __K8SETMASK(ffe); 1254147191Sjkoshy break; 1255147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1256147191Sjkoshy __K8SETMASK(nmcpae); 1257147191Sjkoshy break; 1258147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1259147191Sjkoshy __K8SETMASK(nmct); 1260147191Sjkoshy break; 1261147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1262147191Sjkoshy __K8SETMASK(nmcbs); 1263147191Sjkoshy break; 1264147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1265147191Sjkoshy __K8SETMASK(nsc); 1266147191Sjkoshy break; 1267147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1268147191Sjkoshy __K8SETMASK(npr); 1269147191Sjkoshy break; 1270147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1271147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1272147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1273147191Sjkoshy __K8SETMASK(nhbb); 1274147191Sjkoshy break; 1275147191Sjkoshy 1276147191Sjkoshy default: 1277147191Sjkoshy break; /* no options defined */ 1278147191Sjkoshy } 1279147191Sjkoshy 1280147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1281147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1282147191Sjkoshy q = strchr(p, '='); 1283147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1284174406Sjkoshy return (-1); 1285147191Sjkoshy 1286147191Sjkoshy count = strtol(q, &e, 0); 1287147191Sjkoshy if (e == q || *e != '\0') 1288174406Sjkoshy return (-1); 1289147191Sjkoshy 1290147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1291147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1292147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1293147191Sjkoshy 1294147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1295147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1296147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1297147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1298147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1299147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1300174406Sjkoshy return (-1); 1301147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1302147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1303147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1304147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1305147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1306147191Sjkoshy } else 1307174406Sjkoshy return (-1); 1308147191Sjkoshy } 1309147191Sjkoshy 1310147191Sjkoshy /* other post processing */ 1311147191Sjkoshy switch (pe) { 1312147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1313147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1314147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1315147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1316147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1317147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1318147191Sjkoshy /* XXX only available in rev B and later */ 1319147191Sjkoshy break; 1320147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1321147191Sjkoshy /* XXX only available in rev C and later */ 1322147191Sjkoshy break; 1323147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1324147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1325147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1326174406Sjkoshy return (-1); 1327147191Sjkoshy if (evmask == 0) { 1328147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1329147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1330147191Sjkoshy } 1331147191Sjkoshy break; 1332147191Sjkoshy default: 1333147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1334147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1335147191Sjkoshy evmask |= pm->pm_value; 1336147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1337147191Sjkoshy } 1338147191Sjkoshy } 1339147191Sjkoshy 1340147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1341147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1342147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1343147191Sjkoshy 1344174406Sjkoshy return (0); 1345147191Sjkoshy} 1346147191Sjkoshy 1347147191Sjkoshy#endif 1348147191Sjkoshy 1349147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1350147191Sjkoshy 1351147191Sjkoshy/* 1352145256Sjkoshy * Intel P4 PMCs 1353145256Sjkoshy */ 1354145256Sjkoshy 1355145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1356145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1357145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1358145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1359145351Sjkoshy EV_ALIAS("instructions", 1360145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1361155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1362145256Sjkoshy EV_ALIAS(NULL, NULL) 1363145256Sjkoshy}; 1364145256Sjkoshy 1365145256Sjkoshy#define P4_KW_ACTIVE "active" 1366145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1367145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1368145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1369145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1370145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1371145256Sjkoshy#define P4_KW_CASCADE "cascade" 1372145256Sjkoshy#define P4_KW_EDGE "edge" 1373145256Sjkoshy#define P4_KW_INV "complement" 1374145256Sjkoshy#define P4_KW_OS "os" 1375145256Sjkoshy#define P4_KW_MASK "mask" 1376145256Sjkoshy#define P4_KW_PRECISE "precise" 1377145256Sjkoshy#define P4_KW_TAG "tag" 1378145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1379145256Sjkoshy#define P4_KW_USR "usr" 1380145256Sjkoshy 1381145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1382145256Sjkoshy 1383145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1384145256Sjkoshy __P4MASK(dd, 0), 1385145256Sjkoshy __P4MASK(db, 1), 1386145256Sjkoshy __P4MASK(di, 2), 1387145256Sjkoshy __P4MASK(bd, 3), 1388145256Sjkoshy __P4MASK(bb, 4), 1389145256Sjkoshy __P4MASK(bi, 5), 1390145256Sjkoshy __P4MASK(id, 6), 1391145256Sjkoshy __P4MASK(ib, 7), 1392145256Sjkoshy NULLMASK 1393145256Sjkoshy}; 1394145256Sjkoshy 1395145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1396145256Sjkoshy __P4MASK(tcmiss, 0), 1397145256Sjkoshy NULLMASK, 1398145256Sjkoshy}; 1399145256Sjkoshy 1400145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1401145256Sjkoshy __P4MASK(hit, 0), 1402145256Sjkoshy __P4MASK(miss, 1), 1403145256Sjkoshy __P4MASK(hit-uc, 2), 1404145256Sjkoshy NULLMASK 1405145256Sjkoshy}; 1406145256Sjkoshy 1407145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1408145256Sjkoshy __P4MASK(st-rb-full, 2), 1409145256Sjkoshy __P4MASK(64k-conf, 3), 1410145256Sjkoshy NULLMASK 1411145256Sjkoshy}; 1412145256Sjkoshy 1413145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1414145256Sjkoshy __P4MASK(lsc, 0), 1415145256Sjkoshy __P4MASK(ssc, 1), 1416145256Sjkoshy NULLMASK 1417145256Sjkoshy}; 1418145256Sjkoshy 1419145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1420145256Sjkoshy __P4MASK(split-ld, 1), 1421145256Sjkoshy NULLMASK 1422145256Sjkoshy}; 1423145256Sjkoshy 1424145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1425145256Sjkoshy __P4MASK(split-st, 1), 1426145256Sjkoshy NULLMASK 1427145256Sjkoshy}; 1428145256Sjkoshy 1429145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1430145256Sjkoshy __P4MASK(no-sta, 1), 1431145256Sjkoshy __P4MASK(no-std, 3), 1432145256Sjkoshy __P4MASK(partial-data, 4), 1433145256Sjkoshy __P4MASK(unalgn-addr, 5), 1434145256Sjkoshy NULLMASK 1435145256Sjkoshy}; 1436145256Sjkoshy 1437145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1438145256Sjkoshy __P4MASK(dtmiss, 0), 1439145256Sjkoshy __P4MASK(itmiss, 1), 1440145256Sjkoshy NULLMASK 1441145256Sjkoshy}; 1442145256Sjkoshy 1443145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1444145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1445145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1446145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1447145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1448145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1449145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1450145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1451145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1452145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1453145256Sjkoshy NULLMASK 1454145256Sjkoshy}; 1455145256Sjkoshy 1456145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1457145256Sjkoshy __P4MASK(all-read, 5), 1458145256Sjkoshy __P4MASK(all-write, 6), 1459145256Sjkoshy __P4MASK(mem-uc, 7), 1460145256Sjkoshy __P4MASK(mem-wc, 8), 1461145256Sjkoshy __P4MASK(mem-wt, 9), 1462145256Sjkoshy __P4MASK(mem-wp, 10), 1463145256Sjkoshy __P4MASK(mem-wb, 11), 1464145256Sjkoshy __P4MASK(own, 13), 1465145256Sjkoshy __P4MASK(other, 14), 1466145256Sjkoshy __P4MASK(prefetch, 15), 1467145256Sjkoshy NULLMASK 1468145256Sjkoshy}; 1469145256Sjkoshy 1470145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1471145256Sjkoshy __P4MASK(all-read, 5), 1472145256Sjkoshy __P4MASK(all-write, 6), 1473145256Sjkoshy __P4MASK(mem-uc, 7), 1474145256Sjkoshy __P4MASK(mem-wc, 8), 1475145256Sjkoshy __P4MASK(mem-wt, 9), 1476145256Sjkoshy __P4MASK(mem-wp, 10), 1477145256Sjkoshy __P4MASK(mem-wb, 11), 1478145256Sjkoshy __P4MASK(own, 13), 1479145256Sjkoshy __P4MASK(other, 14), 1480145256Sjkoshy __P4MASK(prefetch, 15), 1481145256Sjkoshy NULLMASK 1482145256Sjkoshy}; 1483145256Sjkoshy 1484145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1485145256Sjkoshy __P4MASK(drdy-drv, 0), 1486145256Sjkoshy __P4MASK(drdy-own, 1), 1487145256Sjkoshy __P4MASK(drdy-other, 2), 1488145256Sjkoshy __P4MASK(dbsy-drv, 3), 1489145256Sjkoshy __P4MASK(dbsy-own, 4), 1490145256Sjkoshy __P4MASK(dbsy-other, 5), 1491145256Sjkoshy NULLMASK 1492145256Sjkoshy}; 1493145256Sjkoshy 1494145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1495145256Sjkoshy __P4MASK(req-type0, 0), 1496145256Sjkoshy __P4MASK(req-type1, 1), 1497145256Sjkoshy __P4MASK(req-len0, 2), 1498145256Sjkoshy __P4MASK(req-len1, 3), 1499145256Sjkoshy __P4MASK(req-io-type, 5), 1500145256Sjkoshy __P4MASK(req-lock-type, 6), 1501145256Sjkoshy __P4MASK(req-cache-type, 7), 1502145256Sjkoshy __P4MASK(req-split-type, 8), 1503145256Sjkoshy __P4MASK(req-dem-type, 9), 1504145256Sjkoshy __P4MASK(req-ord-type, 10), 1505145256Sjkoshy __P4MASK(mem-type0, 11), 1506145256Sjkoshy __P4MASK(mem-type1, 12), 1507145256Sjkoshy __P4MASK(mem-type2, 13), 1508145256Sjkoshy NULLMASK 1509145256Sjkoshy}; 1510145256Sjkoshy 1511145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1512145256Sjkoshy __P4MASK(all, 15), 1513145256Sjkoshy NULLMASK 1514145256Sjkoshy}; 1515145256Sjkoshy 1516145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1517145256Sjkoshy __P4MASK(all, 15), 1518145256Sjkoshy NULLMASK 1519145256Sjkoshy}; 1520145256Sjkoshy 1521145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1522145256Sjkoshy __P4MASK(all, 15), 1523145256Sjkoshy NULLMASK 1524145256Sjkoshy}; 1525145256Sjkoshy 1526145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1527145256Sjkoshy __P4MASK(all, 15), 1528145256Sjkoshy NULLMASK 1529145256Sjkoshy}; 1530145256Sjkoshy 1531145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1532145256Sjkoshy __P4MASK(all, 15), 1533145256Sjkoshy NULLMASK 1534145256Sjkoshy}; 1535145256Sjkoshy 1536145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1537145256Sjkoshy __P4MASK(all, 15), 1538145256Sjkoshy NULLMASK 1539145256Sjkoshy}; 1540145256Sjkoshy 1541145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1542145256Sjkoshy __P4MASK(all, 15), 1543145256Sjkoshy NULLMASK 1544145256Sjkoshy}; 1545145256Sjkoshy 1546145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1547145256Sjkoshy __P4MASK(all, 15), 1548145256Sjkoshy NULLMASK 1549145256Sjkoshy}; 1550145256Sjkoshy 1551145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1552145256Sjkoshy __P4MASK(allp0, 3), 1553145256Sjkoshy __P4MASK(allp2, 4), 1554145256Sjkoshy NULLMASK 1555145256Sjkoshy}; 1556145256Sjkoshy 1557145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1558145256Sjkoshy __P4MASK(running, 0), 1559145256Sjkoshy NULLMASK 1560145256Sjkoshy}; 1561145256Sjkoshy 1562145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1563145256Sjkoshy __P4MASK(cisc, 0), 1564145256Sjkoshy NULLMASK 1565145256Sjkoshy}; 1566145256Sjkoshy 1567145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1568145256Sjkoshy __P4MASK(from-tc-build, 0), 1569145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1570145256Sjkoshy __P4MASK(from-rom, 2), 1571145256Sjkoshy NULLMASK 1572145256Sjkoshy}; 1573145256Sjkoshy 1574145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1575145351Sjkoshy /* retired mispred branch type */ 1576145256Sjkoshy __P4MASK(conditional, 1), 1577145256Sjkoshy __P4MASK(call, 2), 1578145256Sjkoshy __P4MASK(return, 3), 1579145256Sjkoshy __P4MASK(indirect, 4), 1580145256Sjkoshy NULLMASK 1581145256Sjkoshy}; 1582145256Sjkoshy 1583145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1584145256Sjkoshy __P4MASK(conditional, 1), 1585145256Sjkoshy __P4MASK(call, 2), 1586145256Sjkoshy __P4MASK(retired, 3), 1587145256Sjkoshy __P4MASK(indirect, 4), 1588145256Sjkoshy NULLMASK 1589145256Sjkoshy}; 1590145256Sjkoshy 1591145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1592145256Sjkoshy __P4MASK(sbfull, 5), 1593145256Sjkoshy NULLMASK 1594145256Sjkoshy}; 1595145256Sjkoshy 1596145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1597145256Sjkoshy __P4MASK(wcb-evicts, 0), 1598145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1599145256Sjkoshy NULLMASK 1600145256Sjkoshy}; 1601145256Sjkoshy 1602145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1603145256Sjkoshy __P4MASK(nbogus, 0), 1604145256Sjkoshy __P4MASK(bogus, 1), 1605145256Sjkoshy NULLMASK 1606145256Sjkoshy}; 1607145256Sjkoshy 1608145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1609145256Sjkoshy __P4MASK(nbogus0, 0), 1610145256Sjkoshy __P4MASK(nbogus1, 1), 1611145256Sjkoshy __P4MASK(nbogus2, 2), 1612145256Sjkoshy __P4MASK(nbogus3, 3), 1613145256Sjkoshy __P4MASK(bogus0, 4), 1614145256Sjkoshy __P4MASK(bogus1, 5), 1615145256Sjkoshy __P4MASK(bogus2, 6), 1616145256Sjkoshy __P4MASK(bogus3, 7), 1617145256Sjkoshy NULLMASK 1618145256Sjkoshy}; 1619145256Sjkoshy 1620145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1621145256Sjkoshy __P4MASK(nbogus, 0), 1622145256Sjkoshy __P4MASK(bogus, 1), 1623145256Sjkoshy NULLMASK 1624145256Sjkoshy}; 1625145256Sjkoshy 1626145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1627145256Sjkoshy __P4MASK(nbogusntag, 0), 1628145256Sjkoshy __P4MASK(nbogustag, 1), 1629145256Sjkoshy __P4MASK(bogusntag, 2), 1630145256Sjkoshy __P4MASK(bogustag, 3), 1631145256Sjkoshy NULLMASK 1632145256Sjkoshy}; 1633145256Sjkoshy 1634145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1635145256Sjkoshy __P4MASK(nbogus, 0), 1636145256Sjkoshy __P4MASK(bogus, 1), 1637145256Sjkoshy NULLMASK 1638145256Sjkoshy}; 1639145256Sjkoshy 1640145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1641145256Sjkoshy __P4MASK(tagloads, 1), 1642145256Sjkoshy __P4MASK(tagstores, 2), 1643145256Sjkoshy NULLMASK 1644145256Sjkoshy}; 1645145256Sjkoshy 1646145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1647145256Sjkoshy __P4MASK(mmnp, 0), 1648145256Sjkoshy __P4MASK(mmnm, 1), 1649145256Sjkoshy __P4MASK(mmtp, 2), 1650145256Sjkoshy __P4MASK(mmtm, 3), 1651145256Sjkoshy NULLMASK 1652145256Sjkoshy}; 1653145256Sjkoshy 1654145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1655145256Sjkoshy __P4MASK(nbogus, 0), 1656145256Sjkoshy NULLMASK 1657145256Sjkoshy}; 1658145256Sjkoshy 1659145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1660145256Sjkoshy __P4MASK(fpsu, 0), 1661145256Sjkoshy __P4MASK(fpso, 1), 1662145256Sjkoshy __P4MASK(poao, 2), 1663145256Sjkoshy __P4MASK(poau, 3), 1664145256Sjkoshy __P4MASK(prea, 4), 1665145256Sjkoshy NULLMASK 1666145256Sjkoshy}; 1667145256Sjkoshy 1668145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1669145256Sjkoshy __P4MASK(clear, 0), 1670145256Sjkoshy __P4MASK(moclear, 2), 1671145256Sjkoshy __P4MASK(smclear, 3), 1672145256Sjkoshy NULLMASK 1673145256Sjkoshy}; 1674145256Sjkoshy 1675145256Sjkoshy/* P4 event parser */ 1676145256Sjkoshystatic int 1677145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1678145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1679145256Sjkoshy{ 1680145256Sjkoshy 1681145256Sjkoshy char *e, *p, *q; 1682145256Sjkoshy int count, has_tag, has_busreqtype, n; 1683240164Sfabient uint32_t cccractivemask; 1684240164Sfabient uint64_t evmask; 1685145256Sjkoshy const struct pmc_masks *pm, *pmask; 1686145256Sjkoshy 1687183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1688147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1689147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1690145256Sjkoshy 1691145256Sjkoshy pmask = NULL; 1692145256Sjkoshy evmask = 0; 1693145256Sjkoshy cccractivemask = 0x3; 1694145256Sjkoshy has_tag = has_busreqtype = 0; 1695145256Sjkoshy 1696145256Sjkoshy#define __P4SETMASK(M) do { \ 1697183107Sjkoshy pmask = p4_mask_##M; \ 1698145256Sjkoshy} while (0) 1699145256Sjkoshy 1700145256Sjkoshy switch (pe) { 1701145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1702145256Sjkoshy __P4SETMASK(tcdm); 1703145256Sjkoshy break; 1704145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1705145256Sjkoshy __P4SETMASK(bfr); 1706145256Sjkoshy break; 1707145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1708145256Sjkoshy __P4SETMASK(ir); 1709145256Sjkoshy break; 1710145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1711145256Sjkoshy __P4SETMASK(memcan); 1712145256Sjkoshy break; 1713145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1714145256Sjkoshy __P4SETMASK(memcomp); 1715145256Sjkoshy break; 1716145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1717145256Sjkoshy __P4SETMASK(lpr); 1718145256Sjkoshy break; 1719145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1720145256Sjkoshy __P4SETMASK(spr); 1721145256Sjkoshy break; 1722145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1723145256Sjkoshy __P4SETMASK(mlr); 1724145256Sjkoshy break; 1725145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1726145256Sjkoshy __P4SETMASK(pwt); 1727145256Sjkoshy break; 1728145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1729145256Sjkoshy __P4SETMASK(bcr); 1730145256Sjkoshy break; 1731145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1732145256Sjkoshy __P4SETMASK(ia); 1733145256Sjkoshy has_busreqtype = 1; 1734145256Sjkoshy break; 1735145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1736145256Sjkoshy __P4SETMASK(iae); 1737145256Sjkoshy has_busreqtype = 1; 1738145256Sjkoshy break; 1739145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1740145256Sjkoshy __P4SETMASK(fda); 1741145256Sjkoshy break; 1742145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1743145256Sjkoshy __P4SETMASK(ba); 1744145256Sjkoshy break; 1745145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1746145256Sjkoshy __P4SETMASK(sia); 1747145256Sjkoshy break; 1748145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1749145256Sjkoshy __P4SETMASK(psu); 1750145256Sjkoshy break; 1751145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1752145256Sjkoshy __P4SETMASK(pdu); 1753145256Sjkoshy break; 1754145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1755145256Sjkoshy __P4SETMASK(ssu); 1756145256Sjkoshy break; 1757145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1758145256Sjkoshy __P4SETMASK(sdu); 1759145256Sjkoshy break; 1760145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1761145256Sjkoshy __P4SETMASK(64bmu); 1762145256Sjkoshy break; 1763145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1764145256Sjkoshy __P4SETMASK(128bmu); 1765145256Sjkoshy break; 1766145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1767145256Sjkoshy __P4SETMASK(xfu); 1768145256Sjkoshy break; 1769145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1770145256Sjkoshy __P4SETMASK(xsmu); 1771145256Sjkoshy break; 1772145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1773145256Sjkoshy __P4SETMASK(gpe); 1774145256Sjkoshy break; 1775145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1776145256Sjkoshy __P4SETMASK(tmx); 1777145256Sjkoshy break; 1778145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1779145256Sjkoshy __P4SETMASK(uqw); 1780145256Sjkoshy break; 1781145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1782145256Sjkoshy __P4SETMASK(rmbt); 1783145256Sjkoshy break; 1784145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1785145256Sjkoshy __P4SETMASK(rbt); 1786145256Sjkoshy break; 1787145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1788145256Sjkoshy __P4SETMASK(rs); 1789145256Sjkoshy break; 1790145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1791145256Sjkoshy __P4SETMASK(wb); 1792145256Sjkoshy break; 1793145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1794145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1795145256Sjkoshy case PMC_EV_P4_BNR: 1796145256Sjkoshy case PMC_EV_P4_SNOOP: 1797145256Sjkoshy case PMC_EV_P4_RESPONSE: 1798145256Sjkoshy break; 1799145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1800145256Sjkoshy __P4SETMASK(fee); 1801145256Sjkoshy break; 1802145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1803145256Sjkoshy __P4SETMASK(ee); 1804145256Sjkoshy break; 1805145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1806145256Sjkoshy __P4SETMASK(re); 1807145256Sjkoshy break; 1808145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1809145256Sjkoshy __P4SETMASK(insret); 1810145256Sjkoshy break; 1811145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1812145256Sjkoshy __P4SETMASK(ur); 1813145256Sjkoshy break; 1814145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1815145256Sjkoshy __P4SETMASK(ut); 1816145256Sjkoshy break; 1817145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1818145256Sjkoshy __P4SETMASK(br); 1819145256Sjkoshy break; 1820145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1821145256Sjkoshy __P4SETMASK(mbr); 1822145256Sjkoshy break; 1823145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1824145256Sjkoshy __P4SETMASK(xa); 1825145256Sjkoshy break; 1826145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1827145256Sjkoshy __P4SETMASK(machclr); 1828145256Sjkoshy break; 1829145256Sjkoshy default: 1830174406Sjkoshy return (-1); 1831145256Sjkoshy } 1832145256Sjkoshy 1833145256Sjkoshy /* process additional flags */ 1834145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1835145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1836145256Sjkoshy q = strchr(p, '='); 1837145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1838174406Sjkoshy return (-1); 1839145256Sjkoshy 1840183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1841145256Sjkoshy cccractivemask = 0x0; 1842183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1843145256Sjkoshy cccractivemask = 0x1; 1844183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1845145256Sjkoshy cccractivemask = 0x2; 1846183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1847145256Sjkoshy cccractivemask = 0x3; 1848145256Sjkoshy else 1849174406Sjkoshy return (-1); 1850145256Sjkoshy 1851145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1852145256Sjkoshy if (has_busreqtype == 0) 1853174406Sjkoshy return (-1); 1854145256Sjkoshy 1855145256Sjkoshy q = strchr(p, '='); 1856145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1857174406Sjkoshy return (-1); 1858145256Sjkoshy 1859145256Sjkoshy count = strtol(q, &e, 0); 1860145256Sjkoshy if (e == q || *e != '\0') 1861174406Sjkoshy return (-1); 1862145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1863145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1864145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1865145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1866145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1867145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1868145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1869145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1870145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1871174406Sjkoshy return (-1); 1872145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1873145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1874145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1875145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1876145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1877145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1878145256Sjkoshy if (has_tag == 0) 1879174406Sjkoshy return (-1); 1880145256Sjkoshy 1881145256Sjkoshy q = strchr(p, '='); 1882145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1883174406Sjkoshy return (-1); 1884145256Sjkoshy 1885145256Sjkoshy count = strtol(q, &e, 0); 1886145256Sjkoshy if (e == q || *e != '\0') 1887174406Sjkoshy return (-1); 1888145256Sjkoshy 1889145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1890147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1891145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1892145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1893145256Sjkoshy q = strchr(p, '='); 1894145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1895174406Sjkoshy return (-1); 1896145256Sjkoshy 1897145256Sjkoshy count = strtol(q, &e, 0); 1898145256Sjkoshy if (e == q || *e != '\0') 1899174406Sjkoshy return (-1); 1900145256Sjkoshy 1901145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1902147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1903147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1904147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1905147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1906145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1907145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1908145256Sjkoshy else 1909174406Sjkoshy return (-1); 1910145256Sjkoshy } 1911145256Sjkoshy 1912145256Sjkoshy /* other post processing */ 1913145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1914145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1915145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1916145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1917145256Sjkoshy 1918145256Sjkoshy /* fill in thread activity mask */ 1919147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1920145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1921145256Sjkoshy 1922145256Sjkoshy if (evmask) 1923145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1924145256Sjkoshy 1925145256Sjkoshy switch (pe) { 1926145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1927145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1928145256Sjkoshy (evmask & 0x18) == 0x18) 1929174406Sjkoshy return (-1); /* can't have own+other bits together */ 1930145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1931145256Sjkoshy evmask = 0x1D; 1932145256Sjkoshy break; 1933145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1934145256Sjkoshy /* only one bit is allowed to be set */ 1935145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1936174406Sjkoshy return (-1); 1937145256Sjkoshy if (evmask == 0) { 1938183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1939145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1940145256Sjkoshy } 1941145256Sjkoshy break; 1942145256Sjkoshy default: 1943145256Sjkoshy if (evmask == 0 && pmask) { 1944145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1945145256Sjkoshy evmask |= pm->pm_value; 1946145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1947145256Sjkoshy } 1948145256Sjkoshy } 1949145256Sjkoshy 1950147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1951147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1952145256Sjkoshy 1953174406Sjkoshy return (0); 1954145256Sjkoshy} 1955145256Sjkoshy 1956147759Sjkoshy#endif 1957147759Sjkoshy 1958147759Sjkoshy#if defined(__i386__) 1959147759Sjkoshy 1960145256Sjkoshy/* 1961147191Sjkoshy * Pentium style PMCs 1962147191Sjkoshy */ 1963147191Sjkoshy 1964147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1965183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1966183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1967183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1968183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1969183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1970183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1971183105Sjkoshy EV_ALIAS("unhalted-cycles", 1972183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1973147191Sjkoshy EV_ALIAS(NULL, NULL) 1974147191Sjkoshy}; 1975147191Sjkoshy 1976147191Sjkoshystatic int 1977147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1978147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1979147191Sjkoshy{ 1980174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1981147191Sjkoshy} 1982147191Sjkoshy 1983147191Sjkoshy/* 1984145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1985145256Sjkoshy * and Pentium M CPUs. 1986145256Sjkoshy */ 1987145256Sjkoshy 1988145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1989145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1990145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1991145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1992145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1993168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1994145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1995145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1996155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1997145351Sjkoshy EV_ALIAS(NULL, NULL) 1998145256Sjkoshy}; 1999145256Sjkoshy 2000145256Sjkoshy#define P6_KW_CMASK "cmask" 2001145256Sjkoshy#define P6_KW_EDGE "edge" 2002145256Sjkoshy#define P6_KW_INV "inv" 2003145256Sjkoshy#define P6_KW_OS "os" 2004145256Sjkoshy#define P6_KW_UMASK "umask" 2005145256Sjkoshy#define P6_KW_USR "usr" 2006145256Sjkoshy 2007145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 2008145256Sjkoshy PMCMASK(m, 0x01), 2009145256Sjkoshy PMCMASK(e, 0x02), 2010145256Sjkoshy PMCMASK(s, 0x04), 2011145256Sjkoshy PMCMASK(i, 0x08), 2012145256Sjkoshy NULLMASK 2013145256Sjkoshy}; 2014145256Sjkoshy 2015145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 2016145256Sjkoshy PMCMASK(m, 0x01), 2017145256Sjkoshy PMCMASK(e, 0x02), 2018145256Sjkoshy PMCMASK(s, 0x04), 2019145256Sjkoshy PMCMASK(i, 0x08), 2020145256Sjkoshy PMCMASK(nonhw, 0x00), 2021145256Sjkoshy PMCMASK(hw, 0x10), 2022145256Sjkoshy PMCMASK(both, 0x30), 2023145256Sjkoshy NULLMASK 2024145256Sjkoshy}; 2025145256Sjkoshy 2026145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 2027145256Sjkoshy PMCMASK(nonhw, 0x00), 2028145256Sjkoshy PMCMASK(hw, 0x10), 2029145256Sjkoshy PMCMASK(both, 0x30), 2030145256Sjkoshy NULLMASK 2031145256Sjkoshy}; 2032145256Sjkoshy 2033145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 2034145256Sjkoshy PMCMASK(self, 0x00), 2035145256Sjkoshy PMCMASK(any, 0x20), 2036145256Sjkoshy NULLMASK 2037145256Sjkoshy}; 2038145256Sjkoshy 2039145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 2040145256Sjkoshy PMCMASK(nta, 0x00), 2041145256Sjkoshy PMCMASK(t1, 0x01), 2042145256Sjkoshy PMCMASK(t2, 0x02), 2043145256Sjkoshy PMCMASK(wos, 0x03), 2044145256Sjkoshy NULLMASK 2045145256Sjkoshy}; 2046145256Sjkoshy 2047145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 2048145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 2049145256Sjkoshy PMCMASK(scalar, 0x01), 2050145256Sjkoshy NULLMASK 2051145256Sjkoshy}; 2052145256Sjkoshy 2053145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 2054145256Sjkoshy PMCMASK(packed-multiply, 0x01), 2055145256Sjkoshy PMCMASK(packed-shift, 0x02), 2056145256Sjkoshy PMCMASK(pack, 0x04), 2057145256Sjkoshy PMCMASK(unpack, 0x08), 2058145256Sjkoshy PMCMASK(packed-logical, 0x10), 2059145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 2060145256Sjkoshy NULLMASK 2061145256Sjkoshy}; 2062145256Sjkoshy 2063145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 2064145256Sjkoshy PMCMASK(mmxtofp, 0x00), 2065145256Sjkoshy PMCMASK(fptommx, 0x01), 2066145256Sjkoshy NULLMASK 2067145256Sjkoshy}; 2068145256Sjkoshy 2069145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2070145256Sjkoshy PMCMASK(es, 0x01), 2071145256Sjkoshy PMCMASK(ds, 0x02), 2072145256Sjkoshy PMCMASK(fs, 0x04), 2073145256Sjkoshy PMCMASK(gs, 0x08), 2074145256Sjkoshy NULLMASK 2075145256Sjkoshy}; 2076145256Sjkoshy 2077145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2078145256Sjkoshy PMCMASK(all, 0x00), 2079145256Sjkoshy PMCMASK(freq, 0x02), 2080145256Sjkoshy NULLMASK 2081145256Sjkoshy}; 2082145256Sjkoshy 2083145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2084145256Sjkoshy PMCMASK(all, 0x00), 2085145256Sjkoshy PMCMASK(loadop, 0x01), 2086145256Sjkoshy PMCMASK(stdsta, 0x02), 2087145256Sjkoshy NULLMASK 2088145256Sjkoshy}; 2089145256Sjkoshy 2090145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2091145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2092145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2093145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2094145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2095145256Sjkoshy NULLMASK 2096145256Sjkoshy}; 2097145256Sjkoshy 2098145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2099145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2100145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2101145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2102145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2103145256Sjkoshy NULLMASK 2104145256Sjkoshy}; 2105145256Sjkoshy 2106145256Sjkoshy/* P6 event parser */ 2107145256Sjkoshystatic int 2108145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2109145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2110145256Sjkoshy{ 2111145256Sjkoshy char *e, *p, *q; 2112240164Sfabient uint64_t evmask; 2113145256Sjkoshy int count, n; 2114145256Sjkoshy const struct pmc_masks *pm, *pmask; 2115145256Sjkoshy 2116183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2117147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2118145256Sjkoshy 2119145256Sjkoshy evmask = 0; 2120145256Sjkoshy 2121145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2122145256Sjkoshy 2123145256Sjkoshy switch(pe) { 2124183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2125145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2126145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2127145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2128145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2129145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2130145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2131145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2132145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2133145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2134145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2135145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2136145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2137145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2138145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2139145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2140145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2141145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2142145256Sjkoshy P6MASKSET(any); break; 2143145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2144145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2145145256Sjkoshy P6MASKSET(ekp); break; 2146145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2147145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2148145256Sjkoshy P6MASKSET(pps); break; 2149145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2150145256Sjkoshy P6MASKSET(mite); break; 2151145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2152145256Sjkoshy P6MASKSET(fmt); break; 2153145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2154145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2155145256Sjkoshy P6MASKSET(sr); break; 2156145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2157145256Sjkoshy P6MASKSET(eet); break; 2158145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2159145256Sjkoshy P6MASKSET(efur); break; 2160145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2161145256Sjkoshy P6MASKSET(essir); break; 2162145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2163145256Sjkoshy P6MASKSET(esscir); break; 2164145256Sjkoshy default: 2165145256Sjkoshy pmask = NULL; 2166145256Sjkoshy break; 2167145256Sjkoshy } 2168145256Sjkoshy 2169145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2170145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2171145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2172145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2173145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2174145256Sjkoshy P6MASKSET(mesihw); 2175145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2176145256Sjkoshy P6MASKSET(hw); 2177145256Sjkoshy } 2178145256Sjkoshy 2179145256Sjkoshy /* Parse additional modifiers if present */ 2180145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2181145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2182145256Sjkoshy q = strchr(p, '='); 2183145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2184174406Sjkoshy return (-1); 2185145256Sjkoshy count = strtol(q, &e, 0); 2186145256Sjkoshy if (e == q || *e != '\0') 2187174406Sjkoshy return (-1); 2188145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2189147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2190147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2191145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2192145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2193145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2194145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2195145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2196145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2197145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2198145256Sjkoshy evmask = 0; 2199145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2200174406Sjkoshy return (-1); 2201145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2202145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2203145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2204145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2205145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2206145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2207145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2208145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2209145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2210145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2211145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2212145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2213145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2214145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2215145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2216145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2217145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2218145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2219145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2220145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2221145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2222145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2223145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2224174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2225174406Sjkoshy return (-1); 2226145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2227145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2228145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2229145256Sjkoshy } else 2230174406Sjkoshy return (-1); 2231145256Sjkoshy } 2232145256Sjkoshy 2233145256Sjkoshy /* post processing */ 2234145256Sjkoshy switch (pe) { 2235145256Sjkoshy 2236145256Sjkoshy /* 2237145256Sjkoshy * The following events default to an evmask of 0 2238145256Sjkoshy */ 2239145256Sjkoshy 2240145256Sjkoshy /* default => 'self' */ 2241145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2242145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2243145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2244145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2245145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2246145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2247145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2248145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2249145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2250145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2251145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2252145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2253145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2254145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2255145256Sjkoshy 2256145256Sjkoshy /* default => 'nta' */ 2257145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2258145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2259145256Sjkoshy 2260145256Sjkoshy /* default => 'packed and scalar' */ 2261145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2262145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2263145256Sjkoshy 2264145256Sjkoshy /* default => 'mmx to fp transitions' */ 2265145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2266145256Sjkoshy 2267145256Sjkoshy /* default => 'SSE Packed Single' */ 2268145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2269145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2270145256Sjkoshy 2271145256Sjkoshy /* default => 'all fused micro-ops' */ 2272145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2273145256Sjkoshy 2274145256Sjkoshy /* default => 'all transitions' */ 2275145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2276145256Sjkoshy break; 2277145256Sjkoshy 2278145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2279145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2280145256Sjkoshy break; 2281145256Sjkoshy 2282145256Sjkoshy default: 2283145256Sjkoshy /* 2284145256Sjkoshy * For all other events, set the default event mask 2285145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2286145256Sjkoshy */ 2287145256Sjkoshy if (evmask == 0 && pmask) { 2288145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2289145256Sjkoshy evmask |= pm->pm_value; 2290145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2291145256Sjkoshy } 2292145256Sjkoshy 2293145256Sjkoshy break; 2294145256Sjkoshy } 2295145256Sjkoshy 2296145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2297147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2298147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2299145256Sjkoshy 2300174406Sjkoshy return (0); 2301145256Sjkoshy} 2302145256Sjkoshy 2303147191Sjkoshy#endif 2304147191Sjkoshy 2305183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2306183725Sjkoshystatic int 2307183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2308183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2309183725Sjkoshy{ 2310183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2311183725Sjkoshy return (-1); 2312183725Sjkoshy 2313183725Sjkoshy /* TSC events must be unqualified. */ 2314183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2315183725Sjkoshy return (-1); 2316183725Sjkoshy 2317183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2318183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2319183725Sjkoshy 2320183725Sjkoshy return (0); 2321183725Sjkoshy} 2322183725Sjkoshy#endif 2323183725Sjkoshy 2324233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2325233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2326233628Sfabient EV_ALIAS(NULL, NULL) 2327233628Sfabient}; 2328233628Sfabient 2329233628Sfabientstatic int 2330233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2331233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2332233628Sfabient{ 2333233628Sfabient (void)ctrspec; 2334233628Sfabient (void)pmc_config; 2335233628Sfabient 2336242622Sdim if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) 2337233628Sfabient return (-1); 2338233628Sfabient 2339233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2340233628Sfabient return (0); 2341233628Sfabient} 2342233628Sfabient 2343200928Srpaulo#if defined(__XSCALE__) 2344200928Srpaulo 2345200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2346200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2347200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2348200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2349200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2350200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2351200928Srpaulo EV_ALIAS(NULL, NULL) 2352200928Srpaulo}; 2353200928Srpaulostatic int 2354200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2355200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2356200928Srpaulo{ 2357200928Srpaulo switch (pe) { 2358200928Srpaulo default: 2359200928Srpaulo break; 2360200928Srpaulo } 2361200928Srpaulo 2362200928Srpaulo return (0); 2363200928Srpaulo} 2364200928Srpaulo#endif 2365200928Srpaulo 2366204635Sgnn#if defined(__mips__) 2367204635Sgnn 2368204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2369204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2370204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2371204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2372204635Sgnn EV_ALIAS(NULL, NULL) 2373204635Sgnn}; 2374204635Sgnn 2375233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2376233335Sgonzo EV_ALIAS("instructions", "RET"), 2377233335Sgonzo EV_ALIAS("branches", "BR"), 2378233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2379233335Sgonzo EV_ALIAS(NULL, NULL) 2380233335Sgonzo}; 2381233335Sgonzo 2382233320Sgonzo#define MIPS_KW_OS "os" 2383233320Sgonzo#define MIPS_KW_USR "usr" 2384233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2385204635Sgnn 2386204635Sgnnstatic int 2387233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2388204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2389204635Sgnn{ 2390204635Sgnn char *p; 2391204635Sgnn 2392204635Sgnn (void) pe; 2393204635Sgnn 2394204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2395204635Sgnn 2396204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2397233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2398204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2399233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2400204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2401233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2402204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2403204635Sgnn else 2404204635Sgnn return (-1); 2405204635Sgnn } 2406204635Sgnn 2407204635Sgnn return (0); 2408204635Sgnn} 2409233320Sgonzo 2410204635Sgnn#endif /* __mips__ */ 2411204635Sgnn 2412228869Sjhibbits#if defined(__powerpc__) 2413204635Sgnn 2414228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2415228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2416228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2417228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2418228869Sjhibbits EV_ALIAS(NULL, NULL) 2419228869Sjhibbits}; 2420228869Sjhibbits 2421261342Sjhibbitsstatic struct pmc_event_alias ppc970_aliases[] = { 2422261342Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2423261342Sjhibbits EV_ALIAS("cycles", "CYCLES"), 2424261342Sjhibbits EV_ALIAS(NULL, NULL) 2425261342Sjhibbits}; 2426228869Sjhibbits 2427261342Sjhibbits#define POWERPC_KW_OS "os" 2428261342Sjhibbits#define POWERPC_KW_USR "usr" 2429261342Sjhibbits#define POWERPC_KW_ANYTHREAD "anythread" 2430261342Sjhibbits 2431228869Sjhibbitsstatic int 2432261342Sjhibbitspowerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2433261342Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2434228869Sjhibbits{ 2435228869Sjhibbits char *p; 2436228869Sjhibbits 2437228869Sjhibbits (void) pe; 2438228869Sjhibbits 2439228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2440228869Sjhibbits 2441228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2442261342Sjhibbits if (KWMATCH(p, POWERPC_KW_OS)) 2443228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2444261342Sjhibbits else if (KWMATCH(p, POWERPC_KW_USR)) 2445228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2446261342Sjhibbits else if (KWMATCH(p, POWERPC_KW_ANYTHREAD)) 2447228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2448228869Sjhibbits else 2449228869Sjhibbits return (-1); 2450228869Sjhibbits } 2451228869Sjhibbits 2452228869Sjhibbits return (0); 2453228869Sjhibbits} 2454261342Sjhibbits 2455228869Sjhibbits#endif /* __powerpc__ */ 2456228869Sjhibbits 2457228869Sjhibbits 2458145256Sjkoshy/* 2459183725Sjkoshy * Match an event name `name' with its canonical form. 2460183725Sjkoshy * 2461185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2462185363Sjkoshy * hyphen characters are considered to match each other. 2463185363Sjkoshy * 2464183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2465183725Sjkoshy */ 2466183725Sjkoshy 2467183725Sjkoshystatic int 2468183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2469183725Sjkoshy{ 2470183725Sjkoshy int cc, nc; 2471183725Sjkoshy const unsigned char *c, *n; 2472183725Sjkoshy 2473183725Sjkoshy c = (const unsigned char *) canonicalname; 2474183725Sjkoshy n = (const unsigned char *) name; 2475183725Sjkoshy 2476183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2477183725Sjkoshy 2478185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2479185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2480183725Sjkoshy continue; 2481183725Sjkoshy 2482185363Sjkoshy if (toupper(nc) == toupper(cc)) 2483183725Sjkoshy continue; 2484183725Sjkoshy 2485185363Sjkoshy 2486183725Sjkoshy return (0); 2487183725Sjkoshy } 2488183725Sjkoshy 2489183725Sjkoshy if (*n == '\0' && *c == '\0') 2490183725Sjkoshy return (1); 2491183725Sjkoshy 2492183725Sjkoshy return (0); 2493183725Sjkoshy} 2494183725Sjkoshy 2495183725Sjkoshy/* 2496183725Sjkoshy * Match an event name against all the event named supported by a 2497183725Sjkoshy * PMC class. 2498183725Sjkoshy * 2499183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2500183725Sjkoshy */ 2501183725Sjkoshystatic const struct pmc_event_descr * 2502183725Sjkoshypmc_match_event_class(const char *name, 2503183725Sjkoshy const struct pmc_class_descr *pcd) 2504183725Sjkoshy{ 2505183725Sjkoshy size_t n; 2506183725Sjkoshy const struct pmc_event_descr *ev; 2507185363Sjkoshy 2508183725Sjkoshy ev = pcd->pm_evc_event_table; 2509183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2510183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2511183725Sjkoshy return (ev); 2512183725Sjkoshy 2513183725Sjkoshy return (NULL); 2514183725Sjkoshy} 2515183725Sjkoshy 2516183725Sjkoshystatic int 2517183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2518183725Sjkoshy{ 2519183725Sjkoshy size_t n; 2520183725Sjkoshy 2521183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2522183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2523183725Sjkoshy return (1); 2524183725Sjkoshy return (0); 2525183725Sjkoshy} 2526183725Sjkoshy 2527183725Sjkoshy/* 2528147191Sjkoshy * API entry points 2529145256Sjkoshy */ 2530145256Sjkoshy 2531147191Sjkoshyint 2532147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2533147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2534145256Sjkoshy{ 2535183725Sjkoshy size_t n; 2536147191Sjkoshy int retval; 2537147191Sjkoshy char *r, *spec_copy; 2538147191Sjkoshy const char *ctrname; 2539183725Sjkoshy const struct pmc_event_descr *ev; 2540183725Sjkoshy const struct pmc_event_alias *alias; 2541147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2542183725Sjkoshy const struct pmc_class_descr *pcd; 2543145256Sjkoshy 2544147191Sjkoshy spec_copy = NULL; 2545147191Sjkoshy retval = -1; 2546145256Sjkoshy 2547147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2548147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2549147191Sjkoshy errno = EINVAL; 2550147191Sjkoshy goto out; 2551147191Sjkoshy } 2552145256Sjkoshy 2553147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2554147191Sjkoshy if (pmc_mdep_event_aliases) 2555183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2556183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2557183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2558147191Sjkoshy break; 2559147191Sjkoshy } 2560145256Sjkoshy 2561147191Sjkoshy if (spec_copy == NULL) 2562147191Sjkoshy spec_copy = strdup(ctrspec); 2563145256Sjkoshy 2564147191Sjkoshy r = spec_copy; 2565147191Sjkoshy ctrname = strsep(&r, ","); 2566145256Sjkoshy 2567183725Sjkoshy /* 2568183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2569183725Sjkoshy * search for the event to the specified PMC class. 2570183725Sjkoshy */ 2571183725Sjkoshy ev = NULL; 2572185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2573185363Sjkoshy pcd = pmc_class_table[n]; 2574183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2575183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2576183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2577183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2578183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2579183725Sjkoshy errno = EINVAL; 2580183725Sjkoshy goto out; 2581183725Sjkoshy } 2582147191Sjkoshy break; 2583183725Sjkoshy } 2584183725Sjkoshy } 2585145256Sjkoshy 2586183725Sjkoshy /* 2587183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2588183725Sjkoshy * classes. 2589183725Sjkoshy */ 2590185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2591185363Sjkoshy pcd = pmc_class_table[n]; 2592183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2593183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2594183725Sjkoshy } 2595183725Sjkoshy 2596183725Sjkoshy if (ev == NULL) { 2597147191Sjkoshy errno = EINVAL; 2598147191Sjkoshy goto out; 2599147191Sjkoshy } 2600145256Sjkoshy 2601147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2602183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2603183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2604147191Sjkoshy pmc_config.pm_cpu = cpu; 2605147191Sjkoshy pmc_config.pm_mode = mode; 2606147191Sjkoshy pmc_config.pm_flags = flags; 2607145256Sjkoshy 2608147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2609147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2610145256Sjkoshy 2611183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2612147191Sjkoshy errno = EINVAL; 2613147191Sjkoshy goto out; 2614147191Sjkoshy } 2615145256Sjkoshy 2616147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2617147191Sjkoshy goto out; 2618145256Sjkoshy 2619147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2620145256Sjkoshy 2621147191Sjkoshy retval = 0; 2622145256Sjkoshy 2623147191Sjkoshy out: 2624147191Sjkoshy if (spec_copy) 2625147191Sjkoshy free(spec_copy); 2626145256Sjkoshy 2627174406Sjkoshy return (retval); 2628147191Sjkoshy} 2629145256Sjkoshy 2630147191Sjkoshyint 2631147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2632147191Sjkoshy{ 2633147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2634145256Sjkoshy 2635147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2636147191Sjkoshy pmc_attach_args.pm_pid = pid; 2637145256Sjkoshy 2638174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2639147191Sjkoshy} 2640145256Sjkoshy 2641147191Sjkoshyint 2642147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2643147191Sjkoshy{ 2644147191Sjkoshy unsigned int i; 2645147191Sjkoshy enum pmc_class cl; 2646145256Sjkoshy 2647147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2648147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2649147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2650147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2651174406Sjkoshy return (0); 2652147191Sjkoshy } 2653177107Sjkoshy errno = EINVAL; 2654177107Sjkoshy return (-1); 2655147191Sjkoshy} 2656145256Sjkoshy 2657147191Sjkoshyint 2658147191Sjkoshypmc_configure_logfile(int fd) 2659147191Sjkoshy{ 2660147191Sjkoshy struct pmc_op_configurelog cla; 2661145256Sjkoshy 2662147191Sjkoshy cla.pm_logfd = fd; 2663147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2664174406Sjkoshy return (-1); 2665174406Sjkoshy return (0); 2666147191Sjkoshy} 2667145256Sjkoshy 2668147191Sjkoshyint 2669147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2670147191Sjkoshy{ 2671147191Sjkoshy if (pmc_syscall == -1) { 2672147191Sjkoshy errno = ENXIO; 2673174406Sjkoshy return (-1); 2674147191Sjkoshy } 2675145256Sjkoshy 2676147219Sjkoshy *pci = &cpu_info; 2677174406Sjkoshy return (0); 2678147191Sjkoshy} 2679145256Sjkoshy 2680147191Sjkoshyint 2681147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2682147191Sjkoshy{ 2683147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2684145256Sjkoshy 2685147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2686147191Sjkoshy pmc_detach_args.pm_pid = pid; 2687174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2688147191Sjkoshy} 2689147191Sjkoshy 2690147191Sjkoshyint 2691147191Sjkoshypmc_disable(int cpu, int pmc) 2692145256Sjkoshy{ 2693147191Sjkoshy struct pmc_op_pmcadmin ssa; 2694145256Sjkoshy 2695147191Sjkoshy ssa.pm_cpu = cpu; 2696147191Sjkoshy ssa.pm_pmc = pmc; 2697147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2698174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2699147191Sjkoshy} 2700145256Sjkoshy 2701147191Sjkoshyint 2702147191Sjkoshypmc_enable(int cpu, int pmc) 2703147191Sjkoshy{ 2704147191Sjkoshy struct pmc_op_pmcadmin ssa; 2705145256Sjkoshy 2706147191Sjkoshy ssa.pm_cpu = cpu; 2707147191Sjkoshy ssa.pm_pmc = pmc; 2708147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2709174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2710147191Sjkoshy} 2711145256Sjkoshy 2712147191Sjkoshy/* 2713147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2714147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2715147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2716147191Sjkoshy * the number of event name pointers returned. 2717147191Sjkoshy * 2718147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2719147191Sjkoshy * is responsible for freeing this space when done. 2720147191Sjkoshy */ 2721147191Sjkoshyint 2722147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2723147191Sjkoshy int *nevents) 2724147191Sjkoshy{ 2725147191Sjkoshy int count; 2726147191Sjkoshy const char **names; 2727147191Sjkoshy const struct pmc_event_descr *ev; 2728147191Sjkoshy 2729147191Sjkoshy switch (cl) 2730147191Sjkoshy { 2731185363Sjkoshy case PMC_CLASS_IAF: 2732185363Sjkoshy ev = iaf_event_table; 2733185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2734185363Sjkoshy break; 2735185363Sjkoshy case PMC_CLASS_IAP: 2736185363Sjkoshy /* 2737185363Sjkoshy * Return the most appropriate set of event name 2738185363Sjkoshy * spellings for the current CPU. 2739185363Sjkoshy */ 2740185363Sjkoshy switch (cpu_info.pm_cputype) { 2741185363Sjkoshy default: 2742185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2743185363Sjkoshy ev = atom_event_table; 2744185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2745185363Sjkoshy break; 2746263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 2747263446Shiren ev = atom_silvermont_event_table; 2748263446Shiren count = PMC_EVENT_TABLE_SIZE(atom_silvermont); 2749263446Shiren break; 2750185363Sjkoshy case PMC_CPU_INTEL_CORE: 2751185363Sjkoshy ev = core_event_table; 2752185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2753185363Sjkoshy break; 2754185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2755185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2756185363Sjkoshy ev = core2_event_table; 2757185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2758185363Sjkoshy break; 2759187761Sjeff case PMC_CPU_INTEL_COREI7: 2760187761Sjeff ev = corei7_event_table; 2761187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2762187761Sjeff break; 2763248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2764248842Ssbruno ev = haswell_event_table; 2765248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswell); 2766248842Ssbruno break; 2767240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2768240164Sfabient ev = ivybridge_event_table; 2769240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2770240164Sfabient break; 2771246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 2772246166Ssbruno ev = ivybridge_xeon_event_table; 2773246166Ssbruno count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 2774246166Ssbruno break; 2775232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2776232366Sdavide ev = sandybridge_event_table; 2777232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2778232366Sdavide break; 2779241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2780241738Ssbruno ev = sandybridge_xeon_event_table; 2781241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2782241738Ssbruno break; 2783206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2784206089Sfabient ev = westmere_event_table; 2785206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2786206089Sfabient break; 2787185363Sjkoshy } 2788185363Sjkoshy break; 2789206089Sfabient case PMC_CLASS_UCF: 2790206089Sfabient ev = ucf_event_table; 2791206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2792206089Sfabient break; 2793206089Sfabient case PMC_CLASS_UCP: 2794206089Sfabient /* 2795206089Sfabient * Return the most appropriate set of event name 2796206089Sfabient * spellings for the current CPU. 2797206089Sfabient */ 2798206089Sfabient switch (cpu_info.pm_cputype) { 2799206089Sfabient default: 2800206089Sfabient case PMC_CPU_INTEL_COREI7: 2801206089Sfabient ev = corei7uc_event_table; 2802206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2803206089Sfabient break; 2804248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2805248842Ssbruno ev = haswelluc_event_table; 2806248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswelluc); 2807248842Ssbruno break; 2808232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2809232366Sdavide ev = sandybridgeuc_event_table; 2810232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2811232366Sdavide break; 2812206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2813206089Sfabient ev = westmereuc_event_table; 2814206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2815206089Sfabient break; 2816206089Sfabient } 2817206089Sfabient break; 2818147191Sjkoshy case PMC_CLASS_TSC: 2819183725Sjkoshy ev = tsc_event_table; 2820183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2821145256Sjkoshy break; 2822147191Sjkoshy case PMC_CLASS_K7: 2823183725Sjkoshy ev = k7_event_table; 2824183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2825145256Sjkoshy break; 2826147191Sjkoshy case PMC_CLASS_K8: 2827183725Sjkoshy ev = k8_event_table; 2828183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2829145256Sjkoshy break; 2830183725Sjkoshy case PMC_CLASS_P4: 2831183725Sjkoshy ev = p4_event_table; 2832183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2833183725Sjkoshy break; 2834147191Sjkoshy case PMC_CLASS_P5: 2835183725Sjkoshy ev = p5_event_table; 2836183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2837145256Sjkoshy break; 2838147191Sjkoshy case PMC_CLASS_P6: 2839183725Sjkoshy ev = p6_event_table; 2840183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2841145256Sjkoshy break; 2842200928Srpaulo case PMC_CLASS_XSCALE: 2843200928Srpaulo ev = xscale_event_table; 2844200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2845200928Srpaulo break; 2846204635Sgnn case PMC_CLASS_MIPS24K: 2847204635Sgnn ev = mips24k_event_table; 2848204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2849204635Sgnn break; 2850233335Sgonzo case PMC_CLASS_OCTEON: 2851233335Sgonzo ev = octeon_event_table; 2852233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2853233335Sgonzo break; 2854228869Sjhibbits case PMC_CLASS_PPC7450: 2855228869Sjhibbits ev = ppc7450_event_table; 2856228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2857228869Sjhibbits break; 2858261342Sjhibbits case PMC_CLASS_PPC970: 2859261342Sjhibbits ev = ppc970_event_table; 2860261342Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc970); 2861261342Sjhibbits break; 2862233628Sfabient case PMC_CLASS_SOFT: 2863233628Sfabient ev = soft_event_table; 2864233628Sfabient count = soft_event_info.pm_nevent; 2865233628Sfabient break; 2866145256Sjkoshy default: 2867147191Sjkoshy errno = EINVAL; 2868174406Sjkoshy return (-1); 2869145256Sjkoshy } 2870145256Sjkoshy 2871147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2872174406Sjkoshy return (-1); 2873145256Sjkoshy 2874147191Sjkoshy *eventnames = names; 2875147191Sjkoshy *nevents = count; 2876145256Sjkoshy 2877147191Sjkoshy for (;count--; ev++, names++) 2878147191Sjkoshy *names = ev->pm_ev_name; 2879233628Sfabient 2880174406Sjkoshy return (0); 2881147191Sjkoshy} 2882145256Sjkoshy 2883147191Sjkoshyint 2884147191Sjkoshypmc_flush_logfile(void) 2885147191Sjkoshy{ 2886174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2887147191Sjkoshy} 2888145256Sjkoshy 2889147191Sjkoshyint 2890226514Sfabientpmc_close_logfile(void) 2891226514Sfabient{ 2892226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2893226514Sfabient} 2894226514Sfabient 2895226514Sfabientint 2896147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2897147191Sjkoshy{ 2898147191Sjkoshy struct pmc_op_getdriverstats gms; 2899145256Sjkoshy 2900147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2901174406Sjkoshy return (-1); 2902145256Sjkoshy 2903147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2904147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2905147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2906147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2907147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2908147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2909147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2910147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2911147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2912174406Sjkoshy return (0); 2913147191Sjkoshy} 2914145256Sjkoshy 2915147191Sjkoshyint 2916147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2917147191Sjkoshy{ 2918147191Sjkoshy struct pmc_op_getmsr gm; 2919147191Sjkoshy 2920147191Sjkoshy gm.pm_pmcid = pmc; 2921147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2922174406Sjkoshy return (-1); 2923147191Sjkoshy *msr = gm.pm_msr; 2924174406Sjkoshy return (0); 2925145256Sjkoshy} 2926145256Sjkoshy 2927145256Sjkoshyint 2928145256Sjkoshypmc_init(void) 2929145256Sjkoshy{ 2930145256Sjkoshy int error, pmc_mod_id; 2931147219Sjkoshy unsigned int n; 2932145256Sjkoshy uint32_t abi_version; 2933145256Sjkoshy struct module_stat pmc_modstat; 2934147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2935198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2936198433Sjkoshy int cpu_has_iaf_counters; 2937198433Sjkoshy unsigned int t; 2938198433Sjkoshy#endif 2939145256Sjkoshy 2940145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2941174406Sjkoshy return (0); 2942145256Sjkoshy 2943145256Sjkoshy /* retrieve the system call number from the KLD */ 2944145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2945174406Sjkoshy return (-1); 2946145256Sjkoshy 2947145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2948145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2949174406Sjkoshy return (-1); 2950145256Sjkoshy 2951145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2952145256Sjkoshy 2953147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2954147191Sjkoshy abi_version = PMC_VERSION; 2955145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2956145256Sjkoshy return (pmc_syscall = -1); 2957145256Sjkoshy 2958147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2959147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2960145256Sjkoshy errno = EPROGMISMATCH; 2961145256Sjkoshy return (pmc_syscall = -1); 2962145256Sjkoshy } 2963145256Sjkoshy 2964147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2965145256Sjkoshy return (pmc_syscall = -1); 2966145256Sjkoshy 2967147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2968147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2969147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2970147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2971147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2972147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2973147219Sjkoshy 2974185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2975185363Sjkoshy sizeof(struct pmc_class_descr *)); 2976185363Sjkoshy 2977185363Sjkoshy if (pmc_class_table == NULL) 2978185363Sjkoshy return (-1); 2979185363Sjkoshy 2980198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2981198433Sjkoshy pmc_class_table[n] = NULL; 2982185363Sjkoshy 2983185363Sjkoshy /* 2984233628Sfabient * Get soft events list. 2985233628Sfabient */ 2986233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 2987233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 2988233628Sfabient return (pmc_syscall = -1); 2989233628Sfabient 2990233628Sfabient /* Map soft events to static list. */ 2991233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 2992233628Sfabient soft_event_table[n].pm_ev_name = 2993233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 2994233628Sfabient soft_event_table[n].pm_ev_code = 2995233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 2996233628Sfabient } 2997233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 2998233628Sfabient soft_event_info.pm_nevent; 2999233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 3000233628Sfabient soft_event_table; 3001233628Sfabient 3002233628Sfabient /* 3003185363Sjkoshy * Fill in the class table. 3004185363Sjkoshy */ 3005185363Sjkoshy n = 0; 3006233628Sfabient 3007233628Sfabient /* Fill soft events information. */ 3008233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 3009185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 3010233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 3011233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 3012198433Sjkoshy 3013198433Sjkoshy /* 3014198433Sjkoshy * Check if this CPU has fixed function counters. 3015198433Sjkoshy */ 3016198433Sjkoshy cpu_has_iaf_counters = 0; 3017198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 3018212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 3019212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 3020198433Sjkoshy cpu_has_iaf_counters = 1; 3021185363Sjkoshy#endif 3022185363Sjkoshy 3023183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 3024183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 3025183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 3026183725Sjkoshy pmc_mdep_class_list_size = \ 3027183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 3028183725Sjkoshy } while (0) 3029183725Sjkoshy 3030198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 3031198433Sjkoshy PMC_MDEP_INIT(C); \ 3032212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 3033212224Sfabient if (!cpu_has_iaf_counters) \ 3034198433Sjkoshy pmc_mdep_event_aliases = \ 3035198433Sjkoshy C##_aliases_without_iaf; \ 3036198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 3037198433Sjkoshy } while (0) 3038198433Sjkoshy 3039183725Sjkoshy /* Configure the event name parser. */ 3040145256Sjkoshy switch (cpu_info.pm_cputype) { 3041145340Smarcel#if defined(__i386__) 3042145256Sjkoshy case PMC_CPU_AMD_K7: 3043183725Sjkoshy PMC_MDEP_INIT(k7); 3044185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 3045145256Sjkoshy break; 3046145256Sjkoshy case PMC_CPU_INTEL_P5: 3047183725Sjkoshy PMC_MDEP_INIT(p5); 3048185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 3049145256Sjkoshy break; 3050145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 3051145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 3052145256Sjkoshy case PMC_CPU_INTEL_PIII: 3053145256Sjkoshy case PMC_CPU_INTEL_PM: 3054183725Sjkoshy PMC_MDEP_INIT(p6); 3055185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 3056145256Sjkoshy break; 3057147759Sjkoshy#endif 3058147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 3059183725Sjkoshy case PMC_CPU_AMD_K8: 3060183725Sjkoshy PMC_MDEP_INIT(k8); 3061185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 3062183725Sjkoshy break; 3063185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3064198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 3065185363Sjkoshy break; 3066263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3067263446Shiren PMC_MDEP_INIT_INTEL_V2(atom_silvermont); 3068263446Shiren break; 3069185363Sjkoshy case PMC_CPU_INTEL_CORE: 3070185363Sjkoshy PMC_MDEP_INIT(core); 3071202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 3072185363Sjkoshy break; 3073185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3074185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3075198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 3076185363Sjkoshy break; 3077187761Sjeff case PMC_CPU_INTEL_COREI7: 3078206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3079206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 3080198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 3081187761Sjeff break; 3082248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3083248842Ssbruno pmc_class_table[n++] = &ucf_class_table_descr; 3084248842Ssbruno pmc_class_table[n++] = &haswelluc_class_table_descr; 3085248842Ssbruno PMC_MDEP_INIT_INTEL_V2(haswell); 3086248842Ssbruno break; 3087240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3088240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 3089240164Sfabient break; 3090246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3091246166Ssbruno PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); 3092246166Ssbruno break; 3093232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3094232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 3095232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 3096232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 3097232366Sdavide break; 3098241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3099241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 3100241738Ssbruno break; 3101206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3102206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3103206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 3104206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 3105206089Sfabient break; 3106145256Sjkoshy case PMC_CPU_INTEL_PIV: 3107183725Sjkoshy PMC_MDEP_INIT(p4); 3108185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3109145256Sjkoshy break; 3110145256Sjkoshy#endif 3111233628Sfabient case PMC_CPU_GENERIC: 3112233628Sfabient PMC_MDEP_INIT(generic); 3113233628Sfabient break; 3114200928Srpaulo#if defined(__XSCALE__) 3115200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3116200928Srpaulo PMC_MDEP_INIT(xscale); 3117200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3118200928Srpaulo break; 3119200928Srpaulo#endif 3120204635Sgnn#if defined(__mips__) 3121204635Sgnn case PMC_CPU_MIPS_24K: 3122204635Sgnn PMC_MDEP_INIT(mips24k); 3123204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3124204635Sgnn break; 3125233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3126233335Sgonzo PMC_MDEP_INIT(octeon); 3127233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3128233335Sgonzo break; 3129204635Sgnn#endif /* __mips__ */ 3130228869Sjhibbits#if defined(__powerpc__) 3131228869Sjhibbits case PMC_CPU_PPC_7450: 3132228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3133228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3134228869Sjhibbits break; 3135261342Sjhibbits case PMC_CPU_PPC_970: 3136261342Sjhibbits PMC_MDEP_INIT(ppc970); 3137261342Sjhibbits pmc_class_table[n] = &ppc970_class_table_descr; 3138261342Sjhibbits break; 3139228869Sjhibbits#endif 3140145256Sjkoshy default: 3141145256Sjkoshy /* 3142145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3143145256Sjkoshy * about. This shouldn't happen since the abi version check 3144145256Sjkoshy * should have caught this. 3145145256Sjkoshy */ 3146145256Sjkoshy errno = ENXIO; 3147145256Sjkoshy return (pmc_syscall = -1); 3148145256Sjkoshy } 3149145256Sjkoshy 3150174406Sjkoshy return (0); 3151145256Sjkoshy} 3152145256Sjkoshy 3153147191Sjkoshyconst char * 3154147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3155145256Sjkoshy{ 3156147191Sjkoshy int i; 3157145256Sjkoshy 3158147191Sjkoshy /* 3159147191Sjkoshy * 'cap' should have a single bit set and should be in 3160147191Sjkoshy * range. 3161147191Sjkoshy */ 3162147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3163147191Sjkoshy cap > PMC_CAP_LAST) { 3164145256Sjkoshy errno = EINVAL; 3165174406Sjkoshy return (NULL); 3166145256Sjkoshy } 3167145256Sjkoshy 3168147191Sjkoshy i = ffs(cap); 3169174406Sjkoshy return (pmc_capability_names[i - 1]); 3170147191Sjkoshy} 3171145256Sjkoshy 3172147191Sjkoshyconst char * 3173147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3174147191Sjkoshy{ 3175147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3176147191Sjkoshy pc <= PMC_CLASS_LAST) 3177174406Sjkoshy return (pmc_class_names[pc]); 3178145256Sjkoshy 3179147191Sjkoshy errno = EINVAL; 3180174406Sjkoshy return (NULL); 3181147191Sjkoshy} 3182145256Sjkoshy 3183147191Sjkoshyconst char * 3184147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3185147191Sjkoshy{ 3186183725Sjkoshy size_t n; 3187183725Sjkoshy 3188183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3189183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3190183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3191183725Sjkoshy 3192147191Sjkoshy errno = EINVAL; 3193174406Sjkoshy return (NULL); 3194147191Sjkoshy} 3195145256Sjkoshy 3196147191Sjkoshyconst char * 3197147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3198147191Sjkoshy{ 3199147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3200147191Sjkoshy pd <= PMC_DISP_LAST) 3201174406Sjkoshy return (pmc_disposition_names[pd]); 3202145256Sjkoshy 3203147191Sjkoshy errno = EINVAL; 3204174406Sjkoshy return (NULL); 3205147191Sjkoshy} 3206145256Sjkoshy 3207147191Sjkoshyconst char * 3208185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3209147191Sjkoshy{ 3210183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3211145256Sjkoshy 3212183725Sjkoshy ev = evfence = NULL; 3213185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3214185363Sjkoshy ev = iaf_event_table; 3215185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3216185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3217185363Sjkoshy switch (cpu) { 3218185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3219185363Sjkoshy ev = atom_event_table; 3220185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3221185363Sjkoshy break; 3222263446Shiren case PMC_CPU_INTEL_ATOM_SILVERMONT: 3223263446Shiren ev = atom_silvermont_event_table; 3224263446Shiren evfence = atom_silvermont_event_table + 3225263446Shiren PMC_EVENT_TABLE_SIZE(atom_silvermont); 3226263446Shiren break; 3227185363Sjkoshy case PMC_CPU_INTEL_CORE: 3228185363Sjkoshy ev = core_event_table; 3229185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3230185363Sjkoshy break; 3231185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3232185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3233185363Sjkoshy ev = core2_event_table; 3234185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3235185363Sjkoshy break; 3236187761Sjeff case PMC_CPU_INTEL_COREI7: 3237187761Sjeff ev = corei7_event_table; 3238187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3239187761Sjeff break; 3240248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3241248842Ssbruno ev = haswell_event_table; 3242248842Ssbruno evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell); 3243248842Ssbruno break; 3244240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3245240164Sfabient ev = ivybridge_event_table; 3246240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3247240164Sfabient break; 3248246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3249246166Ssbruno ev = ivybridge_xeon_event_table; 3250246166Ssbruno evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 3251246166Ssbruno break; 3252232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3253232366Sdavide ev = sandybridge_event_table; 3254232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3255232366Sdavide break; 3256241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3257241738Ssbruno ev = sandybridge_xeon_event_table; 3258241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3259241738Ssbruno break; 3260206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3261206089Sfabient ev = westmere_event_table; 3262206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3263206089Sfabient break; 3264185363Sjkoshy default: /* Unknown CPU type. */ 3265185363Sjkoshy break; 3266185363Sjkoshy } 3267206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3268206089Sfabient ev = ucf_event_table; 3269206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3270206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3271206089Sfabient switch (cpu) { 3272206089Sfabient case PMC_CPU_INTEL_COREI7: 3273206089Sfabient ev = corei7uc_event_table; 3274206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3275206089Sfabient break; 3276232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3277232366Sdavide ev = sandybridgeuc_event_table; 3278232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3279232366Sdavide break; 3280206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3281206089Sfabient ev = westmereuc_event_table; 3282206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3283206089Sfabient break; 3284206089Sfabient default: /* Unknown CPU type. */ 3285206089Sfabient break; 3286206089Sfabient } 3287206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3288183725Sjkoshy ev = k7_event_table; 3289183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3290183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3291183725Sjkoshy ev = k8_event_table; 3292183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3293183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3294183725Sjkoshy ev = p4_event_table; 3295183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3296183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3297183725Sjkoshy ev = p5_event_table; 3298183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3299183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3300183725Sjkoshy ev = p6_event_table; 3301183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3302200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3303200928Srpaulo ev = xscale_event_table; 3304200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3305204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3306204635Sgnn ev = mips24k_event_table; 3307233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3308233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3309233335Sgonzo ev = octeon_event_table; 3310233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3311228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3312228869Sjhibbits ev = ppc7450_event_table; 3313233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3314261342Sjhibbits } else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) { 3315261342Sjhibbits ev = ppc970_event_table; 3316261342Sjhibbits evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970); 3317183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3318183725Sjkoshy ev = tsc_event_table; 3319183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3320242622Sdim } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { 3321233628Sfabient ev = soft_event_table; 3322233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3323183725Sjkoshy } 3324183725Sjkoshy 3325183725Sjkoshy for (; ev != evfence; ev++) 3326183725Sjkoshy if (pe == ev->pm_ev_code) 3327183725Sjkoshy return (ev->pm_ev_name); 3328183725Sjkoshy 3329185363Sjkoshy return (NULL); 3330185363Sjkoshy} 3331185363Sjkoshy 3332185363Sjkoshyconst char * 3333185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3334185363Sjkoshy{ 3335185363Sjkoshy const char *n; 3336185363Sjkoshy 3337185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3338185363Sjkoshy return (n); 3339185363Sjkoshy 3340147191Sjkoshy errno = EINVAL; 3341174406Sjkoshy return (NULL); 3342147191Sjkoshy} 3343145256Sjkoshy 3344147191Sjkoshyconst char * 3345147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3346147191Sjkoshy{ 3347147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3348147191Sjkoshy pm <= PMC_MODE_LAST) 3349174406Sjkoshy return (pmc_mode_names[pm]); 3350145256Sjkoshy 3351147191Sjkoshy errno = EINVAL; 3352174406Sjkoshy return (NULL); 3353147191Sjkoshy} 3354145256Sjkoshy 3355147191Sjkoshyconst char * 3356147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3357147191Sjkoshy{ 3358147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3359147191Sjkoshy ps <= PMC_STATE_LAST) 3360174406Sjkoshy return (pmc_state_names[ps]); 3361145256Sjkoshy 3362147191Sjkoshy errno = EINVAL; 3363174406Sjkoshy return (NULL); 3364145256Sjkoshy} 3365145256Sjkoshy 3366145256Sjkoshyint 3367147191Sjkoshypmc_ncpu(void) 3368145256Sjkoshy{ 3369147191Sjkoshy if (pmc_syscall == -1) { 3370147191Sjkoshy errno = ENXIO; 3371174406Sjkoshy return (-1); 3372147191Sjkoshy } 3373145256Sjkoshy 3374174406Sjkoshy return (cpu_info.pm_ncpu); 3375145256Sjkoshy} 3376145256Sjkoshy 3377145256Sjkoshyint 3378147191Sjkoshypmc_npmc(int cpu) 3379145256Sjkoshy{ 3380147191Sjkoshy if (pmc_syscall == -1) { 3381147191Sjkoshy errno = ENXIO; 3382174406Sjkoshy return (-1); 3383147191Sjkoshy } 3384145256Sjkoshy 3385147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3386147191Sjkoshy errno = EINVAL; 3387174406Sjkoshy return (-1); 3388147191Sjkoshy } 3389145256Sjkoshy 3390174406Sjkoshy return (cpu_info.pm_npmc); 3391145256Sjkoshy} 3392145256Sjkoshy 3393145256Sjkoshyint 3394147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3395145256Sjkoshy{ 3396147191Sjkoshy int nbytes, npmc; 3397147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3398145256Sjkoshy 3399147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3400174406Sjkoshy return (-1); 3401145256Sjkoshy 3402147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3403147191Sjkoshy npmc * sizeof(struct pmc_info); 3404145256Sjkoshy 3405147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3406174406Sjkoshy return (-1); 3407145256Sjkoshy 3408147191Sjkoshy pmci->pm_cpu = cpu; 3409145256Sjkoshy 3410147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3411147191Sjkoshy free(pmci); 3412174406Sjkoshy return (-1); 3413147191Sjkoshy } 3414145256Sjkoshy 3415147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3416147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3417174406Sjkoshy return (0); 3418145256Sjkoshy} 3419145256Sjkoshy 3420145256Sjkoshyint 3421145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3422145256Sjkoshy{ 3423145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3424145256Sjkoshy 3425145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3426145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3427145256Sjkoshy pmc_read_op.pm_value = -1; 3428145256Sjkoshy 3429145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3430174406Sjkoshy return (-1); 3431145256Sjkoshy 3432145256Sjkoshy *value = pmc_read_op.pm_value; 3433174406Sjkoshy return (0); 3434145256Sjkoshy} 3435145256Sjkoshy 3436145256Sjkoshyint 3437147191Sjkoshypmc_release(pmc_id_t pmc) 3438145256Sjkoshy{ 3439147191Sjkoshy struct pmc_op_simple pmc_release_args; 3440145256Sjkoshy 3441147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3442174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3443145256Sjkoshy} 3444145256Sjkoshy 3445145256Sjkoshyint 3446145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3447145256Sjkoshy{ 3448145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3449145256Sjkoshy 3450145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3451145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3452145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3453145256Sjkoshy 3454145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3455174406Sjkoshy return (-1); 3456145256Sjkoshy 3457145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3458174406Sjkoshy return (0); 3459145256Sjkoshy} 3460145256Sjkoshy 3461145256Sjkoshyint 3462145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3463145256Sjkoshy{ 3464145256Sjkoshy struct pmc_op_pmcsetcount sc; 3465145256Sjkoshy 3466145256Sjkoshy sc.pm_pmcid = pmc; 3467145256Sjkoshy sc.pm_count = value; 3468145256Sjkoshy 3469145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3470174406Sjkoshy return (-1); 3471174406Sjkoshy return (0); 3472145256Sjkoshy} 3473145256Sjkoshy 3474145256Sjkoshyint 3475147191Sjkoshypmc_start(pmc_id_t pmc) 3476145256Sjkoshy{ 3477147191Sjkoshy struct pmc_op_simple pmc_start_args; 3478145256Sjkoshy 3479147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3480174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3481145256Sjkoshy} 3482145256Sjkoshy 3483145256Sjkoshyint 3484147191Sjkoshypmc_stop(pmc_id_t pmc) 3485145256Sjkoshy{ 3486147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3487145256Sjkoshy 3488147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3489174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3490145256Sjkoshy} 3491145256Sjkoshy 3492145256Sjkoshyint 3493145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3494145774Sjkoshy{ 3495145774Sjkoshy unsigned int i; 3496145774Sjkoshy enum pmc_class cl; 3497145774Sjkoshy 3498145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3499145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3500145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3501145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3502174406Sjkoshy return (0); 3503145774Sjkoshy } 3504177107Sjkoshy errno = EINVAL; 3505177107Sjkoshy return (-1); 3506145774Sjkoshy} 3507145774Sjkoshy 3508145774Sjkoshyint 3509147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3510145774Sjkoshy{ 3511147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3512145774Sjkoshy 3513147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3514147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3515147191Sjkoshy pmc_write_op.pm_value = value; 3516174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3517145256Sjkoshy} 3518145256Sjkoshy 3519145256Sjkoshyint 3520147191Sjkoshypmc_writelog(uint32_t userdata) 3521145256Sjkoshy{ 3522147191Sjkoshy struct pmc_op_writelog wl; 3523145256Sjkoshy 3524147191Sjkoshy wl.pm_userdata = userdata; 3525174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3526145256Sjkoshy} 3527