libpmc.c revision 248842
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 248842 2013-03-28 19:15:54Z sbruno $"); 29145256Sjkoshy 30145256Sjkoshy#include <sys/types.h> 31145256Sjkoshy#include <sys/module.h> 32145256Sjkoshy#include <sys/pmc.h> 33145256Sjkoshy#include <sys/syscall.h> 34145256Sjkoshy 35145256Sjkoshy#include <ctype.h> 36145256Sjkoshy#include <errno.h> 37145256Sjkoshy#include <fcntl.h> 38145256Sjkoshy#include <pmc.h> 39145256Sjkoshy#include <stdio.h> 40145256Sjkoshy#include <stdlib.h> 41145256Sjkoshy#include <string.h> 42145256Sjkoshy#include <strings.h> 43145256Sjkoshy#include <unistd.h> 44145256Sjkoshy 45185363Sjkoshy#include "libpmcinternal.h" 46185363Sjkoshy 47145256Sjkoshy/* Function prototypes */ 48145340Smarcel#if defined(__i386__) 49145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 50145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 51147191Sjkoshy#endif 52147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 53185363Sjkoshystatic int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 54185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 55185363Sjkoshystatic int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 56185363Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 57206089Sfabientstatic int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 58206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 59206089Sfabientstatic int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 60206089Sfabient struct pmc_op_pmcallocate *_pmc_config); 61147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 62145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 63147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 64147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 65147191Sjkoshy#endif 66147191Sjkoshy#if defined(__i386__) 67145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 68145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 69147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 70145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 71145256Sjkoshy#endif 72183725Sjkoshy#if defined(__amd64__) || defined(__i386__) 73183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 74183725Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 75183725Sjkoshy#endif 76200928Srpaulo#if defined(__XSCALE__) 77200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 78200928Srpaulo struct pmc_op_pmcallocate *_pmc_config); 79200928Srpaulo#endif 80204635Sgnn#if defined(__mips__) 81233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, 82204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 83204635Sgnn#endif /* __mips__ */ 84233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 85233628Sfabient struct pmc_op_pmcallocate *_pmc_config); 86204635Sgnn 87228869Sjhibbits#if defined(__powerpc__) 88228869Sjhibbitsstatic int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec, 89228869Sjhibbits struct pmc_op_pmcallocate *_pmc_config); 90228869Sjhibbits#endif /* __powerpc__ */ 91204635Sgnn 92145256Sjkoshy#define PMC_CALL(cmd, params) \ 93145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 94145256Sjkoshy 95145256Sjkoshy/* 96145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 97145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 98145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 99145256Sjkoshy * lookup table. 100145256Sjkoshy */ 101145256Sjkoshystruct pmc_event_alias { 102145256Sjkoshy const char *pm_alias; 103145256Sjkoshy const char *pm_spec; 104145256Sjkoshy}; 105145256Sjkoshy 106145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 107145256Sjkoshy 108145256Sjkoshy/* 109183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 110145256Sjkoshy * to integer codes used by the PMC KLD. 111145256Sjkoshy */ 112145256Sjkoshystruct pmc_event_descr { 113145256Sjkoshy const char *pm_ev_name; 114145256Sjkoshy enum pmc_event pm_ev_code; 115145256Sjkoshy}; 116145256Sjkoshy 117183725Sjkoshy/* 118183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 119183725Sjkoshy * event names to event tables and other PMC class data. 120183725Sjkoshy */ 121183725Sjkoshystruct pmc_class_descr { 122183725Sjkoshy const char *pm_evc_name; 123183725Sjkoshy size_t pm_evc_name_size; 124183725Sjkoshy enum pmc_class pm_evc_class; 125183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 126183725Sjkoshy size_t pm_evc_event_table_size; 127183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 128183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 129183725Sjkoshy}; 130183725Sjkoshy 131183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 132183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 133183725Sjkoshy 134183725Sjkoshy#undef __PMC_EV 135183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 136183725Sjkoshy 137183725Sjkoshy/* 138185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 139183725Sjkoshy * 140185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 141183725Sjkoshy */ 142185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 143183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 144183725Sjkoshy { \ 145183725Sjkoshy __PMC_EV_##C() \ 146185363Sjkoshy } 147185363Sjkoshy 148185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 149185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 150185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 151185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 152185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 153185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 154200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 155204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 156233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON); 157206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 158228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450); 159185363Sjkoshy 160233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT]; 161233628Sfabient 162185363Sjkoshy#undef __PMC_EV_ALIAS 163185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 164185363Sjkoshy 165185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 166185363Sjkoshy{ 167185363Sjkoshy __PMC_EV_ALIAS_ATOM() 168185363Sjkoshy}; 169185363Sjkoshy 170185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 171185363Sjkoshy{ 172185363Sjkoshy __PMC_EV_ALIAS_CORE() 173185363Sjkoshy}; 174185363Sjkoshy 175185363Sjkoshy 176185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 177185363Sjkoshy{ 178185363Sjkoshy __PMC_EV_ALIAS_CORE2() 179185363Sjkoshy}; 180185363Sjkoshy 181187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 182187761Sjeff{ 183187761Sjeff __PMC_EV_ALIAS_COREI7() 184187761Sjeff}; 185187761Sjeff 186248842Ssbrunostatic const struct pmc_event_descr haswell_event_table[] = 187248842Ssbruno{ 188248842Ssbruno __PMC_EV_ALIAS_HASWELL() 189248842Ssbruno}; 190248842Ssbruno 191240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] = 192240164Sfabient{ 193240164Sfabient __PMC_EV_ALIAS_IVYBRIDGE() 194240164Sfabient}; 195240164Sfabient 196246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] = 197246166Ssbruno{ 198246166Ssbruno __PMC_EV_ALIAS_IVYBRIDGE_XEON() 199246166Ssbruno}; 200246166Ssbruno 201232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] = 202232366Sdavide{ 203232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGE() 204232366Sdavide}; 205232366Sdavide 206241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] = 207241738Ssbruno{ 208241738Ssbruno __PMC_EV_ALIAS_SANDYBRIDGE_XEON() 209241738Ssbruno}; 210241738Ssbruno 211206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 212206089Sfabient{ 213206089Sfabient __PMC_EV_ALIAS_WESTMERE() 214206089Sfabient}; 215206089Sfabient 216206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 217206089Sfabient{ 218206089Sfabient __PMC_EV_ALIAS_COREI7UC() 219206089Sfabient}; 220206089Sfabient 221248842Ssbrunostatic const struct pmc_event_descr haswelluc_event_table[] = 222248842Ssbruno{ 223248842Ssbruno __PMC_EV_ALIAS_HASWELLUC() 224248842Ssbruno}; 225248842Ssbruno 226232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] = 227232366Sdavide{ 228232366Sdavide __PMC_EV_ALIAS_SANDYBRIDGEUC() 229232366Sdavide}; 230232366Sdavide 231206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 232206089Sfabient{ 233206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 234206089Sfabient}; 235206089Sfabient 236185363Sjkoshy/* 237185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 238185363Sjkoshy * 239185363Sjkoshy * Map a CPU to the PMC classes it supports. 240185363Sjkoshy */ 241185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 242183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 243183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 244183725Sjkoshy } 245183725Sjkoshy 246233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 247233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC); 248233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 249233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 250248842SsbrunoPMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 251240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 252246166SsbrunoPMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 253233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 254241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC); 255233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 256233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC); 257233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); 258233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC); 259233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC); 260233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC); 261233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); 262233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); 263233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); 264233628SfabientPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450); 265233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT); 266183725Sjkoshy 267183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 268145256Sjkoshy{ 269183725Sjkoshy __PMC_EV_TSC() 270145256Sjkoshy}; 271145256Sjkoshy 272183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 273185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 274185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 275185363Sjkoshy { \ 276185363Sjkoshy .pm_evc_name = #CLASS "-", \ 277185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 278185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 279185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 280183725Sjkoshy .pm_evc_event_table_size = \ 281185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 282185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 283183725Sjkoshy } 284183725Sjkoshy 285185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 286185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 287185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 288185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 289185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 290187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 291248842SsbrunoPMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap); 292240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap); 293246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap); 294232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap); 295241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap); 296206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 297206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 298206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 299248842SsbrunoPMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp); 300232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp); 301206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 302185363Sjkoshy#endif 303183725Sjkoshy#if defined(__i386__) 304185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 305183725Sjkoshy#endif 306183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 307185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 308185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 309183725Sjkoshy#endif 310183725Sjkoshy#if defined(__i386__) 311185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 312185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 313183725Sjkoshy#endif 314183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 315185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 316183725Sjkoshy#endif 317200928Srpaulo#if defined(__XSCALE__) 318200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 319200928Srpaulo#endif 320204635Sgnn#if defined(__mips__) 321233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips); 322233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips); 323204635Sgnn#endif /* __mips__ */ 324228869Sjhibbits#if defined(__powerpc__) 325228869SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450); 326228869Sjhibbits#endif 327228869Sjhibbits 328233628Sfabientstatic struct pmc_class_descr soft_class_table_descr = 329233628Sfabient{ 330233628Sfabient .pm_evc_name = "SOFT-", 331233628Sfabient .pm_evc_name_size = sizeof("SOFT-") - 1, 332233628Sfabient .pm_evc_class = PMC_CLASS_SOFT, 333233628Sfabient .pm_evc_event_table = NULL, 334233628Sfabient .pm_evc_event_table_size = 0, 335233628Sfabient .pm_evc_allocate_pmc = soft_allocate_pmc 336233628Sfabient}; 337233628Sfabient 338183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 339183725Sjkoshy 340185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 341185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 342185363Sjkoshy 343183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 344183725Sjkoshystatic size_t pmc_mdep_class_list_size; 345183725Sjkoshy 346145256Sjkoshy/* 347145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 348145256Sjkoshy * strings. 349145256Sjkoshy */ 350145256Sjkoshy 351145256Sjkoshystatic const char * pmc_capability_names[] = { 352145256Sjkoshy#undef __PMC_CAP 353145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 354145256Sjkoshy __PMC_CAPS() 355145256Sjkoshy}; 356145256Sjkoshy 357145256Sjkoshystatic const char * pmc_class_names[] = { 358145256Sjkoshy#undef __PMC_CLASS 359145256Sjkoshy#define __PMC_CLASS(C) #C , 360145256Sjkoshy __PMC_CLASSES() 361145256Sjkoshy}; 362145256Sjkoshy 363183725Sjkoshystruct pmc_cputype_map { 364228557Sdim enum pmc_cputype pm_cputype; 365183725Sjkoshy const char *pm_name; 366183725Sjkoshy}; 367183725Sjkoshy 368183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 369145256Sjkoshy#undef __PMC_CPU 370183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 371145256Sjkoshy __PMC_CPUS() 372145256Sjkoshy}; 373145256Sjkoshy 374145256Sjkoshystatic const char * pmc_disposition_names[] = { 375145256Sjkoshy#undef __PMC_DISP 376145256Sjkoshy#define __PMC_DISP(D) #D , 377145256Sjkoshy __PMC_DISPOSITIONS() 378145256Sjkoshy}; 379145256Sjkoshy 380145256Sjkoshystatic const char * pmc_mode_names[] = { 381145256Sjkoshy#undef __PMC_MODE 382145256Sjkoshy#define __PMC_MODE(M,N) #M , 383145256Sjkoshy __PMC_MODES() 384145256Sjkoshy}; 385145256Sjkoshy 386145256Sjkoshystatic const char * pmc_state_names[] = { 387145256Sjkoshy#undef __PMC_STATE 388145256Sjkoshy#define __PMC_STATE(S) #S , 389145256Sjkoshy __PMC_STATES() 390145256Sjkoshy}; 391145256Sjkoshy 392233628Sfabient/* 393233628Sfabient * Filled in by pmc_init(). 394233628Sfabient */ 395233628Sfabientstatic int pmc_syscall = -1; 396233628Sfabientstatic struct pmc_cpuinfo cpu_info; 397233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info; 398145256Sjkoshy 399145256Sjkoshy/* Event masks for events */ 400145256Sjkoshystruct pmc_masks { 401145256Sjkoshy const char *pm_name; 402240164Sfabient const uint64_t pm_value; 403145256Sjkoshy}; 404145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 405206089Sfabient#define NULLMASK { .pm_name = NULL } 406145256Sjkoshy 407147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 408145256Sjkoshystatic int 409240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask) 410145256Sjkoshy{ 411145256Sjkoshy const struct pmc_masks *pm; 412145256Sjkoshy char *q, *r; 413145256Sjkoshy int c; 414145256Sjkoshy 415145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 416174406Sjkoshy return (-1); 417183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 418145256Sjkoshy if (*++q == '\0') /* no more data */ 419174406Sjkoshy return (-1); 420145256Sjkoshy c = 0; /* count of mask keywords seen */ 421145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 422183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 423183725Sjkoshy pm++) 424145256Sjkoshy ; 425145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 426174406Sjkoshy return (-1); 427145256Sjkoshy *evmask |= pm->pm_value; 428145256Sjkoshy c++; 429145256Sjkoshy } 430174406Sjkoshy return (c); 431145256Sjkoshy} 432145340Smarcel#endif 433145256Sjkoshy 434145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 435145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 436145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 437145256Sjkoshy 438145340Smarcel#if defined(__i386__) 439145256Sjkoshy 440145256Sjkoshy/* 441145256Sjkoshy * AMD K7 (Athlon) CPUs. 442145256Sjkoshy */ 443145256Sjkoshy 444145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 445145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 446145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 447145351Sjkoshy EV_ALIAS("cycles", "tsc"), 448183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 449145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 450145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 451145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 452145351Sjkoshy EV_ALIAS(NULL, NULL) 453145256Sjkoshy}; 454145256Sjkoshy 455145256Sjkoshy#define K7_KW_COUNT "count" 456145256Sjkoshy#define K7_KW_EDGE "edge" 457145256Sjkoshy#define K7_KW_INV "inv" 458145256Sjkoshy#define K7_KW_OS "os" 459145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 460145256Sjkoshy#define K7_KW_USR "usr" 461145256Sjkoshy 462145256Sjkoshystatic int 463145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 464145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 465145256Sjkoshy{ 466183107Sjkoshy char *e, *p, *q; 467183107Sjkoshy int c, has_unitmask; 468145256Sjkoshy uint32_t count, unitmask; 469145256Sjkoshy 470147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 471183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 472145256Sjkoshy 473145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 474145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 475145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 476145256Sjkoshy has_unitmask = 1; 477147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 478145256Sjkoshy } else 479145256Sjkoshy unitmask = has_unitmask = 0; 480145256Sjkoshy 481145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 482145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 483145256Sjkoshy q = strchr(p, '='); 484145256Sjkoshy if (*++q == '\0') /* skip '=' */ 485174406Sjkoshy return (-1); 486145256Sjkoshy 487145256Sjkoshy count = strtol(q, &e, 0); 488145256Sjkoshy if (e == q || *e != '\0') 489174406Sjkoshy return (-1); 490145256Sjkoshy 491145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 492147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 493147191Sjkoshy AMD_PMC_TO_COUNTER(count); 494145256Sjkoshy 495145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 496145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 497145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 498145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 499145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 500145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 501145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 502145256Sjkoshy if (has_unitmask == 0) 503174406Sjkoshy return (-1); 504145256Sjkoshy unitmask = 0; 505145256Sjkoshy q = strchr(p, '='); 506145256Sjkoshy if (*++q == '\0') /* skip '=' */ 507174406Sjkoshy return (-1); 508145256Sjkoshy 509145256Sjkoshy while ((c = tolower(*q++)) != 0) 510145256Sjkoshy if (c == 'm') 511147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 512145256Sjkoshy else if (c == 'o') 513147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 514145256Sjkoshy else if (c == 'e') 515147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 516145256Sjkoshy else if (c == 's') 517147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 518145256Sjkoshy else if (c == 'i') 519147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 520145256Sjkoshy else if (c == '+') 521145256Sjkoshy continue; 522145256Sjkoshy else 523174406Sjkoshy return (-1); 524145256Sjkoshy 525145256Sjkoshy if (unitmask == 0) 526174406Sjkoshy return (-1); 527145256Sjkoshy 528145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 529145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 530145256Sjkoshy } else 531174406Sjkoshy return (-1); 532145256Sjkoshy } 533145256Sjkoshy 534145256Sjkoshy if (has_unitmask) { 535145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 536147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 537147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 538145256Sjkoshy } 539145256Sjkoshy 540174406Sjkoshy return (0); 541145256Sjkoshy 542145256Sjkoshy} 543145256Sjkoshy 544147191Sjkoshy#endif 545147191Sjkoshy 546147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 547147191Sjkoshy 548145256Sjkoshy/* 549185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 550185363Sjkoshy */ 551185363Sjkoshy 552185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 553185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 554185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 555185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 556185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 557185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 558185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 559185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 560185363Sjkoshy EV_ALIAS(NULL, NULL) 561185363Sjkoshy}; 562185363Sjkoshy 563185363Sjkoshy/* 564185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 565185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 566198433Sjkoshy * 567198433Sjkoshy * We map aliases to events on the fixed-function counters if these 568198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 569198433Sjkoshy * counters. 570185363Sjkoshy */ 571185363Sjkoshy 572185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 573185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 574185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 575185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 576185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 577185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 578185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 579185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 580185363Sjkoshy EV_ALIAS(NULL, NULL) 581185363Sjkoshy}; 582185363Sjkoshy 583198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 584198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 585198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 586198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 587198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 588198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 589198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 590198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 591198433Sjkoshy EV_ALIAS(NULL, NULL) 592198433Sjkoshy}; 593198433Sjkoshy 594198433Sjkoshy#define atom_aliases core2_aliases 595198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 596198433Sjkoshy#define corei7_aliases core2_aliases 597198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 598248842Ssbruno#define haswell_aliases core2_aliases 599248842Ssbruno#define haswell_aliases_without_iaf core2_aliases_without_iaf 600240164Sfabient#define ivybridge_aliases core2_aliases 601240164Sfabient#define ivybridge_aliases_without_iaf core2_aliases_without_iaf 602246166Ssbruno#define ivybridge_xeon_aliases core2_aliases 603246166Ssbruno#define ivybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 604232366Sdavide#define sandybridge_aliases core2_aliases 605232366Sdavide#define sandybridge_aliases_without_iaf core2_aliases_without_iaf 606241738Ssbruno#define sandybridge_xeon_aliases core2_aliases 607241738Ssbruno#define sandybridge_xeon_aliases_without_iaf core2_aliases_without_iaf 608206089Sfabient#define westmere_aliases core2_aliases 609206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 610198433Sjkoshy 611185363Sjkoshy#define IAF_KW_OS "os" 612185363Sjkoshy#define IAF_KW_USR "usr" 613185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 614185363Sjkoshy 615185363Sjkoshy/* 616185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 617185363Sjkoshy */ 618185363Sjkoshystatic int 619185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 620185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 621185363Sjkoshy{ 622185363Sjkoshy char *p; 623185363Sjkoshy 624185363Sjkoshy (void) pe; 625185363Sjkoshy 626185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 627185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 628185363Sjkoshy 629185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 630185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 631185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 632185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 633185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 634185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 635185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 636185363Sjkoshy else 637185363Sjkoshy return (-1); 638185363Sjkoshy } 639185363Sjkoshy 640185363Sjkoshy return (0); 641185363Sjkoshy} 642185363Sjkoshy 643185363Sjkoshy/* 644185363Sjkoshy * Core/Core2 support. 645185363Sjkoshy */ 646185363Sjkoshy 647185363Sjkoshy#define IAP_KW_AGENT "agent" 648185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 649185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 650185363Sjkoshy#define IAP_KW_CMASK "cmask" 651185363Sjkoshy#define IAP_KW_CORE "core" 652185363Sjkoshy#define IAP_KW_EDGE "edge" 653185363Sjkoshy#define IAP_KW_INV "inv" 654185363Sjkoshy#define IAP_KW_OS "os" 655185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 656185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 657185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 658185363Sjkoshy#define IAP_KW_TRANSITION "trans" 659185363Sjkoshy#define IAP_KW_USR "usr" 660206089Sfabient#define IAP_KW_RSP "rsp" 661185363Sjkoshy 662185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 663185363Sjkoshy PMCMASK(all, (0x3 << 14)), 664185363Sjkoshy PMCMASK(this, (0x1 << 14)), 665185363Sjkoshy NULLMASK 666185363Sjkoshy}; 667185363Sjkoshy 668185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 669185363Sjkoshy PMCMASK(this, 0), 670185363Sjkoshy PMCMASK(any, (0x1 << 13)), 671185363Sjkoshy NULLMASK 672185363Sjkoshy}; 673185363Sjkoshy 674185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 675185363Sjkoshy PMCMASK(both, (0x3 << 12)), 676185363Sjkoshy PMCMASK(only, (0x1 << 12)), 677185363Sjkoshy PMCMASK(exclude, 0), 678185363Sjkoshy NULLMASK 679185363Sjkoshy}; 680185363Sjkoshy 681185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 682185363Sjkoshy PMCMASK(i, (1 << 8)), 683185363Sjkoshy PMCMASK(s, (1 << 9)), 684185363Sjkoshy PMCMASK(e, (1 << 10)), 685185363Sjkoshy PMCMASK(m, (1 << 11)), 686185363Sjkoshy NULLMASK 687185363Sjkoshy}; 688185363Sjkoshy 689185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 690185363Sjkoshy PMCMASK(clean, (1 << 8)), 691185363Sjkoshy PMCMASK(hit, (1 << 9)), 692185363Sjkoshy PMCMASK(hitm, (1 << 11)), 693185363Sjkoshy NULLMASK 694185363Sjkoshy}; 695185363Sjkoshy 696185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 697185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 698185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 699185363Sjkoshy NULLMASK 700185363Sjkoshy}; 701185363Sjkoshy 702185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 703185363Sjkoshy PMCMASK(any, 0x00), 704185363Sjkoshy PMCMASK(frequency, 0x10), 705185363Sjkoshy NULLMASK 706185363Sjkoshy}; 707185363Sjkoshy 708240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = { 709206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 710206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 711206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 712206089Sfabient PMCMASK(WB, (1 << 3)), 713206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 714206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 715206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 716206089Sfabient PMCMASK(OTHER, (1 << 7)), 717206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 718206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 719206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 720206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 721206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 722206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 723206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 724206089Sfabient NULLMASK 725206089Sfabient}; 726206089Sfabient 727241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = { 728240164Sfabient PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 729240164Sfabient PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 730240164Sfabient PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 731240164Sfabient PMCMASK(REQ_WB, (1ULL << 3)), 732240164Sfabient PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 733240164Sfabient PMCMASK(REQ_PF_RFO, (1ULL << 5)), 734240164Sfabient PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 735240164Sfabient PMCMASK(REQ_PF_LLC_DATA_RD, (1ULL << 7)), 736240164Sfabient PMCMASK(REQ_PF_LLC_RFO, (1ULL << 8)), 737240164Sfabient PMCMASK(REQ_PF_LLC_IFETCH, (1ULL << 9)), 738240164Sfabient PMCMASK(REQ_BUS_LOCKS, (1ULL << 10)), 739240164Sfabient PMCMASK(REQ_STRM_ST, (1ULL << 11)), 740240164Sfabient PMCMASK(REQ_OTHER, (1ULL << 15)), 741240164Sfabient PMCMASK(RES_ANY, (1ULL << 16)), 742240164Sfabient PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 743240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 744240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 745240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 746240164Sfabient PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 747240164Sfabient PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 748241974Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 749240164Sfabient PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 750240164Sfabient PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 751240164Sfabient PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 752240164Sfabient PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 753240164Sfabient PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 754240164Sfabient PMCMASK(RES_NON_DRAM, (1ULL << 37)), 755240164Sfabient NULLMASK 756240164Sfabient}; 757240164Sfabient 758248842Ssbrunostatic struct pmc_masks iap_rsp_mask_haswell[] = { 759248842Ssbruno PMCMASK(REQ_DMND_DATA_RD, (1ULL << 0)), 760248842Ssbruno PMCMASK(REQ_DMND_RFO, (1ULL << 1)), 761248842Ssbruno PMCMASK(REQ_DMND_IFETCH, (1ULL << 2)), 762248842Ssbruno PMCMASK(REQ_PF_DATA_RD, (1ULL << 4)), 763248842Ssbruno PMCMASK(REQ_PF_RFO, (1ULL << 5)), 764248842Ssbruno PMCMASK(REQ_PF_IFETCH, (1ULL << 6)), 765248842Ssbruno PMCMASK(REQ_OTHER, (1ULL << 15)), 766248842Ssbruno PMCMASK(RES_ANY, (1ULL << 16)), 767248842Ssbruno PMCMASK(RES_SUPPLIER_SUPP, (1ULL << 17)), 768248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITM, (1ULL << 18)), 769248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITE, (1ULL << 19)), 770248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITS, (1ULL << 20)), 771248842Ssbruno PMCMASK(RES_SUPPLIER_LLC_HITF, (1ULL << 21)), 772248842Ssbruno PMCMASK(RES_SUPPLIER_LOCAL, (1ULL << 22)), 773248842Ssbruno PMCMASK(RES_SNOOP_SNP_NONE, (1ULL << 31)), 774248842Ssbruno PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)), 775248842Ssbruno PMCMASK(RES_SNOOP_SNP_MISS, (1ULL << 33)), 776248842Ssbruno PMCMASK(RES_SNOOP_HIT_NO_FWD, (1ULL << 34)), 777248842Ssbruno PMCMASK(RES_SNOOP_HIT_FWD, (1ULL << 35)), 778248842Ssbruno PMCMASK(RES_SNOOP_HITM, (1ULL << 36)), 779248842Ssbruno PMCMASK(RES_NON_DRAM, (1ULL << 37)), 780248842Ssbruno NULLMASK 781248842Ssbruno}; 782248842Ssbruno 783185363Sjkoshystatic int 784185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 785185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 786185363Sjkoshy{ 787185363Sjkoshy char *e, *p, *q; 788240164Sfabient uint64_t cachestate, evmask, rsp; 789185363Sjkoshy int count, n; 790185363Sjkoshy 791185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 792185363Sjkoshy PMC_CAP_QUALIFIER); 793185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 794185363Sjkoshy 795206089Sfabient cachestate = evmask = rsp = 0; 796185363Sjkoshy 797185363Sjkoshy /* Parse additional modifiers if present */ 798185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 799185363Sjkoshy 800185363Sjkoshy n = 0; 801185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 802185363Sjkoshy q = strchr(p, '='); 803185363Sjkoshy if (*++q == '\0') /* skip '=' */ 804185363Sjkoshy return (-1); 805185363Sjkoshy count = strtol(q, &e, 0); 806185363Sjkoshy if (e == q || *e != '\0') 807185363Sjkoshy return (-1); 808185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 809185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 810185363Sjkoshy IAP_CMASK(count); 811185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 812185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 813185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 814185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 815185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 816185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 817185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 818185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 819185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 820185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 821193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 822185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 823185363Sjkoshy if (n != 1) 824185363Sjkoshy return (-1); 825193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 826185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 827185363Sjkoshy if (n != 1) 828185363Sjkoshy return (-1); 829193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 830185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 831185363Sjkoshy if (n != 1) 832185363Sjkoshy return (-1); 833193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 834185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 835185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 836193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 837185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 838185363Sjkoshy if (n != 1) 839185363Sjkoshy return (-1); 840185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 841185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 842206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 843193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 844185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 845185363Sjkoshy &evmask); 846193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 847185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 848185363Sjkoshy &evmask); 849185363Sjkoshy } else 850185363Sjkoshy return (-1); 851206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 852206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 853206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 854240164Sfabient n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp); 855206089Sfabient } else 856206089Sfabient return (-1); 857240164Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE || 858241738Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON || 859246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE || 860246166Ssbruno cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) { 861240164Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 862241738Ssbruno n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp); 863240164Sfabient } else 864240164Sfabient return (-1); 865248842Ssbruno } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL) { 866248842Ssbruno if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 867248842Ssbruno n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp); 868248842Ssbruno } else 869248842Ssbruno return (-1); 870185363Sjkoshy } else 871185363Sjkoshy return (-1); 872185363Sjkoshy 873185363Sjkoshy if (n < 0) /* Parsing failed. */ 874185363Sjkoshy return (-1); 875185363Sjkoshy } 876185363Sjkoshy 877185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 878185363Sjkoshy 879185363Sjkoshy /* 880185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 881185363Sjkoshy * specified by the user, use a sensible default. 882185363Sjkoshy */ 883185363Sjkoshy switch (pe) { 884185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 885185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 886185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 887185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 888185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 889185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 890185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 891185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 892185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 893185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 894185363Sjkoshy if (cachestate == 0) 895185363Sjkoshy cachestate = (0xF << 8); 896207482Srstone break; 897207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 898207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 899207482Srstone * Atom processor 900207482Srstone */ 901207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 902207482Srstone cachestate = (0xF << 8); 903207482Srstone break; 904185363Sjkoshy default: 905185363Sjkoshy break; 906185363Sjkoshy } 907185363Sjkoshy 908185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 909206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 910185363Sjkoshy 911185363Sjkoshy return (0); 912185363Sjkoshy} 913185363Sjkoshy 914185363Sjkoshy/* 915206089Sfabient * Intel Uncore. 916206089Sfabient */ 917206089Sfabient 918206089Sfabientstatic int 919206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 920206089Sfabient struct pmc_op_pmcallocate *pmc_config) 921206089Sfabient{ 922206089Sfabient (void) pe; 923206089Sfabient (void) ctrspec; 924206089Sfabient 925206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 926206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 927206089Sfabient 928206089Sfabient return (0); 929206089Sfabient} 930206089Sfabient 931206089Sfabient#define UCP_KW_CMASK "cmask" 932206089Sfabient#define UCP_KW_EDGE "edge" 933206089Sfabient#define UCP_KW_INV "inv" 934206089Sfabient 935206089Sfabientstatic int 936206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 937206089Sfabient struct pmc_op_pmcallocate *pmc_config) 938206089Sfabient{ 939206089Sfabient char *e, *p, *q; 940206089Sfabient int count, n; 941206089Sfabient 942206089Sfabient (void) pe; 943206089Sfabient 944206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 945206089Sfabient PMC_CAP_QUALIFIER); 946206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 947206089Sfabient 948206089Sfabient /* Parse additional modifiers if present */ 949206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 950206089Sfabient 951206089Sfabient n = 0; 952206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 953206089Sfabient q = strchr(p, '='); 954206089Sfabient if (*++q == '\0') /* skip '=' */ 955206089Sfabient return (-1); 956206089Sfabient count = strtol(q, &e, 0); 957206089Sfabient if (e == q || *e != '\0') 958206089Sfabient return (-1); 959206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 960206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 961206089Sfabient UCP_CMASK(count); 962206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 963206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 964206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 965206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 966206089Sfabient } else 967206089Sfabient return (-1); 968206089Sfabient 969206089Sfabient if (n < 0) /* Parsing failed. */ 970206089Sfabient return (-1); 971206089Sfabient } 972206089Sfabient 973206089Sfabient return (0); 974206089Sfabient} 975206089Sfabient 976206089Sfabient/* 977147191Sjkoshy * AMD K8 PMCs. 978147191Sjkoshy * 979147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 980147191Sjkoshy * events. 981147191Sjkoshy */ 982147191Sjkoshy 983147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 984147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 985147191Sjkoshy EV_ALIAS("branch-mispredicts", 986147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 987147191Sjkoshy EV_ALIAS("cycles", "tsc"), 988147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 989147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 990183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 991147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 992155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 993147191Sjkoshy EV_ALIAS(NULL, NULL) 994147191Sjkoshy}; 995147191Sjkoshy 996147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 997147191Sjkoshy 998147191Sjkoshy/* 999147191Sjkoshy * Parsing tables 1000147191Sjkoshy */ 1001147191Sjkoshy 1002147191Sjkoshy/* fp dispatched fpu ops */ 1003147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 1004147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 1005147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 1006147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 1007147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 1008147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 1009147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 1010147191Sjkoshy NULLMASK 1011147191Sjkoshy}; 1012147191Sjkoshy 1013147191Sjkoshy/* ls segment register loads */ 1014147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 1015147191Sjkoshy __K8MASK(es, 0), 1016147191Sjkoshy __K8MASK(cs, 1), 1017147191Sjkoshy __K8MASK(ss, 2), 1018147191Sjkoshy __K8MASK(ds, 3), 1019147191Sjkoshy __K8MASK(fs, 4), 1020147191Sjkoshy __K8MASK(gs, 5), 1021147191Sjkoshy __K8MASK(hs, 6), 1022147191Sjkoshy NULLMASK 1023147191Sjkoshy}; 1024147191Sjkoshy 1025147191Sjkoshy/* ls locked operation */ 1026147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 1027147191Sjkoshy __K8MASK(locked-instructions, 0), 1028147191Sjkoshy __K8MASK(cycles-in-request, 1), 1029147191Sjkoshy __K8MASK(cycles-to-complete, 2), 1030147191Sjkoshy NULLMASK 1031147191Sjkoshy}; 1032147191Sjkoshy 1033147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 1034147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 1035147191Sjkoshy __K8MASK(invalid, 0), 1036147191Sjkoshy __K8MASK(shared, 1), 1037147191Sjkoshy __K8MASK(exclusive, 2), 1038147191Sjkoshy __K8MASK(owner, 3), 1039147191Sjkoshy __K8MASK(modified, 4), 1040147191Sjkoshy NULLMASK 1041147191Sjkoshy}; 1042147191Sjkoshy 1043147191Sjkoshy/* dc one bit ecc error */ 1044147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1045147191Sjkoshy __K8MASK(scrubber, 0), 1046147191Sjkoshy __K8MASK(piggyback, 1), 1047147191Sjkoshy NULLMASK 1048147191Sjkoshy}; 1049147191Sjkoshy 1050147191Sjkoshy/* dc dispatched prefetch instructions */ 1051147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1052147191Sjkoshy __K8MASK(load, 0), 1053147191Sjkoshy __K8MASK(store, 1), 1054147191Sjkoshy __K8MASK(nta, 2), 1055147191Sjkoshy NULLMASK 1056147191Sjkoshy}; 1057147191Sjkoshy 1058147191Sjkoshy/* dc dcache accesses by locks */ 1059147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1060147191Sjkoshy __K8MASK(accesses, 0), 1061147191Sjkoshy __K8MASK(misses, 1), 1062147191Sjkoshy NULLMASK 1063147191Sjkoshy}; 1064147191Sjkoshy 1065147191Sjkoshy/* bu internal l2 request */ 1066147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1067147191Sjkoshy __K8MASK(ic-fill, 0), 1068147191Sjkoshy __K8MASK(dc-fill, 1), 1069147191Sjkoshy __K8MASK(tlb-reload, 2), 1070147191Sjkoshy __K8MASK(tag-snoop, 3), 1071147191Sjkoshy __K8MASK(cancelled, 4), 1072147191Sjkoshy NULLMASK 1073147191Sjkoshy}; 1074147191Sjkoshy 1075147191Sjkoshy/* bu fill request l2 miss */ 1076147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1077147191Sjkoshy __K8MASK(ic-fill, 0), 1078147191Sjkoshy __K8MASK(dc-fill, 1), 1079147191Sjkoshy __K8MASK(tlb-reload, 2), 1080147191Sjkoshy NULLMASK 1081147191Sjkoshy}; 1082147191Sjkoshy 1083147191Sjkoshy/* bu fill into l2 */ 1084147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1085147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 1086147191Sjkoshy __K8MASK(victim-from-l2, 1), 1087147191Sjkoshy NULLMASK 1088147191Sjkoshy}; 1089147191Sjkoshy 1090147191Sjkoshy/* fr retired fpu instructions */ 1091147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1092147191Sjkoshy __K8MASK(x87, 0), 1093147191Sjkoshy __K8MASK(mmx-3dnow, 1), 1094147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 1095147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1096147191Sjkoshy NULLMASK 1097147191Sjkoshy}; 1098147191Sjkoshy 1099147191Sjkoshy/* fr retired fastpath double op instructions */ 1100147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1101147191Sjkoshy __K8MASK(low-op-pos-0, 0), 1102147191Sjkoshy __K8MASK(low-op-pos-1, 1), 1103147191Sjkoshy __K8MASK(low-op-pos-2, 2), 1104147191Sjkoshy NULLMASK 1105147191Sjkoshy}; 1106147191Sjkoshy 1107147191Sjkoshy/* fr fpu exceptions */ 1108147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1109147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1110147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1111147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1112147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1113147191Sjkoshy NULLMASK 1114147191Sjkoshy}; 1115147191Sjkoshy 1116147191Sjkoshy/* nb memory controller page access event */ 1117147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1118147191Sjkoshy __K8MASK(page-hit, 0), 1119147191Sjkoshy __K8MASK(page-miss, 1), 1120147191Sjkoshy __K8MASK(page-conflict, 2), 1121147191Sjkoshy NULLMASK 1122147191Sjkoshy}; 1123147191Sjkoshy 1124147191Sjkoshy/* nb memory controller turnaround */ 1125147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1126147191Sjkoshy __K8MASK(dimm-turnaround, 0), 1127147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1128147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1129147191Sjkoshy NULLMASK 1130147191Sjkoshy}; 1131147191Sjkoshy 1132147191Sjkoshy/* nb memory controller bypass saturation */ 1133147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1134147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1135147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1136147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1137147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1138147191Sjkoshy NULLMASK 1139147191Sjkoshy}; 1140147191Sjkoshy 1141147191Sjkoshy/* nb sized commands */ 1142147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1143147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1144147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 1145147191Sjkoshy __K8MASK(postwrszbyte, 2), 1146147191Sjkoshy __K8MASK(postwrszdword, 3), 1147147191Sjkoshy __K8MASK(rdszbyte, 4), 1148147191Sjkoshy __K8MASK(rdszdword, 5), 1149147191Sjkoshy __K8MASK(rdmodwr, 6), 1150147191Sjkoshy NULLMASK 1151147191Sjkoshy}; 1152147191Sjkoshy 1153147191Sjkoshy/* nb probe result */ 1154147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1155147191Sjkoshy __K8MASK(probe-miss, 0), 1156147191Sjkoshy __K8MASK(probe-hit, 1), 1157147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1158147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1159147191Sjkoshy NULLMASK 1160147191Sjkoshy}; 1161147191Sjkoshy 1162147191Sjkoshy/* nb hypertransport bus bandwidth */ 1163147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1164147191Sjkoshy __K8MASK(command, 0), 1165183107Sjkoshy __K8MASK(data, 1), 1166147191Sjkoshy __K8MASK(buffer-release, 2), 1167147191Sjkoshy __K8MASK(nop, 3), 1168147191Sjkoshy NULLMASK 1169147191Sjkoshy}; 1170147191Sjkoshy 1171147191Sjkoshy#undef __K8MASK 1172147191Sjkoshy 1173147191Sjkoshy#define K8_KW_COUNT "count" 1174147191Sjkoshy#define K8_KW_EDGE "edge" 1175147191Sjkoshy#define K8_KW_INV "inv" 1176147191Sjkoshy#define K8_KW_MASK "mask" 1177147191Sjkoshy#define K8_KW_OS "os" 1178147191Sjkoshy#define K8_KW_USR "usr" 1179147191Sjkoshy 1180147191Sjkoshystatic int 1181147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1182147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1183147191Sjkoshy{ 1184183107Sjkoshy char *e, *p, *q; 1185183107Sjkoshy int n; 1186240164Sfabient uint32_t count; 1187240164Sfabient uint64_t evmask; 1188147191Sjkoshy const struct pmc_masks *pm, *pmask; 1189147191Sjkoshy 1190183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1191147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1192147191Sjkoshy 1193147191Sjkoshy pmask = NULL; 1194147191Sjkoshy evmask = 0; 1195147191Sjkoshy 1196147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1197147191Sjkoshy 1198147191Sjkoshy /* setup parsing tables */ 1199147191Sjkoshy switch (pe) { 1200147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1201147191Sjkoshy __K8SETMASK(fdfo); 1202147191Sjkoshy break; 1203147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1204147191Sjkoshy __K8SETMASK(lsrl); 1205147191Sjkoshy break; 1206147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1207147191Sjkoshy __K8SETMASK(llo); 1208147191Sjkoshy break; 1209147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1210147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1211147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1212147191Sjkoshy __K8SETMASK(dc); 1213147191Sjkoshy break; 1214147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1215147191Sjkoshy __K8SETMASK(dobee); 1216147191Sjkoshy break; 1217147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1218147191Sjkoshy __K8SETMASK(ddpi); 1219147191Sjkoshy break; 1220147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1221147191Sjkoshy __K8SETMASK(dabl); 1222147191Sjkoshy break; 1223147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1224147191Sjkoshy __K8SETMASK(bilr); 1225147191Sjkoshy break; 1226147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1227147191Sjkoshy __K8SETMASK(bfrlm); 1228147191Sjkoshy break; 1229147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1230147191Sjkoshy __K8SETMASK(bfil); 1231147191Sjkoshy break; 1232147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1233147191Sjkoshy __K8SETMASK(frfi); 1234147191Sjkoshy break; 1235147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1236147191Sjkoshy __K8SETMASK(frfdoi); 1237147191Sjkoshy break; 1238147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1239147191Sjkoshy __K8SETMASK(ffe); 1240147191Sjkoshy break; 1241147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1242147191Sjkoshy __K8SETMASK(nmcpae); 1243147191Sjkoshy break; 1244147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1245147191Sjkoshy __K8SETMASK(nmct); 1246147191Sjkoshy break; 1247147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1248147191Sjkoshy __K8SETMASK(nmcbs); 1249147191Sjkoshy break; 1250147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1251147191Sjkoshy __K8SETMASK(nsc); 1252147191Sjkoshy break; 1253147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1254147191Sjkoshy __K8SETMASK(npr); 1255147191Sjkoshy break; 1256147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1257147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1258147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1259147191Sjkoshy __K8SETMASK(nhbb); 1260147191Sjkoshy break; 1261147191Sjkoshy 1262147191Sjkoshy default: 1263147191Sjkoshy break; /* no options defined */ 1264147191Sjkoshy } 1265147191Sjkoshy 1266147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1267147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1268147191Sjkoshy q = strchr(p, '='); 1269147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1270174406Sjkoshy return (-1); 1271147191Sjkoshy 1272147191Sjkoshy count = strtol(q, &e, 0); 1273147191Sjkoshy if (e == q || *e != '\0') 1274174406Sjkoshy return (-1); 1275147191Sjkoshy 1276147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1277147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1278147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1279147191Sjkoshy 1280147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1281147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1282147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1283147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1284147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1285147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1286174406Sjkoshy return (-1); 1287147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1288147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1289147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1290147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1291147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1292147191Sjkoshy } else 1293174406Sjkoshy return (-1); 1294147191Sjkoshy } 1295147191Sjkoshy 1296147191Sjkoshy /* other post processing */ 1297147191Sjkoshy switch (pe) { 1298147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1299147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1300147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1301147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1302147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1303147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1304147191Sjkoshy /* XXX only available in rev B and later */ 1305147191Sjkoshy break; 1306147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1307147191Sjkoshy /* XXX only available in rev C and later */ 1308147191Sjkoshy break; 1309147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1310147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1311147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1312174406Sjkoshy return (-1); 1313147191Sjkoshy if (evmask == 0) { 1314147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1315147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1316147191Sjkoshy } 1317147191Sjkoshy break; 1318147191Sjkoshy default: 1319147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1320147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1321147191Sjkoshy evmask |= pm->pm_value; 1322147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1323147191Sjkoshy } 1324147191Sjkoshy } 1325147191Sjkoshy 1326147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1327147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1328147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1329147191Sjkoshy 1330174406Sjkoshy return (0); 1331147191Sjkoshy} 1332147191Sjkoshy 1333147191Sjkoshy#endif 1334147191Sjkoshy 1335147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1336147191Sjkoshy 1337147191Sjkoshy/* 1338145256Sjkoshy * Intel P4 PMCs 1339145256Sjkoshy */ 1340145256Sjkoshy 1341145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1342145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1343145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1344145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1345145351Sjkoshy EV_ALIAS("instructions", 1346145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1347155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1348145256Sjkoshy EV_ALIAS(NULL, NULL) 1349145256Sjkoshy}; 1350145256Sjkoshy 1351145256Sjkoshy#define P4_KW_ACTIVE "active" 1352145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1353145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1354145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1355145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1356145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1357145256Sjkoshy#define P4_KW_CASCADE "cascade" 1358145256Sjkoshy#define P4_KW_EDGE "edge" 1359145256Sjkoshy#define P4_KW_INV "complement" 1360145256Sjkoshy#define P4_KW_OS "os" 1361145256Sjkoshy#define P4_KW_MASK "mask" 1362145256Sjkoshy#define P4_KW_PRECISE "precise" 1363145256Sjkoshy#define P4_KW_TAG "tag" 1364145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1365145256Sjkoshy#define P4_KW_USR "usr" 1366145256Sjkoshy 1367145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1368145256Sjkoshy 1369145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1370145256Sjkoshy __P4MASK(dd, 0), 1371145256Sjkoshy __P4MASK(db, 1), 1372145256Sjkoshy __P4MASK(di, 2), 1373145256Sjkoshy __P4MASK(bd, 3), 1374145256Sjkoshy __P4MASK(bb, 4), 1375145256Sjkoshy __P4MASK(bi, 5), 1376145256Sjkoshy __P4MASK(id, 6), 1377145256Sjkoshy __P4MASK(ib, 7), 1378145256Sjkoshy NULLMASK 1379145256Sjkoshy}; 1380145256Sjkoshy 1381145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1382145256Sjkoshy __P4MASK(tcmiss, 0), 1383145256Sjkoshy NULLMASK, 1384145256Sjkoshy}; 1385145256Sjkoshy 1386145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1387145256Sjkoshy __P4MASK(hit, 0), 1388145256Sjkoshy __P4MASK(miss, 1), 1389145256Sjkoshy __P4MASK(hit-uc, 2), 1390145256Sjkoshy NULLMASK 1391145256Sjkoshy}; 1392145256Sjkoshy 1393145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1394145256Sjkoshy __P4MASK(st-rb-full, 2), 1395145256Sjkoshy __P4MASK(64k-conf, 3), 1396145256Sjkoshy NULLMASK 1397145256Sjkoshy}; 1398145256Sjkoshy 1399145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1400145256Sjkoshy __P4MASK(lsc, 0), 1401145256Sjkoshy __P4MASK(ssc, 1), 1402145256Sjkoshy NULLMASK 1403145256Sjkoshy}; 1404145256Sjkoshy 1405145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1406145256Sjkoshy __P4MASK(split-ld, 1), 1407145256Sjkoshy NULLMASK 1408145256Sjkoshy}; 1409145256Sjkoshy 1410145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1411145256Sjkoshy __P4MASK(split-st, 1), 1412145256Sjkoshy NULLMASK 1413145256Sjkoshy}; 1414145256Sjkoshy 1415145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1416145256Sjkoshy __P4MASK(no-sta, 1), 1417145256Sjkoshy __P4MASK(no-std, 3), 1418145256Sjkoshy __P4MASK(partial-data, 4), 1419145256Sjkoshy __P4MASK(unalgn-addr, 5), 1420145256Sjkoshy NULLMASK 1421145256Sjkoshy}; 1422145256Sjkoshy 1423145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1424145256Sjkoshy __P4MASK(dtmiss, 0), 1425145256Sjkoshy __P4MASK(itmiss, 1), 1426145256Sjkoshy NULLMASK 1427145256Sjkoshy}; 1428145256Sjkoshy 1429145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1430145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1431145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1432145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1433145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1434145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1435145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1436145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1437145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1438145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1439145256Sjkoshy NULLMASK 1440145256Sjkoshy}; 1441145256Sjkoshy 1442145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1443145256Sjkoshy __P4MASK(all-read, 5), 1444145256Sjkoshy __P4MASK(all-write, 6), 1445145256Sjkoshy __P4MASK(mem-uc, 7), 1446145256Sjkoshy __P4MASK(mem-wc, 8), 1447145256Sjkoshy __P4MASK(mem-wt, 9), 1448145256Sjkoshy __P4MASK(mem-wp, 10), 1449145256Sjkoshy __P4MASK(mem-wb, 11), 1450145256Sjkoshy __P4MASK(own, 13), 1451145256Sjkoshy __P4MASK(other, 14), 1452145256Sjkoshy __P4MASK(prefetch, 15), 1453145256Sjkoshy NULLMASK 1454145256Sjkoshy}; 1455145256Sjkoshy 1456145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 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_fda[] = { /* fsb data activity */ 1471145256Sjkoshy __P4MASK(drdy-drv, 0), 1472145256Sjkoshy __P4MASK(drdy-own, 1), 1473145256Sjkoshy __P4MASK(drdy-other, 2), 1474145256Sjkoshy __P4MASK(dbsy-drv, 3), 1475145256Sjkoshy __P4MASK(dbsy-own, 4), 1476145256Sjkoshy __P4MASK(dbsy-other, 5), 1477145256Sjkoshy NULLMASK 1478145256Sjkoshy}; 1479145256Sjkoshy 1480145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1481145256Sjkoshy __P4MASK(req-type0, 0), 1482145256Sjkoshy __P4MASK(req-type1, 1), 1483145256Sjkoshy __P4MASK(req-len0, 2), 1484145256Sjkoshy __P4MASK(req-len1, 3), 1485145256Sjkoshy __P4MASK(req-io-type, 5), 1486145256Sjkoshy __P4MASK(req-lock-type, 6), 1487145256Sjkoshy __P4MASK(req-cache-type, 7), 1488145256Sjkoshy __P4MASK(req-split-type, 8), 1489145256Sjkoshy __P4MASK(req-dem-type, 9), 1490145256Sjkoshy __P4MASK(req-ord-type, 10), 1491145256Sjkoshy __P4MASK(mem-type0, 11), 1492145256Sjkoshy __P4MASK(mem-type1, 12), 1493145256Sjkoshy __P4MASK(mem-type2, 13), 1494145256Sjkoshy NULLMASK 1495145256Sjkoshy}; 1496145256Sjkoshy 1497145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1498145256Sjkoshy __P4MASK(all, 15), 1499145256Sjkoshy NULLMASK 1500145256Sjkoshy}; 1501145256Sjkoshy 1502145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1503145256Sjkoshy __P4MASK(all, 15), 1504145256Sjkoshy NULLMASK 1505145256Sjkoshy}; 1506145256Sjkoshy 1507145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1508145256Sjkoshy __P4MASK(all, 15), 1509145256Sjkoshy NULLMASK 1510145256Sjkoshy}; 1511145256Sjkoshy 1512145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1513145256Sjkoshy __P4MASK(all, 15), 1514145256Sjkoshy NULLMASK 1515145256Sjkoshy}; 1516145256Sjkoshy 1517145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1518145256Sjkoshy __P4MASK(all, 15), 1519145256Sjkoshy NULLMASK 1520145256Sjkoshy}; 1521145256Sjkoshy 1522145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1523145256Sjkoshy __P4MASK(all, 15), 1524145256Sjkoshy NULLMASK 1525145256Sjkoshy}; 1526145256Sjkoshy 1527145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1528145256Sjkoshy __P4MASK(all, 15), 1529145256Sjkoshy NULLMASK 1530145256Sjkoshy}; 1531145256Sjkoshy 1532145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1533145256Sjkoshy __P4MASK(all, 15), 1534145256Sjkoshy NULLMASK 1535145256Sjkoshy}; 1536145256Sjkoshy 1537145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1538145256Sjkoshy __P4MASK(allp0, 3), 1539145256Sjkoshy __P4MASK(allp2, 4), 1540145256Sjkoshy NULLMASK 1541145256Sjkoshy}; 1542145256Sjkoshy 1543145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1544145256Sjkoshy __P4MASK(running, 0), 1545145256Sjkoshy NULLMASK 1546145256Sjkoshy}; 1547145256Sjkoshy 1548145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1549145256Sjkoshy __P4MASK(cisc, 0), 1550145256Sjkoshy NULLMASK 1551145256Sjkoshy}; 1552145256Sjkoshy 1553145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1554145256Sjkoshy __P4MASK(from-tc-build, 0), 1555145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1556145256Sjkoshy __P4MASK(from-rom, 2), 1557145256Sjkoshy NULLMASK 1558145256Sjkoshy}; 1559145256Sjkoshy 1560145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1561145351Sjkoshy /* retired mispred branch type */ 1562145256Sjkoshy __P4MASK(conditional, 1), 1563145256Sjkoshy __P4MASK(call, 2), 1564145256Sjkoshy __P4MASK(return, 3), 1565145256Sjkoshy __P4MASK(indirect, 4), 1566145256Sjkoshy NULLMASK 1567145256Sjkoshy}; 1568145256Sjkoshy 1569145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1570145256Sjkoshy __P4MASK(conditional, 1), 1571145256Sjkoshy __P4MASK(call, 2), 1572145256Sjkoshy __P4MASK(retired, 3), 1573145256Sjkoshy __P4MASK(indirect, 4), 1574145256Sjkoshy NULLMASK 1575145256Sjkoshy}; 1576145256Sjkoshy 1577145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1578145256Sjkoshy __P4MASK(sbfull, 5), 1579145256Sjkoshy NULLMASK 1580145256Sjkoshy}; 1581145256Sjkoshy 1582145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1583145256Sjkoshy __P4MASK(wcb-evicts, 0), 1584145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1585145256Sjkoshy NULLMASK 1586145256Sjkoshy}; 1587145256Sjkoshy 1588145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1589145256Sjkoshy __P4MASK(nbogus, 0), 1590145256Sjkoshy __P4MASK(bogus, 1), 1591145256Sjkoshy NULLMASK 1592145256Sjkoshy}; 1593145256Sjkoshy 1594145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1595145256Sjkoshy __P4MASK(nbogus0, 0), 1596145256Sjkoshy __P4MASK(nbogus1, 1), 1597145256Sjkoshy __P4MASK(nbogus2, 2), 1598145256Sjkoshy __P4MASK(nbogus3, 3), 1599145256Sjkoshy __P4MASK(bogus0, 4), 1600145256Sjkoshy __P4MASK(bogus1, 5), 1601145256Sjkoshy __P4MASK(bogus2, 6), 1602145256Sjkoshy __P4MASK(bogus3, 7), 1603145256Sjkoshy NULLMASK 1604145256Sjkoshy}; 1605145256Sjkoshy 1606145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1607145256Sjkoshy __P4MASK(nbogus, 0), 1608145256Sjkoshy __P4MASK(bogus, 1), 1609145256Sjkoshy NULLMASK 1610145256Sjkoshy}; 1611145256Sjkoshy 1612145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1613145256Sjkoshy __P4MASK(nbogusntag, 0), 1614145256Sjkoshy __P4MASK(nbogustag, 1), 1615145256Sjkoshy __P4MASK(bogusntag, 2), 1616145256Sjkoshy __P4MASK(bogustag, 3), 1617145256Sjkoshy NULLMASK 1618145256Sjkoshy}; 1619145256Sjkoshy 1620145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1621145256Sjkoshy __P4MASK(nbogus, 0), 1622145256Sjkoshy __P4MASK(bogus, 1), 1623145256Sjkoshy NULLMASK 1624145256Sjkoshy}; 1625145256Sjkoshy 1626145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1627145256Sjkoshy __P4MASK(tagloads, 1), 1628145256Sjkoshy __P4MASK(tagstores, 2), 1629145256Sjkoshy NULLMASK 1630145256Sjkoshy}; 1631145256Sjkoshy 1632145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1633145256Sjkoshy __P4MASK(mmnp, 0), 1634145256Sjkoshy __P4MASK(mmnm, 1), 1635145256Sjkoshy __P4MASK(mmtp, 2), 1636145256Sjkoshy __P4MASK(mmtm, 3), 1637145256Sjkoshy NULLMASK 1638145256Sjkoshy}; 1639145256Sjkoshy 1640145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1641145256Sjkoshy __P4MASK(nbogus, 0), 1642145256Sjkoshy NULLMASK 1643145256Sjkoshy}; 1644145256Sjkoshy 1645145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1646145256Sjkoshy __P4MASK(fpsu, 0), 1647145256Sjkoshy __P4MASK(fpso, 1), 1648145256Sjkoshy __P4MASK(poao, 2), 1649145256Sjkoshy __P4MASK(poau, 3), 1650145256Sjkoshy __P4MASK(prea, 4), 1651145256Sjkoshy NULLMASK 1652145256Sjkoshy}; 1653145256Sjkoshy 1654145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1655145256Sjkoshy __P4MASK(clear, 0), 1656145256Sjkoshy __P4MASK(moclear, 2), 1657145256Sjkoshy __P4MASK(smclear, 3), 1658145256Sjkoshy NULLMASK 1659145256Sjkoshy}; 1660145256Sjkoshy 1661145256Sjkoshy/* P4 event parser */ 1662145256Sjkoshystatic int 1663145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1664145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1665145256Sjkoshy{ 1666145256Sjkoshy 1667145256Sjkoshy char *e, *p, *q; 1668145256Sjkoshy int count, has_tag, has_busreqtype, n; 1669240164Sfabient uint32_t cccractivemask; 1670240164Sfabient uint64_t evmask; 1671145256Sjkoshy const struct pmc_masks *pm, *pmask; 1672145256Sjkoshy 1673183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1674147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1675147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1676145256Sjkoshy 1677145256Sjkoshy pmask = NULL; 1678145256Sjkoshy evmask = 0; 1679145256Sjkoshy cccractivemask = 0x3; 1680145256Sjkoshy has_tag = has_busreqtype = 0; 1681145256Sjkoshy 1682145256Sjkoshy#define __P4SETMASK(M) do { \ 1683183107Sjkoshy pmask = p4_mask_##M; \ 1684145256Sjkoshy} while (0) 1685145256Sjkoshy 1686145256Sjkoshy switch (pe) { 1687145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1688145256Sjkoshy __P4SETMASK(tcdm); 1689145256Sjkoshy break; 1690145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1691145256Sjkoshy __P4SETMASK(bfr); 1692145256Sjkoshy break; 1693145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1694145256Sjkoshy __P4SETMASK(ir); 1695145256Sjkoshy break; 1696145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1697145256Sjkoshy __P4SETMASK(memcan); 1698145256Sjkoshy break; 1699145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1700145256Sjkoshy __P4SETMASK(memcomp); 1701145256Sjkoshy break; 1702145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1703145256Sjkoshy __P4SETMASK(lpr); 1704145256Sjkoshy break; 1705145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1706145256Sjkoshy __P4SETMASK(spr); 1707145256Sjkoshy break; 1708145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1709145256Sjkoshy __P4SETMASK(mlr); 1710145256Sjkoshy break; 1711145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1712145256Sjkoshy __P4SETMASK(pwt); 1713145256Sjkoshy break; 1714145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1715145256Sjkoshy __P4SETMASK(bcr); 1716145256Sjkoshy break; 1717145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1718145256Sjkoshy __P4SETMASK(ia); 1719145256Sjkoshy has_busreqtype = 1; 1720145256Sjkoshy break; 1721145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1722145256Sjkoshy __P4SETMASK(iae); 1723145256Sjkoshy has_busreqtype = 1; 1724145256Sjkoshy break; 1725145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1726145256Sjkoshy __P4SETMASK(fda); 1727145256Sjkoshy break; 1728145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1729145256Sjkoshy __P4SETMASK(ba); 1730145256Sjkoshy break; 1731145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1732145256Sjkoshy __P4SETMASK(sia); 1733145256Sjkoshy break; 1734145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1735145256Sjkoshy __P4SETMASK(psu); 1736145256Sjkoshy break; 1737145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1738145256Sjkoshy __P4SETMASK(pdu); 1739145256Sjkoshy break; 1740145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1741145256Sjkoshy __P4SETMASK(ssu); 1742145256Sjkoshy break; 1743145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1744145256Sjkoshy __P4SETMASK(sdu); 1745145256Sjkoshy break; 1746145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1747145256Sjkoshy __P4SETMASK(64bmu); 1748145256Sjkoshy break; 1749145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1750145256Sjkoshy __P4SETMASK(128bmu); 1751145256Sjkoshy break; 1752145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1753145256Sjkoshy __P4SETMASK(xfu); 1754145256Sjkoshy break; 1755145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1756145256Sjkoshy __P4SETMASK(xsmu); 1757145256Sjkoshy break; 1758145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1759145256Sjkoshy __P4SETMASK(gpe); 1760145256Sjkoshy break; 1761145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1762145256Sjkoshy __P4SETMASK(tmx); 1763145256Sjkoshy break; 1764145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1765145256Sjkoshy __P4SETMASK(uqw); 1766145256Sjkoshy break; 1767145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1768145256Sjkoshy __P4SETMASK(rmbt); 1769145256Sjkoshy break; 1770145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1771145256Sjkoshy __P4SETMASK(rbt); 1772145256Sjkoshy break; 1773145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1774145256Sjkoshy __P4SETMASK(rs); 1775145256Sjkoshy break; 1776145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1777145256Sjkoshy __P4SETMASK(wb); 1778145256Sjkoshy break; 1779145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1780145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1781145256Sjkoshy case PMC_EV_P4_BNR: 1782145256Sjkoshy case PMC_EV_P4_SNOOP: 1783145256Sjkoshy case PMC_EV_P4_RESPONSE: 1784145256Sjkoshy break; 1785145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1786145256Sjkoshy __P4SETMASK(fee); 1787145256Sjkoshy break; 1788145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1789145256Sjkoshy __P4SETMASK(ee); 1790145256Sjkoshy break; 1791145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1792145256Sjkoshy __P4SETMASK(re); 1793145256Sjkoshy break; 1794145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1795145256Sjkoshy __P4SETMASK(insret); 1796145256Sjkoshy break; 1797145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1798145256Sjkoshy __P4SETMASK(ur); 1799145256Sjkoshy break; 1800145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1801145256Sjkoshy __P4SETMASK(ut); 1802145256Sjkoshy break; 1803145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1804145256Sjkoshy __P4SETMASK(br); 1805145256Sjkoshy break; 1806145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1807145256Sjkoshy __P4SETMASK(mbr); 1808145256Sjkoshy break; 1809145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1810145256Sjkoshy __P4SETMASK(xa); 1811145256Sjkoshy break; 1812145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1813145256Sjkoshy __P4SETMASK(machclr); 1814145256Sjkoshy break; 1815145256Sjkoshy default: 1816174406Sjkoshy return (-1); 1817145256Sjkoshy } 1818145256Sjkoshy 1819145256Sjkoshy /* process additional flags */ 1820145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1821145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1822145256Sjkoshy q = strchr(p, '='); 1823145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1824174406Sjkoshy return (-1); 1825145256Sjkoshy 1826183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1827145256Sjkoshy cccractivemask = 0x0; 1828183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1829145256Sjkoshy cccractivemask = 0x1; 1830183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1831145256Sjkoshy cccractivemask = 0x2; 1832183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1833145256Sjkoshy cccractivemask = 0x3; 1834145256Sjkoshy else 1835174406Sjkoshy return (-1); 1836145256Sjkoshy 1837145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1838145256Sjkoshy if (has_busreqtype == 0) 1839174406Sjkoshy return (-1); 1840145256Sjkoshy 1841145256Sjkoshy q = strchr(p, '='); 1842145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1843174406Sjkoshy return (-1); 1844145256Sjkoshy 1845145256Sjkoshy count = strtol(q, &e, 0); 1846145256Sjkoshy if (e == q || *e != '\0') 1847174406Sjkoshy return (-1); 1848145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1849145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1850145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1851145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1852145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1853145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1854145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1855145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1856145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1857174406Sjkoshy return (-1); 1858145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1859145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1860145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1861145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1862145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1863145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1864145256Sjkoshy if (has_tag == 0) 1865174406Sjkoshy return (-1); 1866145256Sjkoshy 1867145256Sjkoshy q = strchr(p, '='); 1868145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1869174406Sjkoshy return (-1); 1870145256Sjkoshy 1871145256Sjkoshy count = strtol(q, &e, 0); 1872145256Sjkoshy if (e == q || *e != '\0') 1873174406Sjkoshy return (-1); 1874145256Sjkoshy 1875145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1876147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1877145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1878145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1879145256Sjkoshy q = strchr(p, '='); 1880145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1881174406Sjkoshy return (-1); 1882145256Sjkoshy 1883145256Sjkoshy count = strtol(q, &e, 0); 1884145256Sjkoshy if (e == q || *e != '\0') 1885174406Sjkoshy return (-1); 1886145256Sjkoshy 1887145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1888147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1889147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1890147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1891147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1892145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1893145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1894145256Sjkoshy else 1895174406Sjkoshy return (-1); 1896145256Sjkoshy } 1897145256Sjkoshy 1898145256Sjkoshy /* other post processing */ 1899145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1900145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1901145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1902145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1903145256Sjkoshy 1904145256Sjkoshy /* fill in thread activity mask */ 1905147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1906145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1907145256Sjkoshy 1908145256Sjkoshy if (evmask) 1909145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1910145256Sjkoshy 1911145256Sjkoshy switch (pe) { 1912145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1913145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1914145256Sjkoshy (evmask & 0x18) == 0x18) 1915174406Sjkoshy return (-1); /* can't have own+other bits together */ 1916145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1917145256Sjkoshy evmask = 0x1D; 1918145256Sjkoshy break; 1919145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1920145256Sjkoshy /* only one bit is allowed to be set */ 1921145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1922174406Sjkoshy return (-1); 1923145256Sjkoshy if (evmask == 0) { 1924183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1925145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1926145256Sjkoshy } 1927145256Sjkoshy break; 1928145256Sjkoshy default: 1929145256Sjkoshy if (evmask == 0 && pmask) { 1930145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1931145256Sjkoshy evmask |= pm->pm_value; 1932145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1933145256Sjkoshy } 1934145256Sjkoshy } 1935145256Sjkoshy 1936147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1937147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1938145256Sjkoshy 1939174406Sjkoshy return (0); 1940145256Sjkoshy} 1941145256Sjkoshy 1942147759Sjkoshy#endif 1943147759Sjkoshy 1944147759Sjkoshy#if defined(__i386__) 1945147759Sjkoshy 1946145256Sjkoshy/* 1947147191Sjkoshy * Pentium style PMCs 1948147191Sjkoshy */ 1949147191Sjkoshy 1950147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1951183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1952183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1953183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1954183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1955183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1956183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1957183105Sjkoshy EV_ALIAS("unhalted-cycles", 1958183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1959147191Sjkoshy EV_ALIAS(NULL, NULL) 1960147191Sjkoshy}; 1961147191Sjkoshy 1962147191Sjkoshystatic int 1963147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1964147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1965147191Sjkoshy{ 1966174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1967147191Sjkoshy} 1968147191Sjkoshy 1969147191Sjkoshy/* 1970145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1971145256Sjkoshy * and Pentium M CPUs. 1972145256Sjkoshy */ 1973145256Sjkoshy 1974145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1975145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1976145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1977145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1978145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1979168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1980145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1981145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1982155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1983145351Sjkoshy EV_ALIAS(NULL, NULL) 1984145256Sjkoshy}; 1985145256Sjkoshy 1986145256Sjkoshy#define P6_KW_CMASK "cmask" 1987145256Sjkoshy#define P6_KW_EDGE "edge" 1988145256Sjkoshy#define P6_KW_INV "inv" 1989145256Sjkoshy#define P6_KW_OS "os" 1990145256Sjkoshy#define P6_KW_UMASK "umask" 1991145256Sjkoshy#define P6_KW_USR "usr" 1992145256Sjkoshy 1993145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1994145256Sjkoshy PMCMASK(m, 0x01), 1995145256Sjkoshy PMCMASK(e, 0x02), 1996145256Sjkoshy PMCMASK(s, 0x04), 1997145256Sjkoshy PMCMASK(i, 0x08), 1998145256Sjkoshy NULLMASK 1999145256Sjkoshy}; 2000145256Sjkoshy 2001145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 2002145256Sjkoshy PMCMASK(m, 0x01), 2003145256Sjkoshy PMCMASK(e, 0x02), 2004145256Sjkoshy PMCMASK(s, 0x04), 2005145256Sjkoshy PMCMASK(i, 0x08), 2006145256Sjkoshy PMCMASK(nonhw, 0x00), 2007145256Sjkoshy PMCMASK(hw, 0x10), 2008145256Sjkoshy PMCMASK(both, 0x30), 2009145256Sjkoshy NULLMASK 2010145256Sjkoshy}; 2011145256Sjkoshy 2012145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 2013145256Sjkoshy PMCMASK(nonhw, 0x00), 2014145256Sjkoshy PMCMASK(hw, 0x10), 2015145256Sjkoshy PMCMASK(both, 0x30), 2016145256Sjkoshy NULLMASK 2017145256Sjkoshy}; 2018145256Sjkoshy 2019145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 2020145256Sjkoshy PMCMASK(self, 0x00), 2021145256Sjkoshy PMCMASK(any, 0x20), 2022145256Sjkoshy NULLMASK 2023145256Sjkoshy}; 2024145256Sjkoshy 2025145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 2026145256Sjkoshy PMCMASK(nta, 0x00), 2027145256Sjkoshy PMCMASK(t1, 0x01), 2028145256Sjkoshy PMCMASK(t2, 0x02), 2029145256Sjkoshy PMCMASK(wos, 0x03), 2030145256Sjkoshy NULLMASK 2031145256Sjkoshy}; 2032145256Sjkoshy 2033145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 2034145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 2035145256Sjkoshy PMCMASK(scalar, 0x01), 2036145256Sjkoshy NULLMASK 2037145256Sjkoshy}; 2038145256Sjkoshy 2039145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 2040145256Sjkoshy PMCMASK(packed-multiply, 0x01), 2041145256Sjkoshy PMCMASK(packed-shift, 0x02), 2042145256Sjkoshy PMCMASK(pack, 0x04), 2043145256Sjkoshy PMCMASK(unpack, 0x08), 2044145256Sjkoshy PMCMASK(packed-logical, 0x10), 2045145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 2046145256Sjkoshy NULLMASK 2047145256Sjkoshy}; 2048145256Sjkoshy 2049145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 2050145256Sjkoshy PMCMASK(mmxtofp, 0x00), 2051145256Sjkoshy PMCMASK(fptommx, 0x01), 2052145256Sjkoshy NULLMASK 2053145256Sjkoshy}; 2054145256Sjkoshy 2055145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 2056145256Sjkoshy PMCMASK(es, 0x01), 2057145256Sjkoshy PMCMASK(ds, 0x02), 2058145256Sjkoshy PMCMASK(fs, 0x04), 2059145256Sjkoshy PMCMASK(gs, 0x08), 2060145256Sjkoshy NULLMASK 2061145256Sjkoshy}; 2062145256Sjkoshy 2063145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 2064145256Sjkoshy PMCMASK(all, 0x00), 2065145256Sjkoshy PMCMASK(freq, 0x02), 2066145256Sjkoshy NULLMASK 2067145256Sjkoshy}; 2068145256Sjkoshy 2069145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 2070145256Sjkoshy PMCMASK(all, 0x00), 2071145256Sjkoshy PMCMASK(loadop, 0x01), 2072145256Sjkoshy PMCMASK(stdsta, 0x02), 2073145256Sjkoshy NULLMASK 2074145256Sjkoshy}; 2075145256Sjkoshy 2076145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 2077145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2078145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 2079145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2080145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2081145256Sjkoshy NULLMASK 2082145256Sjkoshy}; 2083145256Sjkoshy 2084145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 2085145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 2086145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 2087145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 2088145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 2089145256Sjkoshy NULLMASK 2090145256Sjkoshy}; 2091145256Sjkoshy 2092145256Sjkoshy/* P6 event parser */ 2093145256Sjkoshystatic int 2094145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 2095145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2096145256Sjkoshy{ 2097145256Sjkoshy char *e, *p, *q; 2098240164Sfabient uint64_t evmask; 2099145256Sjkoshy int count, n; 2100145256Sjkoshy const struct pmc_masks *pm, *pmask; 2101145256Sjkoshy 2102183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2103147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 2104145256Sjkoshy 2105145256Sjkoshy evmask = 0; 2106145256Sjkoshy 2107145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 2108145256Sjkoshy 2109145256Sjkoshy switch(pe) { 2110183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 2111145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 2112145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 2113145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 2114145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2115145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2116145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2117145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2118145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2119145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2120145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2121145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2122145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2123145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2124145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2125145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2126145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2127145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2128145256Sjkoshy P6MASKSET(any); break; 2129145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2130145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2131145256Sjkoshy P6MASKSET(ekp); break; 2132145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2133145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2134145256Sjkoshy P6MASKSET(pps); break; 2135145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 2136145256Sjkoshy P6MASKSET(mite); break; 2137145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2138145256Sjkoshy P6MASKSET(fmt); break; 2139145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 2140145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 2141145256Sjkoshy P6MASKSET(sr); break; 2142145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2143145256Sjkoshy P6MASKSET(eet); break; 2144145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2145145256Sjkoshy P6MASKSET(efur); break; 2146145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2147145256Sjkoshy P6MASKSET(essir); break; 2148145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2149145256Sjkoshy P6MASKSET(esscir); break; 2150145256Sjkoshy default: 2151145256Sjkoshy pmask = NULL; 2152145256Sjkoshy break; 2153145256Sjkoshy } 2154145256Sjkoshy 2155145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2156145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2157145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2158145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2159145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2160145256Sjkoshy P6MASKSET(mesihw); 2161145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2162145256Sjkoshy P6MASKSET(hw); 2163145256Sjkoshy } 2164145256Sjkoshy 2165145256Sjkoshy /* Parse additional modifiers if present */ 2166145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2167145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2168145256Sjkoshy q = strchr(p, '='); 2169145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2170174406Sjkoshy return (-1); 2171145256Sjkoshy count = strtol(q, &e, 0); 2172145256Sjkoshy if (e == q || *e != '\0') 2173174406Sjkoshy return (-1); 2174145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2175147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2176147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2177145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2178145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2179145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2180145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2181145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2182145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2183145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2184145256Sjkoshy evmask = 0; 2185145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2186174406Sjkoshy return (-1); 2187145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2188145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2189145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2190145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2191145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2192145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2193145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2194145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2195145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2196145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2197145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2198145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2199145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2200145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2201145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2202145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2203145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2204145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2205145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2206145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2207145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2208145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2209145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2210174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2211174406Sjkoshy return (-1); 2212145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2213145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2214145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2215145256Sjkoshy } else 2216174406Sjkoshy return (-1); 2217145256Sjkoshy } 2218145256Sjkoshy 2219145256Sjkoshy /* post processing */ 2220145256Sjkoshy switch (pe) { 2221145256Sjkoshy 2222145256Sjkoshy /* 2223145256Sjkoshy * The following events default to an evmask of 0 2224145256Sjkoshy */ 2225145256Sjkoshy 2226145256Sjkoshy /* default => 'self' */ 2227145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2228145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2229145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2230145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2231145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2232145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2233145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2234145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2235145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2236145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2237145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2238145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2239145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2240145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2241145256Sjkoshy 2242145256Sjkoshy /* default => 'nta' */ 2243145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2244145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2245145256Sjkoshy 2246145256Sjkoshy /* default => 'packed and scalar' */ 2247145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2248145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2249145256Sjkoshy 2250145256Sjkoshy /* default => 'mmx to fp transitions' */ 2251145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2252145256Sjkoshy 2253145256Sjkoshy /* default => 'SSE Packed Single' */ 2254145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2255145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2256145256Sjkoshy 2257145256Sjkoshy /* default => 'all fused micro-ops' */ 2258145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2259145256Sjkoshy 2260145256Sjkoshy /* default => 'all transitions' */ 2261145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2262145256Sjkoshy break; 2263145256Sjkoshy 2264145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2265145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2266145256Sjkoshy break; 2267145256Sjkoshy 2268145256Sjkoshy default: 2269145256Sjkoshy /* 2270145256Sjkoshy * For all other events, set the default event mask 2271145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2272145256Sjkoshy */ 2273145256Sjkoshy if (evmask == 0 && pmask) { 2274145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2275145256Sjkoshy evmask |= pm->pm_value; 2276145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2277145256Sjkoshy } 2278145256Sjkoshy 2279145256Sjkoshy break; 2280145256Sjkoshy } 2281145256Sjkoshy 2282145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2283147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2284147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2285145256Sjkoshy 2286174406Sjkoshy return (0); 2287145256Sjkoshy} 2288145256Sjkoshy 2289147191Sjkoshy#endif 2290147191Sjkoshy 2291183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2292183725Sjkoshystatic int 2293183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2294183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2295183725Sjkoshy{ 2296183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2297183725Sjkoshy return (-1); 2298183725Sjkoshy 2299183725Sjkoshy /* TSC events must be unqualified. */ 2300183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2301183725Sjkoshy return (-1); 2302183725Sjkoshy 2303183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2304183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2305183725Sjkoshy 2306183725Sjkoshy return (0); 2307183725Sjkoshy} 2308183725Sjkoshy#endif 2309183725Sjkoshy 2310233628Sfabientstatic struct pmc_event_alias generic_aliases[] = { 2311233628Sfabient EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), 2312233628Sfabient EV_ALIAS(NULL, NULL) 2313233628Sfabient}; 2314233628Sfabient 2315233628Sfabientstatic int 2316233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec, 2317233628Sfabient struct pmc_op_pmcallocate *pmc_config) 2318233628Sfabient{ 2319233628Sfabient (void)ctrspec; 2320233628Sfabient (void)pmc_config; 2321233628Sfabient 2322242622Sdim if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST) 2323233628Sfabient return (-1); 2324233628Sfabient 2325233628Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2326233628Sfabient return (0); 2327233628Sfabient} 2328233628Sfabient 2329200928Srpaulo#if defined(__XSCALE__) 2330200928Srpaulo 2331200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2332200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2333200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2334200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2335200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2336200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2337200928Srpaulo EV_ALIAS(NULL, NULL) 2338200928Srpaulo}; 2339200928Srpaulostatic int 2340200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2341200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2342200928Srpaulo{ 2343200928Srpaulo switch (pe) { 2344200928Srpaulo default: 2345200928Srpaulo break; 2346200928Srpaulo } 2347200928Srpaulo 2348200928Srpaulo return (0); 2349200928Srpaulo} 2350200928Srpaulo#endif 2351200928Srpaulo 2352204635Sgnn#if defined(__mips__) 2353204635Sgnn 2354204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2355204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2356204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2357204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2358204635Sgnn EV_ALIAS(NULL, NULL) 2359204635Sgnn}; 2360204635Sgnn 2361233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = { 2362233335Sgonzo EV_ALIAS("instructions", "RET"), 2363233335Sgonzo EV_ALIAS("branches", "BR"), 2364233335Sgonzo EV_ALIAS("branch-mispredicts", "BRMIS"), 2365233335Sgonzo EV_ALIAS(NULL, NULL) 2366233335Sgonzo}; 2367233335Sgonzo 2368233320Sgonzo#define MIPS_KW_OS "os" 2369233320Sgonzo#define MIPS_KW_USR "usr" 2370233320Sgonzo#define MIPS_KW_ANYTHREAD "anythread" 2371204635Sgnn 2372204635Sgnnstatic int 2373233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2374204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2375204635Sgnn{ 2376204635Sgnn char *p; 2377204635Sgnn 2378204635Sgnn (void) pe; 2379204635Sgnn 2380204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2381204635Sgnn 2382204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2383233320Sgonzo if (KWMATCH(p, MIPS_KW_OS)) 2384204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2385233320Sgonzo else if (KWMATCH(p, MIPS_KW_USR)) 2386204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2387233320Sgonzo else if (KWMATCH(p, MIPS_KW_ANYTHREAD)) 2388204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2389204635Sgnn else 2390204635Sgnn return (-1); 2391204635Sgnn } 2392204635Sgnn 2393204635Sgnn return (0); 2394204635Sgnn} 2395233320Sgonzo 2396204635Sgnn#endif /* __mips__ */ 2397204635Sgnn 2398228869Sjhibbits#if defined(__powerpc__) 2399204635Sgnn 2400228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = { 2401228869Sjhibbits EV_ALIAS("instructions", "INSTR_COMPLETED"), 2402228869Sjhibbits EV_ALIAS("branches", "BRANCHES_COMPLETED"), 2403228869Sjhibbits EV_ALIAS("branch-mispredicts", "MISPREDICTED_BRANCHES"), 2404228869Sjhibbits EV_ALIAS(NULL, NULL) 2405228869Sjhibbits}; 2406228869Sjhibbits 2407228869Sjhibbits#define PPC7450_KW_OS "os" 2408228869Sjhibbits#define PPC7450_KW_USR "usr" 2409228869Sjhibbits#define PPC7450_KW_ANYTHREAD "anythread" 2410228869Sjhibbits 2411228869Sjhibbitsstatic int 2412228869Sjhibbitsppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2413228869Sjhibbits struct pmc_op_pmcallocate *pmc_config __unused) 2414228869Sjhibbits{ 2415228869Sjhibbits char *p; 2416228869Sjhibbits 2417228869Sjhibbits (void) pe; 2418228869Sjhibbits 2419228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2420228869Sjhibbits 2421228869Sjhibbits while ((p = strsep(&ctrspec, ",")) != NULL) { 2422228869Sjhibbits if (KWMATCH(p, PPC7450_KW_OS)) 2423228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2424228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_USR)) 2425228869Sjhibbits pmc_config->pm_caps |= PMC_CAP_USER; 2426228869Sjhibbits else if (KWMATCH(p, PPC7450_KW_ANYTHREAD)) 2427228869Sjhibbits pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2428228869Sjhibbits else 2429228869Sjhibbits return (-1); 2430228869Sjhibbits } 2431228869Sjhibbits 2432228869Sjhibbits return (0); 2433228869Sjhibbits} 2434228869Sjhibbits#endif /* __powerpc__ */ 2435228869Sjhibbits 2436228869Sjhibbits 2437145256Sjkoshy/* 2438183725Sjkoshy * Match an event name `name' with its canonical form. 2439183725Sjkoshy * 2440185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2441185363Sjkoshy * hyphen characters are considered to match each other. 2442185363Sjkoshy * 2443183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2444183725Sjkoshy */ 2445183725Sjkoshy 2446183725Sjkoshystatic int 2447183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2448183725Sjkoshy{ 2449183725Sjkoshy int cc, nc; 2450183725Sjkoshy const unsigned char *c, *n; 2451183725Sjkoshy 2452183725Sjkoshy c = (const unsigned char *) canonicalname; 2453183725Sjkoshy n = (const unsigned char *) name; 2454183725Sjkoshy 2455183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2456183725Sjkoshy 2457185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2458185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2459183725Sjkoshy continue; 2460183725Sjkoshy 2461185363Sjkoshy if (toupper(nc) == toupper(cc)) 2462183725Sjkoshy continue; 2463183725Sjkoshy 2464185363Sjkoshy 2465183725Sjkoshy return (0); 2466183725Sjkoshy } 2467183725Sjkoshy 2468183725Sjkoshy if (*n == '\0' && *c == '\0') 2469183725Sjkoshy return (1); 2470183725Sjkoshy 2471183725Sjkoshy return (0); 2472183725Sjkoshy} 2473183725Sjkoshy 2474183725Sjkoshy/* 2475183725Sjkoshy * Match an event name against all the event named supported by a 2476183725Sjkoshy * PMC class. 2477183725Sjkoshy * 2478183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2479183725Sjkoshy */ 2480183725Sjkoshystatic const struct pmc_event_descr * 2481183725Sjkoshypmc_match_event_class(const char *name, 2482183725Sjkoshy const struct pmc_class_descr *pcd) 2483183725Sjkoshy{ 2484183725Sjkoshy size_t n; 2485183725Sjkoshy const struct pmc_event_descr *ev; 2486185363Sjkoshy 2487183725Sjkoshy ev = pcd->pm_evc_event_table; 2488183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2489183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2490183725Sjkoshy return (ev); 2491183725Sjkoshy 2492183725Sjkoshy return (NULL); 2493183725Sjkoshy} 2494183725Sjkoshy 2495183725Sjkoshystatic int 2496183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2497183725Sjkoshy{ 2498183725Sjkoshy size_t n; 2499183725Sjkoshy 2500183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2501183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2502183725Sjkoshy return (1); 2503183725Sjkoshy return (0); 2504183725Sjkoshy} 2505183725Sjkoshy 2506183725Sjkoshy/* 2507147191Sjkoshy * API entry points 2508145256Sjkoshy */ 2509145256Sjkoshy 2510147191Sjkoshyint 2511147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2512147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2513145256Sjkoshy{ 2514183725Sjkoshy size_t n; 2515147191Sjkoshy int retval; 2516147191Sjkoshy char *r, *spec_copy; 2517147191Sjkoshy const char *ctrname; 2518183725Sjkoshy const struct pmc_event_descr *ev; 2519183725Sjkoshy const struct pmc_event_alias *alias; 2520147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2521183725Sjkoshy const struct pmc_class_descr *pcd; 2522145256Sjkoshy 2523147191Sjkoshy spec_copy = NULL; 2524147191Sjkoshy retval = -1; 2525145256Sjkoshy 2526147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2527147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2528147191Sjkoshy errno = EINVAL; 2529147191Sjkoshy goto out; 2530147191Sjkoshy } 2531145256Sjkoshy 2532147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2533147191Sjkoshy if (pmc_mdep_event_aliases) 2534183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2535183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2536183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2537147191Sjkoshy break; 2538147191Sjkoshy } 2539145256Sjkoshy 2540147191Sjkoshy if (spec_copy == NULL) 2541147191Sjkoshy spec_copy = strdup(ctrspec); 2542145256Sjkoshy 2543147191Sjkoshy r = spec_copy; 2544147191Sjkoshy ctrname = strsep(&r, ","); 2545145256Sjkoshy 2546183725Sjkoshy /* 2547183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2548183725Sjkoshy * search for the event to the specified PMC class. 2549183725Sjkoshy */ 2550183725Sjkoshy ev = NULL; 2551185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2552185363Sjkoshy pcd = pmc_class_table[n]; 2553183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2554183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2555183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2556183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2557183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2558183725Sjkoshy errno = EINVAL; 2559183725Sjkoshy goto out; 2560183725Sjkoshy } 2561147191Sjkoshy break; 2562183725Sjkoshy } 2563183725Sjkoshy } 2564145256Sjkoshy 2565183725Sjkoshy /* 2566183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2567183725Sjkoshy * classes. 2568183725Sjkoshy */ 2569185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2570185363Sjkoshy pcd = pmc_class_table[n]; 2571183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2572183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2573183725Sjkoshy } 2574183725Sjkoshy 2575183725Sjkoshy if (ev == NULL) { 2576147191Sjkoshy errno = EINVAL; 2577147191Sjkoshy goto out; 2578147191Sjkoshy } 2579145256Sjkoshy 2580147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2581183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2582183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2583147191Sjkoshy pmc_config.pm_cpu = cpu; 2584147191Sjkoshy pmc_config.pm_mode = mode; 2585147191Sjkoshy pmc_config.pm_flags = flags; 2586145256Sjkoshy 2587147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2588147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2589145256Sjkoshy 2590183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2591147191Sjkoshy errno = EINVAL; 2592147191Sjkoshy goto out; 2593147191Sjkoshy } 2594145256Sjkoshy 2595147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2596147191Sjkoshy goto out; 2597145256Sjkoshy 2598147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2599145256Sjkoshy 2600147191Sjkoshy retval = 0; 2601145256Sjkoshy 2602147191Sjkoshy out: 2603147191Sjkoshy if (spec_copy) 2604147191Sjkoshy free(spec_copy); 2605145256Sjkoshy 2606174406Sjkoshy return (retval); 2607147191Sjkoshy} 2608145256Sjkoshy 2609147191Sjkoshyint 2610147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2611147191Sjkoshy{ 2612147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2613145256Sjkoshy 2614147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2615147191Sjkoshy pmc_attach_args.pm_pid = pid; 2616145256Sjkoshy 2617174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2618147191Sjkoshy} 2619145256Sjkoshy 2620147191Sjkoshyint 2621147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2622147191Sjkoshy{ 2623147191Sjkoshy unsigned int i; 2624147191Sjkoshy enum pmc_class cl; 2625145256Sjkoshy 2626147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2627147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2628147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2629147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2630174406Sjkoshy return (0); 2631147191Sjkoshy } 2632177107Sjkoshy errno = EINVAL; 2633177107Sjkoshy return (-1); 2634147191Sjkoshy} 2635145256Sjkoshy 2636147191Sjkoshyint 2637147191Sjkoshypmc_configure_logfile(int fd) 2638147191Sjkoshy{ 2639147191Sjkoshy struct pmc_op_configurelog cla; 2640145256Sjkoshy 2641147191Sjkoshy cla.pm_logfd = fd; 2642147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2643174406Sjkoshy return (-1); 2644174406Sjkoshy return (0); 2645147191Sjkoshy} 2646145256Sjkoshy 2647147191Sjkoshyint 2648147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2649147191Sjkoshy{ 2650147191Sjkoshy if (pmc_syscall == -1) { 2651147191Sjkoshy errno = ENXIO; 2652174406Sjkoshy return (-1); 2653147191Sjkoshy } 2654145256Sjkoshy 2655147219Sjkoshy *pci = &cpu_info; 2656174406Sjkoshy return (0); 2657147191Sjkoshy} 2658145256Sjkoshy 2659147191Sjkoshyint 2660147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2661147191Sjkoshy{ 2662147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2663145256Sjkoshy 2664147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2665147191Sjkoshy pmc_detach_args.pm_pid = pid; 2666174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2667147191Sjkoshy} 2668147191Sjkoshy 2669147191Sjkoshyint 2670147191Sjkoshypmc_disable(int cpu, int pmc) 2671145256Sjkoshy{ 2672147191Sjkoshy struct pmc_op_pmcadmin ssa; 2673145256Sjkoshy 2674147191Sjkoshy ssa.pm_cpu = cpu; 2675147191Sjkoshy ssa.pm_pmc = pmc; 2676147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2677174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2678147191Sjkoshy} 2679145256Sjkoshy 2680147191Sjkoshyint 2681147191Sjkoshypmc_enable(int cpu, int pmc) 2682147191Sjkoshy{ 2683147191Sjkoshy struct pmc_op_pmcadmin ssa; 2684145256Sjkoshy 2685147191Sjkoshy ssa.pm_cpu = cpu; 2686147191Sjkoshy ssa.pm_pmc = pmc; 2687147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2688174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2689147191Sjkoshy} 2690145256Sjkoshy 2691147191Sjkoshy/* 2692147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2693147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2694147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2695147191Sjkoshy * the number of event name pointers returned. 2696147191Sjkoshy * 2697147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2698147191Sjkoshy * is responsible for freeing this space when done. 2699147191Sjkoshy */ 2700147191Sjkoshyint 2701147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2702147191Sjkoshy int *nevents) 2703147191Sjkoshy{ 2704147191Sjkoshy int count; 2705147191Sjkoshy const char **names; 2706147191Sjkoshy const struct pmc_event_descr *ev; 2707147191Sjkoshy 2708147191Sjkoshy switch (cl) 2709147191Sjkoshy { 2710185363Sjkoshy case PMC_CLASS_IAF: 2711185363Sjkoshy ev = iaf_event_table; 2712185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2713185363Sjkoshy break; 2714185363Sjkoshy case PMC_CLASS_IAP: 2715185363Sjkoshy /* 2716185363Sjkoshy * Return the most appropriate set of event name 2717185363Sjkoshy * spellings for the current CPU. 2718185363Sjkoshy */ 2719185363Sjkoshy switch (cpu_info.pm_cputype) { 2720185363Sjkoshy default: 2721185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2722185363Sjkoshy ev = atom_event_table; 2723185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2724185363Sjkoshy break; 2725185363Sjkoshy case PMC_CPU_INTEL_CORE: 2726185363Sjkoshy ev = core_event_table; 2727185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2728185363Sjkoshy break; 2729185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2730185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2731185363Sjkoshy ev = core2_event_table; 2732185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2733185363Sjkoshy break; 2734187761Sjeff case PMC_CPU_INTEL_COREI7: 2735187761Sjeff ev = corei7_event_table; 2736187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2737187761Sjeff break; 2738248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2739248842Ssbruno ev = haswell_event_table; 2740248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswell); 2741248842Ssbruno break; 2742240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 2743240164Sfabient ev = ivybridge_event_table; 2744240164Sfabient count = PMC_EVENT_TABLE_SIZE(ivybridge); 2745240164Sfabient break; 2746246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 2747246166Ssbruno ev = ivybridge_xeon_event_table; 2748246166Ssbruno count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 2749246166Ssbruno break; 2750232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2751232366Sdavide ev = sandybridge_event_table; 2752232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridge); 2753232366Sdavide break; 2754241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 2755241738Ssbruno ev = sandybridge_xeon_event_table; 2756241738Ssbruno count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 2757241738Ssbruno break; 2758206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2759206089Sfabient ev = westmere_event_table; 2760206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2761206089Sfabient break; 2762185363Sjkoshy } 2763185363Sjkoshy break; 2764206089Sfabient case PMC_CLASS_UCF: 2765206089Sfabient ev = ucf_event_table; 2766206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2767206089Sfabient break; 2768206089Sfabient case PMC_CLASS_UCP: 2769206089Sfabient /* 2770206089Sfabient * Return the most appropriate set of event name 2771206089Sfabient * spellings for the current CPU. 2772206089Sfabient */ 2773206089Sfabient switch (cpu_info.pm_cputype) { 2774206089Sfabient default: 2775206089Sfabient case PMC_CPU_INTEL_COREI7: 2776206089Sfabient ev = corei7uc_event_table; 2777206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2778206089Sfabient break; 2779248842Ssbruno case PMC_CPU_INTEL_HASWELL: 2780248842Ssbruno ev = haswelluc_event_table; 2781248842Ssbruno count = PMC_EVENT_TABLE_SIZE(haswelluc); 2782248842Ssbruno break; 2783232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 2784232366Sdavide ev = sandybridgeuc_event_table; 2785232366Sdavide count = PMC_EVENT_TABLE_SIZE(sandybridgeuc); 2786232366Sdavide break; 2787206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2788206089Sfabient ev = westmereuc_event_table; 2789206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2790206089Sfabient break; 2791206089Sfabient } 2792206089Sfabient break; 2793147191Sjkoshy case PMC_CLASS_TSC: 2794183725Sjkoshy ev = tsc_event_table; 2795183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2796145256Sjkoshy break; 2797147191Sjkoshy case PMC_CLASS_K7: 2798183725Sjkoshy ev = k7_event_table; 2799183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2800145256Sjkoshy break; 2801147191Sjkoshy case PMC_CLASS_K8: 2802183725Sjkoshy ev = k8_event_table; 2803183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2804145256Sjkoshy break; 2805183725Sjkoshy case PMC_CLASS_P4: 2806183725Sjkoshy ev = p4_event_table; 2807183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2808183725Sjkoshy break; 2809147191Sjkoshy case PMC_CLASS_P5: 2810183725Sjkoshy ev = p5_event_table; 2811183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2812145256Sjkoshy break; 2813147191Sjkoshy case PMC_CLASS_P6: 2814183725Sjkoshy ev = p6_event_table; 2815183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2816145256Sjkoshy break; 2817200928Srpaulo case PMC_CLASS_XSCALE: 2818200928Srpaulo ev = xscale_event_table; 2819200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2820200928Srpaulo break; 2821204635Sgnn case PMC_CLASS_MIPS24K: 2822204635Sgnn ev = mips24k_event_table; 2823204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2824204635Sgnn break; 2825233335Sgonzo case PMC_CLASS_OCTEON: 2826233335Sgonzo ev = octeon_event_table; 2827233335Sgonzo count = PMC_EVENT_TABLE_SIZE(octeon); 2828233335Sgonzo break; 2829228869Sjhibbits case PMC_CLASS_PPC7450: 2830228869Sjhibbits ev = ppc7450_event_table; 2831228869Sjhibbits count = PMC_EVENT_TABLE_SIZE(ppc7450); 2832228869Sjhibbits break; 2833233628Sfabient case PMC_CLASS_SOFT: 2834233628Sfabient ev = soft_event_table; 2835233628Sfabient count = soft_event_info.pm_nevent; 2836233628Sfabient break; 2837145256Sjkoshy default: 2838147191Sjkoshy errno = EINVAL; 2839174406Sjkoshy return (-1); 2840145256Sjkoshy } 2841145256Sjkoshy 2842147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2843174406Sjkoshy return (-1); 2844145256Sjkoshy 2845147191Sjkoshy *eventnames = names; 2846147191Sjkoshy *nevents = count; 2847145256Sjkoshy 2848147191Sjkoshy for (;count--; ev++, names++) 2849147191Sjkoshy *names = ev->pm_ev_name; 2850233628Sfabient 2851174406Sjkoshy return (0); 2852147191Sjkoshy} 2853145256Sjkoshy 2854147191Sjkoshyint 2855147191Sjkoshypmc_flush_logfile(void) 2856147191Sjkoshy{ 2857174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2858147191Sjkoshy} 2859145256Sjkoshy 2860147191Sjkoshyint 2861226514Sfabientpmc_close_logfile(void) 2862226514Sfabient{ 2863226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2864226514Sfabient} 2865226514Sfabient 2866226514Sfabientint 2867147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2868147191Sjkoshy{ 2869147191Sjkoshy struct pmc_op_getdriverstats gms; 2870145256Sjkoshy 2871147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2872174406Sjkoshy return (-1); 2873145256Sjkoshy 2874147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2875147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2876147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2877147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2878147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2879147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2880147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2881147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2882147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2883174406Sjkoshy return (0); 2884147191Sjkoshy} 2885145256Sjkoshy 2886147191Sjkoshyint 2887147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2888147191Sjkoshy{ 2889147191Sjkoshy struct pmc_op_getmsr gm; 2890147191Sjkoshy 2891147191Sjkoshy gm.pm_pmcid = pmc; 2892147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2893174406Sjkoshy return (-1); 2894147191Sjkoshy *msr = gm.pm_msr; 2895174406Sjkoshy return (0); 2896145256Sjkoshy} 2897145256Sjkoshy 2898145256Sjkoshyint 2899145256Sjkoshypmc_init(void) 2900145256Sjkoshy{ 2901145256Sjkoshy int error, pmc_mod_id; 2902147219Sjkoshy unsigned int n; 2903145256Sjkoshy uint32_t abi_version; 2904145256Sjkoshy struct module_stat pmc_modstat; 2905147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2906198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2907198433Sjkoshy int cpu_has_iaf_counters; 2908198433Sjkoshy unsigned int t; 2909198433Sjkoshy#endif 2910145256Sjkoshy 2911145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2912174406Sjkoshy return (0); 2913145256Sjkoshy 2914145256Sjkoshy /* retrieve the system call number from the KLD */ 2915145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2916174406Sjkoshy return (-1); 2917145256Sjkoshy 2918145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2919145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2920174406Sjkoshy return (-1); 2921145256Sjkoshy 2922145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2923145256Sjkoshy 2924147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2925147191Sjkoshy abi_version = PMC_VERSION; 2926145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2927145256Sjkoshy return (pmc_syscall = -1); 2928145256Sjkoshy 2929147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2930147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2931145256Sjkoshy errno = EPROGMISMATCH; 2932145256Sjkoshy return (pmc_syscall = -1); 2933145256Sjkoshy } 2934145256Sjkoshy 2935147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2936145256Sjkoshy return (pmc_syscall = -1); 2937145256Sjkoshy 2938147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2939147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2940147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2941147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2942147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2943147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2944147219Sjkoshy 2945185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2946185363Sjkoshy sizeof(struct pmc_class_descr *)); 2947185363Sjkoshy 2948185363Sjkoshy if (pmc_class_table == NULL) 2949185363Sjkoshy return (-1); 2950185363Sjkoshy 2951198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2952198433Sjkoshy pmc_class_table[n] = NULL; 2953185363Sjkoshy 2954185363Sjkoshy /* 2955233628Sfabient * Get soft events list. 2956233628Sfabient */ 2957233628Sfabient soft_event_info.pm_class = PMC_CLASS_SOFT; 2958233628Sfabient if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0) 2959233628Sfabient return (pmc_syscall = -1); 2960233628Sfabient 2961233628Sfabient /* Map soft events to static list. */ 2962233628Sfabient for (n = 0; n < soft_event_info.pm_nevent; n++) { 2963233628Sfabient soft_event_table[n].pm_ev_name = 2964233628Sfabient soft_event_info.pm_events[n].pm_ev_name; 2965233628Sfabient soft_event_table[n].pm_ev_code = 2966233628Sfabient soft_event_info.pm_events[n].pm_ev_code; 2967233628Sfabient } 2968233628Sfabient soft_class_table_descr.pm_evc_event_table_size = \ 2969233628Sfabient soft_event_info.pm_nevent; 2970233628Sfabient soft_class_table_descr.pm_evc_event_table = \ 2971233628Sfabient soft_event_table; 2972233628Sfabient 2973233628Sfabient /* 2974185363Sjkoshy * Fill in the class table. 2975185363Sjkoshy */ 2976185363Sjkoshy n = 0; 2977233628Sfabient 2978233628Sfabient /* Fill soft events information. */ 2979233628Sfabient pmc_class_table[n++] = &soft_class_table_descr; 2980185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2981233628Sfabient if (cpu_info.pm_cputype != PMC_CPU_GENERIC) 2982233628Sfabient pmc_class_table[n++] = &tsc_class_table_descr; 2983198433Sjkoshy 2984198433Sjkoshy /* 2985198433Sjkoshy * Check if this CPU has fixed function counters. 2986198433Sjkoshy */ 2987198433Sjkoshy cpu_has_iaf_counters = 0; 2988198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2989212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 2990212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 2991198433Sjkoshy cpu_has_iaf_counters = 1; 2992185363Sjkoshy#endif 2993185363Sjkoshy 2994183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2995183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2996183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2997183725Sjkoshy pmc_mdep_class_list_size = \ 2998183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2999183725Sjkoshy } while (0) 3000183725Sjkoshy 3001198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 3002198433Sjkoshy PMC_MDEP_INIT(C); \ 3003212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 3004212224Sfabient if (!cpu_has_iaf_counters) \ 3005198433Sjkoshy pmc_mdep_event_aliases = \ 3006198433Sjkoshy C##_aliases_without_iaf; \ 3007198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 3008198433Sjkoshy } while (0) 3009198433Sjkoshy 3010183725Sjkoshy /* Configure the event name parser. */ 3011145256Sjkoshy switch (cpu_info.pm_cputype) { 3012145340Smarcel#if defined(__i386__) 3013145256Sjkoshy case PMC_CPU_AMD_K7: 3014183725Sjkoshy PMC_MDEP_INIT(k7); 3015185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 3016145256Sjkoshy break; 3017145256Sjkoshy case PMC_CPU_INTEL_P5: 3018183725Sjkoshy PMC_MDEP_INIT(p5); 3019185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 3020145256Sjkoshy break; 3021145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 3022145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 3023145256Sjkoshy case PMC_CPU_INTEL_PIII: 3024145256Sjkoshy case PMC_CPU_INTEL_PM: 3025183725Sjkoshy PMC_MDEP_INIT(p6); 3026185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 3027145256Sjkoshy break; 3028147759Sjkoshy#endif 3029147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 3030183725Sjkoshy case PMC_CPU_AMD_K8: 3031183725Sjkoshy PMC_MDEP_INIT(k8); 3032185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 3033183725Sjkoshy break; 3034185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3035198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 3036185363Sjkoshy break; 3037185363Sjkoshy case PMC_CPU_INTEL_CORE: 3038185363Sjkoshy PMC_MDEP_INIT(core); 3039202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 3040185363Sjkoshy break; 3041185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3042185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3043198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 3044185363Sjkoshy break; 3045187761Sjeff case PMC_CPU_INTEL_COREI7: 3046206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3047206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 3048198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 3049187761Sjeff break; 3050248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3051248842Ssbruno pmc_class_table[n++] = &ucf_class_table_descr; 3052248842Ssbruno pmc_class_table[n++] = &haswelluc_class_table_descr; 3053248842Ssbruno PMC_MDEP_INIT_INTEL_V2(haswell); 3054248842Ssbruno break; 3055240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3056240164Sfabient PMC_MDEP_INIT_INTEL_V2(ivybridge); 3057240164Sfabient break; 3058246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3059246166Ssbruno PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon); 3060246166Ssbruno break; 3061232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3062232366Sdavide pmc_class_table[n++] = &ucf_class_table_descr; 3063232366Sdavide pmc_class_table[n++] = &sandybridgeuc_class_table_descr; 3064232366Sdavide PMC_MDEP_INIT_INTEL_V2(sandybridge); 3065232366Sdavide break; 3066241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3067241738Ssbruno PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon); 3068241738Ssbruno break; 3069206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3070206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 3071206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 3072206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 3073206089Sfabient break; 3074145256Sjkoshy case PMC_CPU_INTEL_PIV: 3075183725Sjkoshy PMC_MDEP_INIT(p4); 3076185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 3077145256Sjkoshy break; 3078145256Sjkoshy#endif 3079233628Sfabient case PMC_CPU_GENERIC: 3080233628Sfabient PMC_MDEP_INIT(generic); 3081233628Sfabient break; 3082200928Srpaulo#if defined(__XSCALE__) 3083200928Srpaulo case PMC_CPU_INTEL_XSCALE: 3084200928Srpaulo PMC_MDEP_INIT(xscale); 3085200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 3086200928Srpaulo break; 3087200928Srpaulo#endif 3088204635Sgnn#if defined(__mips__) 3089204635Sgnn case PMC_CPU_MIPS_24K: 3090204635Sgnn PMC_MDEP_INIT(mips24k); 3091204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 3092204635Sgnn break; 3093233335Sgonzo case PMC_CPU_MIPS_OCTEON: 3094233335Sgonzo PMC_MDEP_INIT(octeon); 3095233335Sgonzo pmc_class_table[n] = &octeon_class_table_descr; 3096233335Sgonzo break; 3097204635Sgnn#endif /* __mips__ */ 3098228869Sjhibbits#if defined(__powerpc__) 3099228869Sjhibbits case PMC_CPU_PPC_7450: 3100228869Sjhibbits PMC_MDEP_INIT(ppc7450); 3101228869Sjhibbits pmc_class_table[n] = &ppc7450_class_table_descr; 3102228869Sjhibbits break; 3103228869Sjhibbits#endif 3104145256Sjkoshy default: 3105145256Sjkoshy /* 3106145256Sjkoshy * Some kind of CPU this version of the library knows nothing 3107145256Sjkoshy * about. This shouldn't happen since the abi version check 3108145256Sjkoshy * should have caught this. 3109145256Sjkoshy */ 3110145256Sjkoshy errno = ENXIO; 3111145256Sjkoshy return (pmc_syscall = -1); 3112145256Sjkoshy } 3113145256Sjkoshy 3114174406Sjkoshy return (0); 3115145256Sjkoshy} 3116145256Sjkoshy 3117147191Sjkoshyconst char * 3118147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 3119145256Sjkoshy{ 3120147191Sjkoshy int i; 3121145256Sjkoshy 3122147191Sjkoshy /* 3123147191Sjkoshy * 'cap' should have a single bit set and should be in 3124147191Sjkoshy * range. 3125147191Sjkoshy */ 3126147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 3127147191Sjkoshy cap > PMC_CAP_LAST) { 3128145256Sjkoshy errno = EINVAL; 3129174406Sjkoshy return (NULL); 3130145256Sjkoshy } 3131145256Sjkoshy 3132147191Sjkoshy i = ffs(cap); 3133174406Sjkoshy return (pmc_capability_names[i - 1]); 3134147191Sjkoshy} 3135145256Sjkoshy 3136147191Sjkoshyconst char * 3137147191Sjkoshypmc_name_of_class(enum pmc_class pc) 3138147191Sjkoshy{ 3139147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 3140147191Sjkoshy pc <= PMC_CLASS_LAST) 3141174406Sjkoshy return (pmc_class_names[pc]); 3142145256Sjkoshy 3143147191Sjkoshy errno = EINVAL; 3144174406Sjkoshy return (NULL); 3145147191Sjkoshy} 3146145256Sjkoshy 3147147191Sjkoshyconst char * 3148147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 3149147191Sjkoshy{ 3150183725Sjkoshy size_t n; 3151183725Sjkoshy 3152183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 3153183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 3154183725Sjkoshy return (pmc_cputype_names[n].pm_name); 3155183725Sjkoshy 3156147191Sjkoshy errno = EINVAL; 3157174406Sjkoshy return (NULL); 3158147191Sjkoshy} 3159145256Sjkoshy 3160147191Sjkoshyconst char * 3161147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 3162147191Sjkoshy{ 3163147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 3164147191Sjkoshy pd <= PMC_DISP_LAST) 3165174406Sjkoshy return (pmc_disposition_names[pd]); 3166145256Sjkoshy 3167147191Sjkoshy errno = EINVAL; 3168174406Sjkoshy return (NULL); 3169147191Sjkoshy} 3170145256Sjkoshy 3171147191Sjkoshyconst char * 3172185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 3173147191Sjkoshy{ 3174183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 3175145256Sjkoshy 3176183725Sjkoshy ev = evfence = NULL; 3177185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 3178185363Sjkoshy ev = iaf_event_table; 3179185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 3180185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 3181185363Sjkoshy switch (cpu) { 3182185363Sjkoshy case PMC_CPU_INTEL_ATOM: 3183185363Sjkoshy ev = atom_event_table; 3184185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 3185185363Sjkoshy break; 3186185363Sjkoshy case PMC_CPU_INTEL_CORE: 3187185363Sjkoshy ev = core_event_table; 3188185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 3189185363Sjkoshy break; 3190185363Sjkoshy case PMC_CPU_INTEL_CORE2: 3191185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 3192185363Sjkoshy ev = core2_event_table; 3193185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 3194185363Sjkoshy break; 3195187761Sjeff case PMC_CPU_INTEL_COREI7: 3196187761Sjeff ev = corei7_event_table; 3197187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 3198187761Sjeff break; 3199248842Ssbruno case PMC_CPU_INTEL_HASWELL: 3200248842Ssbruno ev = haswell_event_table; 3201248842Ssbruno evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell); 3202248842Ssbruno break; 3203240164Sfabient case PMC_CPU_INTEL_IVYBRIDGE: 3204240164Sfabient ev = ivybridge_event_table; 3205240164Sfabient evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge); 3206240164Sfabient break; 3207246166Ssbruno case PMC_CPU_INTEL_IVYBRIDGE_XEON: 3208246166Ssbruno ev = ivybridge_xeon_event_table; 3209246166Ssbruno evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon); 3210246166Ssbruno break; 3211232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3212232366Sdavide ev = sandybridge_event_table; 3213232366Sdavide evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge); 3214232366Sdavide break; 3215241738Ssbruno case PMC_CPU_INTEL_SANDYBRIDGE_XEON: 3216241738Ssbruno ev = sandybridge_xeon_event_table; 3217241738Ssbruno evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon); 3218241738Ssbruno break; 3219206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3220206089Sfabient ev = westmere_event_table; 3221206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 3222206089Sfabient break; 3223185363Sjkoshy default: /* Unknown CPU type. */ 3224185363Sjkoshy break; 3225185363Sjkoshy } 3226206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 3227206089Sfabient ev = ucf_event_table; 3228206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 3229206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 3230206089Sfabient switch (cpu) { 3231206089Sfabient case PMC_CPU_INTEL_COREI7: 3232206089Sfabient ev = corei7uc_event_table; 3233206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 3234206089Sfabient break; 3235232366Sdavide case PMC_CPU_INTEL_SANDYBRIDGE: 3236232366Sdavide ev = sandybridgeuc_event_table; 3237232366Sdavide evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc); 3238232366Sdavide break; 3239206089Sfabient case PMC_CPU_INTEL_WESTMERE: 3240206089Sfabient ev = westmereuc_event_table; 3241206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 3242206089Sfabient break; 3243206089Sfabient default: /* Unknown CPU type. */ 3244206089Sfabient break; 3245206089Sfabient } 3246206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 3247183725Sjkoshy ev = k7_event_table; 3248183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 3249183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 3250183725Sjkoshy ev = k8_event_table; 3251183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 3252183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 3253183725Sjkoshy ev = p4_event_table; 3254183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 3255183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 3256183725Sjkoshy ev = p5_event_table; 3257183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 3258183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 3259183725Sjkoshy ev = p6_event_table; 3260183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 3261200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 3262200928Srpaulo ev = xscale_event_table; 3263200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 3264204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 3265204635Sgnn ev = mips24k_event_table; 3266233628Sfabient evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); 3267233335Sgonzo } else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) { 3268233335Sgonzo ev = octeon_event_table; 3269233335Sgonzo evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon); 3270228869Sjhibbits } else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) { 3271228869Sjhibbits ev = ppc7450_event_table; 3272233628Sfabient evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450); 3273183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 3274183725Sjkoshy ev = tsc_event_table; 3275183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 3276242622Sdim } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { 3277233628Sfabient ev = soft_event_table; 3278233628Sfabient evfence = soft_event_table + soft_event_info.pm_nevent; 3279183725Sjkoshy } 3280183725Sjkoshy 3281183725Sjkoshy for (; ev != evfence; ev++) 3282183725Sjkoshy if (pe == ev->pm_ev_code) 3283183725Sjkoshy return (ev->pm_ev_name); 3284183725Sjkoshy 3285185363Sjkoshy return (NULL); 3286185363Sjkoshy} 3287185363Sjkoshy 3288185363Sjkoshyconst char * 3289185363Sjkoshypmc_name_of_event(enum pmc_event pe) 3290185363Sjkoshy{ 3291185363Sjkoshy const char *n; 3292185363Sjkoshy 3293185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 3294185363Sjkoshy return (n); 3295185363Sjkoshy 3296147191Sjkoshy errno = EINVAL; 3297174406Sjkoshy return (NULL); 3298147191Sjkoshy} 3299145256Sjkoshy 3300147191Sjkoshyconst char * 3301147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 3302147191Sjkoshy{ 3303147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 3304147191Sjkoshy pm <= PMC_MODE_LAST) 3305174406Sjkoshy return (pmc_mode_names[pm]); 3306145256Sjkoshy 3307147191Sjkoshy errno = EINVAL; 3308174406Sjkoshy return (NULL); 3309147191Sjkoshy} 3310145256Sjkoshy 3311147191Sjkoshyconst char * 3312147191Sjkoshypmc_name_of_state(enum pmc_state ps) 3313147191Sjkoshy{ 3314147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 3315147191Sjkoshy ps <= PMC_STATE_LAST) 3316174406Sjkoshy return (pmc_state_names[ps]); 3317145256Sjkoshy 3318147191Sjkoshy errno = EINVAL; 3319174406Sjkoshy return (NULL); 3320145256Sjkoshy} 3321145256Sjkoshy 3322145256Sjkoshyint 3323147191Sjkoshypmc_ncpu(void) 3324145256Sjkoshy{ 3325147191Sjkoshy if (pmc_syscall == -1) { 3326147191Sjkoshy errno = ENXIO; 3327174406Sjkoshy return (-1); 3328147191Sjkoshy } 3329145256Sjkoshy 3330174406Sjkoshy return (cpu_info.pm_ncpu); 3331145256Sjkoshy} 3332145256Sjkoshy 3333145256Sjkoshyint 3334147191Sjkoshypmc_npmc(int cpu) 3335145256Sjkoshy{ 3336147191Sjkoshy if (pmc_syscall == -1) { 3337147191Sjkoshy errno = ENXIO; 3338174406Sjkoshy return (-1); 3339147191Sjkoshy } 3340145256Sjkoshy 3341147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 3342147191Sjkoshy errno = EINVAL; 3343174406Sjkoshy return (-1); 3344147191Sjkoshy } 3345145256Sjkoshy 3346174406Sjkoshy return (cpu_info.pm_npmc); 3347145256Sjkoshy} 3348145256Sjkoshy 3349145256Sjkoshyint 3350147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3351145256Sjkoshy{ 3352147191Sjkoshy int nbytes, npmc; 3353147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3354145256Sjkoshy 3355147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3356174406Sjkoshy return (-1); 3357145256Sjkoshy 3358147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3359147191Sjkoshy npmc * sizeof(struct pmc_info); 3360145256Sjkoshy 3361147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3362174406Sjkoshy return (-1); 3363145256Sjkoshy 3364147191Sjkoshy pmci->pm_cpu = cpu; 3365145256Sjkoshy 3366147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3367147191Sjkoshy free(pmci); 3368174406Sjkoshy return (-1); 3369147191Sjkoshy } 3370145256Sjkoshy 3371147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3372147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3373174406Sjkoshy return (0); 3374145256Sjkoshy} 3375145256Sjkoshy 3376145256Sjkoshyint 3377145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3378145256Sjkoshy{ 3379145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3380145256Sjkoshy 3381145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3382145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3383145256Sjkoshy pmc_read_op.pm_value = -1; 3384145256Sjkoshy 3385145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3386174406Sjkoshy return (-1); 3387145256Sjkoshy 3388145256Sjkoshy *value = pmc_read_op.pm_value; 3389174406Sjkoshy return (0); 3390145256Sjkoshy} 3391145256Sjkoshy 3392145256Sjkoshyint 3393147191Sjkoshypmc_release(pmc_id_t pmc) 3394145256Sjkoshy{ 3395147191Sjkoshy struct pmc_op_simple pmc_release_args; 3396145256Sjkoshy 3397147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3398174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3399145256Sjkoshy} 3400145256Sjkoshy 3401145256Sjkoshyint 3402145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3403145256Sjkoshy{ 3404145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3405145256Sjkoshy 3406145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3407145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3408145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3409145256Sjkoshy 3410145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3411174406Sjkoshy return (-1); 3412145256Sjkoshy 3413145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3414174406Sjkoshy return (0); 3415145256Sjkoshy} 3416145256Sjkoshy 3417145256Sjkoshyint 3418145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3419145256Sjkoshy{ 3420145256Sjkoshy struct pmc_op_pmcsetcount sc; 3421145256Sjkoshy 3422145256Sjkoshy sc.pm_pmcid = pmc; 3423145256Sjkoshy sc.pm_count = value; 3424145256Sjkoshy 3425145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3426174406Sjkoshy return (-1); 3427174406Sjkoshy return (0); 3428145256Sjkoshy} 3429145256Sjkoshy 3430145256Sjkoshyint 3431147191Sjkoshypmc_start(pmc_id_t pmc) 3432145256Sjkoshy{ 3433147191Sjkoshy struct pmc_op_simple pmc_start_args; 3434145256Sjkoshy 3435147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3436174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3437145256Sjkoshy} 3438145256Sjkoshy 3439145256Sjkoshyint 3440147191Sjkoshypmc_stop(pmc_id_t pmc) 3441145256Sjkoshy{ 3442147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3443145256Sjkoshy 3444147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3445174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3446145256Sjkoshy} 3447145256Sjkoshy 3448145256Sjkoshyint 3449145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3450145774Sjkoshy{ 3451145774Sjkoshy unsigned int i; 3452145774Sjkoshy enum pmc_class cl; 3453145774Sjkoshy 3454145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3455145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3456145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3457145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3458174406Sjkoshy return (0); 3459145774Sjkoshy } 3460177107Sjkoshy errno = EINVAL; 3461177107Sjkoshy return (-1); 3462145774Sjkoshy} 3463145774Sjkoshy 3464145774Sjkoshyint 3465147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3466145774Sjkoshy{ 3467147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3468145774Sjkoshy 3469147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3470147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3471147191Sjkoshy pmc_write_op.pm_value = value; 3472174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3473145256Sjkoshy} 3474145256Sjkoshy 3475145256Sjkoshyint 3476147191Sjkoshypmc_writelog(uint32_t userdata) 3477145256Sjkoshy{ 3478147191Sjkoshy struct pmc_op_writelog wl; 3479145256Sjkoshy 3480147191Sjkoshy wl.pm_userdata = userdata; 3481174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3482145256Sjkoshy} 3483