libpmc.c revision 228557
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 228557 2011-12-16 00:13:43Z dim $"); 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 80145256Sjkoshy 81204635Sgnn#if defined(__mips__) 82204635Sgnnstatic int mips24k_allocate_pmc(enum pmc_event _pe, char* ctrspec, 83204635Sgnn struct pmc_op_pmcallocate *_pmc_config); 84204635Sgnn#endif /* __mips__ */ 85204635Sgnn 86204635Sgnn 87145256Sjkoshy#define PMC_CALL(cmd, params) \ 88145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 89145256Sjkoshy 90145256Sjkoshy/* 91145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 92145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 93145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 94145256Sjkoshy * lookup table. 95145256Sjkoshy */ 96145256Sjkoshystruct pmc_event_alias { 97145256Sjkoshy const char *pm_alias; 98145256Sjkoshy const char *pm_spec; 99145256Sjkoshy}; 100145256Sjkoshy 101145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 102145256Sjkoshy 103145256Sjkoshy/* 104183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user 105145256Sjkoshy * to integer codes used by the PMC KLD. 106145256Sjkoshy */ 107145256Sjkoshystruct pmc_event_descr { 108145256Sjkoshy const char *pm_ev_name; 109145256Sjkoshy enum pmc_event pm_ev_code; 110145256Sjkoshy}; 111145256Sjkoshy 112183725Sjkoshy/* 113183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for 114183725Sjkoshy * event names to event tables and other PMC class data. 115183725Sjkoshy */ 116183725Sjkoshystruct pmc_class_descr { 117183725Sjkoshy const char *pm_evc_name; 118183725Sjkoshy size_t pm_evc_name_size; 119183725Sjkoshy enum pmc_class pm_evc_class; 120183725Sjkoshy const struct pmc_event_descr *pm_evc_event_table; 121183725Sjkoshy size_t pm_evc_event_table_size; 122183725Sjkoshy int (*pm_evc_allocate_pmc)(enum pmc_event _pe, 123183725Sjkoshy char *_ctrspec, struct pmc_op_pmcallocate *_pa); 124183725Sjkoshy}; 125183725Sjkoshy 126183725Sjkoshy#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) 127183725Sjkoshy#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) 128183725Sjkoshy 129183725Sjkoshy#undef __PMC_EV 130183725Sjkoshy#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, 131183725Sjkoshy 132183725Sjkoshy/* 133185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS) 134183725Sjkoshy * 135185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs. 136183725Sjkoshy */ 137185363Sjkoshy#define PMC_CLASSDEP_TABLE(N, C) \ 138183725Sjkoshy static const struct pmc_event_descr N##_event_table[] = \ 139183725Sjkoshy { \ 140183725Sjkoshy __PMC_EV_##C() \ 141185363Sjkoshy } 142185363Sjkoshy 143185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF); 144185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7); 145185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8); 146185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4); 147185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5); 148185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6); 149200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE); 150204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K); 151206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF); 152185363Sjkoshy 153185363Sjkoshy#undef __PMC_EV_ALIAS 154185363Sjkoshy#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, 155185363Sjkoshy 156185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] = 157185363Sjkoshy{ 158185363Sjkoshy __PMC_EV_ALIAS_ATOM() 159185363Sjkoshy}; 160185363Sjkoshy 161185363Sjkoshystatic const struct pmc_event_descr core_event_table[] = 162185363Sjkoshy{ 163185363Sjkoshy __PMC_EV_ALIAS_CORE() 164185363Sjkoshy}; 165185363Sjkoshy 166185363Sjkoshy 167185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] = 168185363Sjkoshy{ 169185363Sjkoshy __PMC_EV_ALIAS_CORE2() 170185363Sjkoshy}; 171185363Sjkoshy 172187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] = 173187761Sjeff{ 174187761Sjeff __PMC_EV_ALIAS_COREI7() 175187761Sjeff}; 176187761Sjeff 177206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] = 178206089Sfabient{ 179206089Sfabient __PMC_EV_ALIAS_WESTMERE() 180206089Sfabient}; 181206089Sfabient 182206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] = 183206089Sfabient{ 184206089Sfabient __PMC_EV_ALIAS_COREI7UC() 185206089Sfabient}; 186206089Sfabient 187206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] = 188206089Sfabient{ 189206089Sfabient __PMC_EV_ALIAS_WESTMEREUC() 190206089Sfabient}; 191206089Sfabient 192185363Sjkoshy/* 193185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) 194185363Sjkoshy * 195185363Sjkoshy * Map a CPU to the PMC classes it supports. 196185363Sjkoshy */ 197185363Sjkoshy#define PMC_MDEP_TABLE(N,C,...) \ 198183725Sjkoshy static const enum pmc_class N##_pmc_classes[] = { \ 199183725Sjkoshy PMC_CLASS_##C, __VA_ARGS__ \ 200183725Sjkoshy } 201183725Sjkoshy 202185363SjkoshyPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 203185363SjkoshyPMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC); 204185363SjkoshyPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); 205206089SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 206206089SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP); 207183725SjkoshyPMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC); 208183725SjkoshyPMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC); 209183725SjkoshyPMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC); 210183725SjkoshyPMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC); 211183725SjkoshyPMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC); 212200928SrpauloPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_XSCALE); 213204635SgnnPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_MIPS24K); 214183725Sjkoshy 215183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] = 216145256Sjkoshy{ 217183725Sjkoshy __PMC_EV_TSC() 218145256Sjkoshy}; 219145256Sjkoshy 220183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 221185363Sjkoshy#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ 222185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr = \ 223185363Sjkoshy { \ 224185363Sjkoshy .pm_evc_name = #CLASS "-", \ 225185363Sjkoshy .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ 226185363Sjkoshy .pm_evc_class = PMC_CLASS_##CLASS , \ 227185363Sjkoshy .pm_evc_event_table = EVENTS##_event_table , \ 228183725Sjkoshy .pm_evc_event_table_size = \ 229185363Sjkoshy PMC_EVENT_TABLE_SIZE(EVENTS), \ 230185363Sjkoshy .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ 231183725Sjkoshy } 232183725Sjkoshy 233185363Sjkoshy#if defined(__i386__) || defined(__amd64__) 234185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); 235185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); 236185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap); 237185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); 238187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); 239206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap); 240206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf); 241206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp); 242206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp); 243185363Sjkoshy#endif 244183725Sjkoshy#if defined(__i386__) 245185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7); 246183725Sjkoshy#endif 247183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 248185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8); 249185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4); 250183725Sjkoshy#endif 251183725Sjkoshy#if defined(__i386__) 252185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5); 253185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6); 254183725Sjkoshy#endif 255183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 256185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); 257183725Sjkoshy#endif 258200928Srpaulo#if defined(__XSCALE__) 259200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); 260200928Srpaulo#endif 261183725Sjkoshy 262204635Sgnn#if defined(__mips__) 263204635SgnnPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips24k); 264204635Sgnn#endif /* __mips__ */ 265204635Sgnn 266183725Sjkoshy#undef PMC_CLASS_TABLE_DESC 267183725Sjkoshy 268185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table; 269185363Sjkoshy#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass 270185363Sjkoshy 271183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list; 272183725Sjkoshystatic size_t pmc_mdep_class_list_size; 273183725Sjkoshy 274145256Sjkoshy/* 275145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 276145256Sjkoshy * strings. 277145256Sjkoshy */ 278145256Sjkoshy 279145256Sjkoshystatic const char * pmc_capability_names[] = { 280145256Sjkoshy#undef __PMC_CAP 281145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 282145256Sjkoshy __PMC_CAPS() 283145256Sjkoshy}; 284145256Sjkoshy 285145256Sjkoshystatic const char * pmc_class_names[] = { 286145256Sjkoshy#undef __PMC_CLASS 287145256Sjkoshy#define __PMC_CLASS(C) #C , 288145256Sjkoshy __PMC_CLASSES() 289145256Sjkoshy}; 290145256Sjkoshy 291183725Sjkoshystruct pmc_cputype_map { 292228557Sdim enum pmc_cputype pm_cputype; 293183725Sjkoshy const char *pm_name; 294183725Sjkoshy}; 295183725Sjkoshy 296183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = { 297145256Sjkoshy#undef __PMC_CPU 298183725Sjkoshy#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , 299145256Sjkoshy __PMC_CPUS() 300145256Sjkoshy}; 301145256Sjkoshy 302145256Sjkoshystatic const char * pmc_disposition_names[] = { 303145256Sjkoshy#undef __PMC_DISP 304145256Sjkoshy#define __PMC_DISP(D) #D , 305145256Sjkoshy __PMC_DISPOSITIONS() 306145256Sjkoshy}; 307145256Sjkoshy 308145256Sjkoshystatic const char * pmc_mode_names[] = { 309145256Sjkoshy#undef __PMC_MODE 310145256Sjkoshy#define __PMC_MODE(M,N) #M , 311145256Sjkoshy __PMC_MODES() 312145256Sjkoshy}; 313145256Sjkoshy 314145256Sjkoshystatic const char * pmc_state_names[] = { 315145256Sjkoshy#undef __PMC_STATE 316145256Sjkoshy#define __PMC_STATE(S) #S , 317145256Sjkoshy __PMC_STATES() 318145256Sjkoshy}; 319145256Sjkoshy 320145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 321145256Sjkoshy 322147219Sjkoshystatic struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */ 323145256Sjkoshy 324145256Sjkoshy/* Event masks for events */ 325145256Sjkoshystruct pmc_masks { 326145256Sjkoshy const char *pm_name; 327145256Sjkoshy const uint32_t pm_value; 328145256Sjkoshy}; 329145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 330206089Sfabient#define NULLMASK { .pm_name = NULL } 331145256Sjkoshy 332147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 333145256Sjkoshystatic int 334145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 335145256Sjkoshy{ 336145256Sjkoshy const struct pmc_masks *pm; 337145256Sjkoshy char *q, *r; 338145256Sjkoshy int c; 339145256Sjkoshy 340145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 341174406Sjkoshy return (-1); 342183107Sjkoshy q = strchr(p, '='); /* skip '=' */ 343145256Sjkoshy if (*++q == '\0') /* no more data */ 344174406Sjkoshy return (-1); 345145256Sjkoshy c = 0; /* count of mask keywords seen */ 346145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 347183725Sjkoshy for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); 348183725Sjkoshy pm++) 349145256Sjkoshy ; 350145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 351174406Sjkoshy return (-1); 352145256Sjkoshy *evmask |= pm->pm_value; 353145256Sjkoshy c++; 354145256Sjkoshy } 355174406Sjkoshy return (c); 356145256Sjkoshy} 357145340Smarcel#endif 358145256Sjkoshy 359145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 360145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 361145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 362145256Sjkoshy 363145340Smarcel#if defined(__i386__) 364145256Sjkoshy 365145256Sjkoshy/* 366145256Sjkoshy * AMD K7 (Athlon) CPUs. 367145256Sjkoshy */ 368145256Sjkoshy 369145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 370145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 371145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 372145351Sjkoshy EV_ALIAS("cycles", "tsc"), 373183075Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses"), 374145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 375145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 376145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 377145351Sjkoshy EV_ALIAS(NULL, NULL) 378145256Sjkoshy}; 379145256Sjkoshy 380145256Sjkoshy#define K7_KW_COUNT "count" 381145256Sjkoshy#define K7_KW_EDGE "edge" 382145256Sjkoshy#define K7_KW_INV "inv" 383145256Sjkoshy#define K7_KW_OS "os" 384145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 385145256Sjkoshy#define K7_KW_USR "usr" 386145256Sjkoshy 387145256Sjkoshystatic int 388145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 389145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 390145256Sjkoshy{ 391183107Sjkoshy char *e, *p, *q; 392183107Sjkoshy int c, has_unitmask; 393145256Sjkoshy uint32_t count, unitmask; 394145256Sjkoshy 395147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 396183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 397145256Sjkoshy 398145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 399145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 400145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 401145256Sjkoshy has_unitmask = 1; 402147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 403145256Sjkoshy } else 404145256Sjkoshy unitmask = has_unitmask = 0; 405145256Sjkoshy 406145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 407145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 408145256Sjkoshy q = strchr(p, '='); 409145256Sjkoshy if (*++q == '\0') /* skip '=' */ 410174406Sjkoshy return (-1); 411145256Sjkoshy 412145256Sjkoshy count = strtol(q, &e, 0); 413145256Sjkoshy if (e == q || *e != '\0') 414174406Sjkoshy return (-1); 415145256Sjkoshy 416145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 417147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 418147191Sjkoshy AMD_PMC_TO_COUNTER(count); 419145256Sjkoshy 420145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 421145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 422145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 423145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 424145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 425145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 426145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 427145256Sjkoshy if (has_unitmask == 0) 428174406Sjkoshy return (-1); 429145256Sjkoshy unitmask = 0; 430145256Sjkoshy q = strchr(p, '='); 431145256Sjkoshy if (*++q == '\0') /* skip '=' */ 432174406Sjkoshy return (-1); 433145256Sjkoshy 434145256Sjkoshy while ((c = tolower(*q++)) != 0) 435145256Sjkoshy if (c == 'm') 436147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 437145256Sjkoshy else if (c == 'o') 438147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 439145256Sjkoshy else if (c == 'e') 440147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 441145256Sjkoshy else if (c == 's') 442147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 443145256Sjkoshy else if (c == 'i') 444147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 445145256Sjkoshy else if (c == '+') 446145256Sjkoshy continue; 447145256Sjkoshy else 448174406Sjkoshy return (-1); 449145256Sjkoshy 450145256Sjkoshy if (unitmask == 0) 451174406Sjkoshy return (-1); 452145256Sjkoshy 453145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 454145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 455145256Sjkoshy } else 456174406Sjkoshy return (-1); 457145256Sjkoshy } 458145256Sjkoshy 459145256Sjkoshy if (has_unitmask) { 460145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 461147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 462147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 463145256Sjkoshy } 464145256Sjkoshy 465174406Sjkoshy return (0); 466145256Sjkoshy 467145256Sjkoshy} 468145256Sjkoshy 469147191Sjkoshy#endif 470147191Sjkoshy 471147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 472147191Sjkoshy 473145256Sjkoshy/* 474185363Sjkoshy * Intel Core (Family 6, Model E) PMCs. 475185363Sjkoshy */ 476185363Sjkoshy 477185363Sjkoshystatic struct pmc_event_alias core_aliases[] = { 478185363Sjkoshy EV_ALIAS("branches", "iap-br-instr-ret"), 479185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), 480185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 481185363Sjkoshy EV_ALIAS("ic-misses", "iap-icache-misses"), 482185363Sjkoshy EV_ALIAS("instructions", "iap-instr-ret"), 483185363Sjkoshy EV_ALIAS("interrupts", "iap-core-hw-int-rx"), 484185363Sjkoshy EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), 485185363Sjkoshy EV_ALIAS(NULL, NULL) 486185363Sjkoshy}; 487185363Sjkoshy 488185363Sjkoshy/* 489185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) 490185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs. 491198433Sjkoshy * 492198433Sjkoshy * We map aliases to events on the fixed-function counters if these 493198433Sjkoshy * are present. Note that not all CPUs in this family contain fixed-function 494198433Sjkoshy * counters. 495185363Sjkoshy */ 496185363Sjkoshy 497185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = { 498185363Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 499185363Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 500185363Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 501185363Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 502185363Sjkoshy EV_ALIAS("instructions", "iaf-instr-retired.any"), 503185363Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 504185363Sjkoshy EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), 505185363Sjkoshy EV_ALIAS(NULL, NULL) 506185363Sjkoshy}; 507185363Sjkoshy 508198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = { 509198433Sjkoshy EV_ALIAS("branches", "iap-br-inst-retired.any"), 510198433Sjkoshy EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), 511198433Sjkoshy EV_ALIAS("cycles", "tsc-tsc"), 512198433Sjkoshy EV_ALIAS("ic-misses", "iap-l1i-misses"), 513198433Sjkoshy EV_ALIAS("instructions", "iap-inst-retired.any_p"), 514198433Sjkoshy EV_ALIAS("interrupts", "iap-hw-int-rcv"), 515198433Sjkoshy EV_ALIAS("unhalted-cycles", "iap-cpu-clk-unhalted.core_p"), 516198433Sjkoshy EV_ALIAS(NULL, NULL) 517198433Sjkoshy}; 518198433Sjkoshy 519198433Sjkoshy#define atom_aliases core2_aliases 520198433Sjkoshy#define atom_aliases_without_iaf core2_aliases_without_iaf 521198433Sjkoshy#define corei7_aliases core2_aliases 522198433Sjkoshy#define corei7_aliases_without_iaf core2_aliases_without_iaf 523206089Sfabient#define westmere_aliases core2_aliases 524206089Sfabient#define westmere_aliases_without_iaf core2_aliases_without_iaf 525198433Sjkoshy 526185363Sjkoshy#define IAF_KW_OS "os" 527185363Sjkoshy#define IAF_KW_USR "usr" 528185363Sjkoshy#define IAF_KW_ANYTHREAD "anythread" 529185363Sjkoshy 530185363Sjkoshy/* 531185363Sjkoshy * Parse an event specifier for Intel fixed function counters. 532185363Sjkoshy */ 533185363Sjkoshystatic int 534185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec, 535185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 536185363Sjkoshy{ 537185363Sjkoshy char *p; 538185363Sjkoshy 539185363Sjkoshy (void) pe; 540185363Sjkoshy 541185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 542185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; 543185363Sjkoshy 544185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 545185363Sjkoshy if (KWMATCH(p, IAF_KW_OS)) 546185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 547185363Sjkoshy else if (KWMATCH(p, IAF_KW_USR)) 548185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 549185363Sjkoshy else if (KWMATCH(p, IAF_KW_ANYTHREAD)) 550185363Sjkoshy pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; 551185363Sjkoshy else 552185363Sjkoshy return (-1); 553185363Sjkoshy } 554185363Sjkoshy 555185363Sjkoshy return (0); 556185363Sjkoshy} 557185363Sjkoshy 558185363Sjkoshy/* 559185363Sjkoshy * Core/Core2 support. 560185363Sjkoshy */ 561185363Sjkoshy 562185363Sjkoshy#define IAP_KW_AGENT "agent" 563185363Sjkoshy#define IAP_KW_ANYTHREAD "anythread" 564185363Sjkoshy#define IAP_KW_CACHESTATE "cachestate" 565185363Sjkoshy#define IAP_KW_CMASK "cmask" 566185363Sjkoshy#define IAP_KW_CORE "core" 567185363Sjkoshy#define IAP_KW_EDGE "edge" 568185363Sjkoshy#define IAP_KW_INV "inv" 569185363Sjkoshy#define IAP_KW_OS "os" 570185363Sjkoshy#define IAP_KW_PREFETCH "prefetch" 571185363Sjkoshy#define IAP_KW_SNOOPRESPONSE "snoopresponse" 572185363Sjkoshy#define IAP_KW_SNOOPTYPE "snooptype" 573185363Sjkoshy#define IAP_KW_TRANSITION "trans" 574185363Sjkoshy#define IAP_KW_USR "usr" 575206089Sfabient#define IAP_KW_RSP "rsp" 576185363Sjkoshy 577185363Sjkoshystatic struct pmc_masks iap_core_mask[] = { 578185363Sjkoshy PMCMASK(all, (0x3 << 14)), 579185363Sjkoshy PMCMASK(this, (0x1 << 14)), 580185363Sjkoshy NULLMASK 581185363Sjkoshy}; 582185363Sjkoshy 583185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = { 584185363Sjkoshy PMCMASK(this, 0), 585185363Sjkoshy PMCMASK(any, (0x1 << 13)), 586185363Sjkoshy NULLMASK 587185363Sjkoshy}; 588185363Sjkoshy 589185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = { 590185363Sjkoshy PMCMASK(both, (0x3 << 12)), 591185363Sjkoshy PMCMASK(only, (0x1 << 12)), 592185363Sjkoshy PMCMASK(exclude, 0), 593185363Sjkoshy NULLMASK 594185363Sjkoshy}; 595185363Sjkoshy 596185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = { 597185363Sjkoshy PMCMASK(i, (1 << 8)), 598185363Sjkoshy PMCMASK(s, (1 << 9)), 599185363Sjkoshy PMCMASK(e, (1 << 10)), 600185363Sjkoshy PMCMASK(m, (1 << 11)), 601185363Sjkoshy NULLMASK 602185363Sjkoshy}; 603185363Sjkoshy 604185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = { 605185363Sjkoshy PMCMASK(clean, (1 << 8)), 606185363Sjkoshy PMCMASK(hit, (1 << 9)), 607185363Sjkoshy PMCMASK(hitm, (1 << 11)), 608185363Sjkoshy NULLMASK 609185363Sjkoshy}; 610185363Sjkoshy 611185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = { 612185363Sjkoshy PMCMASK(cmp2s, (1 << 8)), 613185363Sjkoshy PMCMASK(cmp2i, (1 << 9)), 614185363Sjkoshy NULLMASK 615185363Sjkoshy}; 616185363Sjkoshy 617185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = { 618185363Sjkoshy PMCMASK(any, 0x00), 619185363Sjkoshy PMCMASK(frequency, 0x10), 620185363Sjkoshy NULLMASK 621185363Sjkoshy}; 622185363Sjkoshy 623206089Sfabientstatic struct pmc_masks iap_rsp_mask[] = { 624206089Sfabient PMCMASK(DMND_DATA_RD, (1 << 0)), 625206089Sfabient PMCMASK(DMND_RFO, (1 << 1)), 626206089Sfabient PMCMASK(DMND_IFETCH, (1 << 2)), 627206089Sfabient PMCMASK(WB, (1 << 3)), 628206089Sfabient PMCMASK(PF_DATA_RD, (1 << 4)), 629206089Sfabient PMCMASK(PF_RFO, (1 << 5)), 630206089Sfabient PMCMASK(PF_IFETCH, (1 << 6)), 631206089Sfabient PMCMASK(OTHER, (1 << 7)), 632206089Sfabient PMCMASK(UNCORE_HIT, (1 << 8)), 633206089Sfabient PMCMASK(OTHER_CORE_HIT_SNP, (1 << 9)), 634206089Sfabient PMCMASK(OTHER_CORE_HITM, (1 << 10)), 635206089Sfabient PMCMASK(REMOTE_CACHE_FWD, (1 << 12)), 636206089Sfabient PMCMASK(REMOTE_DRAM, (1 << 13)), 637206089Sfabient PMCMASK(LOCAL_DRAM, (1 << 14)), 638206089Sfabient PMCMASK(NON_DRAM, (1 << 15)), 639206089Sfabient NULLMASK 640206089Sfabient}; 641206089Sfabient 642185363Sjkoshystatic int 643185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec, 644185363Sjkoshy struct pmc_op_pmcallocate *pmc_config) 645185363Sjkoshy{ 646185363Sjkoshy char *e, *p, *q; 647206089Sfabient uint32_t cachestate, evmask, rsp; 648185363Sjkoshy int count, n; 649185363Sjkoshy 650185363Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 651185363Sjkoshy PMC_CAP_QUALIFIER); 652185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config = 0; 653185363Sjkoshy 654206089Sfabient cachestate = evmask = rsp = 0; 655185363Sjkoshy 656185363Sjkoshy /* Parse additional modifiers if present */ 657185363Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 658185363Sjkoshy 659185363Sjkoshy n = 0; 660185363Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { 661185363Sjkoshy q = strchr(p, '='); 662185363Sjkoshy if (*++q == '\0') /* skip '=' */ 663185363Sjkoshy return (-1); 664185363Sjkoshy count = strtol(q, &e, 0); 665185363Sjkoshy if (e == q || *e != '\0') 666185363Sjkoshy return (-1); 667185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 668185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= 669185363Sjkoshy IAP_CMASK(count); 670185363Sjkoshy } else if (KWMATCH(p, IAP_KW_EDGE)) { 671185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 672185363Sjkoshy } else if (KWMATCH(p, IAP_KW_INV)) { 673185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 674185363Sjkoshy } else if (KWMATCH(p, IAP_KW_OS)) { 675185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 676185363Sjkoshy } else if (KWMATCH(p, IAP_KW_USR)) { 677185363Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 678185363Sjkoshy } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { 679185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; 680193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) { 681185363Sjkoshy n = pmc_parse_mask(iap_core_mask, p, &evmask); 682185363Sjkoshy if (n != 1) 683185363Sjkoshy return (-1); 684193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) { 685185363Sjkoshy n = pmc_parse_mask(iap_agent_mask, p, &evmask); 686185363Sjkoshy if (n != 1) 687185363Sjkoshy return (-1); 688193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) { 689185363Sjkoshy n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); 690185363Sjkoshy if (n != 1) 691185363Sjkoshy return (-1); 692193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) { 693185363Sjkoshy n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); 694185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && 695193809Sjkoshy KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) { 696185363Sjkoshy n = pmc_parse_mask(iap_transition_mask, p, &evmask); 697185363Sjkoshy if (n != 1) 698185363Sjkoshy return (-1); 699185363Sjkoshy } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || 700185585Sjkoshy cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || 701206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) { 702193809Sjkoshy if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) { 703185363Sjkoshy n = pmc_parse_mask(iap_snoopresponse_mask, p, 704185363Sjkoshy &evmask); 705193809Sjkoshy } else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) { 706185363Sjkoshy n = pmc_parse_mask(iap_snooptype_mask, p, 707185363Sjkoshy &evmask); 708185363Sjkoshy } else 709185363Sjkoshy return (-1); 710206089Sfabient } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 || 711206089Sfabient cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) { 712206089Sfabient if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) { 713206089Sfabient n = pmc_parse_mask(iap_rsp_mask, p, &rsp); 714206089Sfabient } else 715206089Sfabient return (-1); 716185363Sjkoshy } else 717185363Sjkoshy return (-1); 718185363Sjkoshy 719185363Sjkoshy if (n < 0) /* Parsing failed. */ 720185363Sjkoshy return (-1); 721185363Sjkoshy } 722185363Sjkoshy 723185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; 724185363Sjkoshy 725185363Sjkoshy /* 726185363Sjkoshy * If the event requires a 'cachestate' qualifier but was not 727185363Sjkoshy * specified by the user, use a sensible default. 728185363Sjkoshy */ 729185363Sjkoshy switch (pe) { 730185363Sjkoshy case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ 731185363Sjkoshy case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ 732185363Sjkoshy case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ 733185363Sjkoshy case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ 734185363Sjkoshy case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ 735185363Sjkoshy case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ 736185363Sjkoshy case PMC_EV_IAP_EVENT_32H: /* Core */ 737185363Sjkoshy case PMC_EV_IAP_EVENT_40H: /* Core */ 738185363Sjkoshy case PMC_EV_IAP_EVENT_41H: /* Core */ 739185363Sjkoshy case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ 740185363Sjkoshy if (cachestate == 0) 741185363Sjkoshy cachestate = (0xF << 8); 742207482Srstone break; 743207482Srstone case PMC_EV_IAP_EVENT_77H: /* Atom */ 744207482Srstone /* IAP_EVENT_77H only accepts a cachestate qualifier on the 745207482Srstone * Atom processor 746207482Srstone */ 747207482Srstone if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0) 748207482Srstone cachestate = (0xF << 8); 749207482Srstone break; 750185363Sjkoshy default: 751185363Sjkoshy break; 752185363Sjkoshy } 753185363Sjkoshy 754185363Sjkoshy pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; 755206089Sfabient pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp; 756185363Sjkoshy 757185363Sjkoshy return (0); 758185363Sjkoshy} 759185363Sjkoshy 760185363Sjkoshy/* 761206089Sfabient * Intel Uncore. 762206089Sfabient */ 763206089Sfabient 764206089Sfabientstatic int 765206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec, 766206089Sfabient struct pmc_op_pmcallocate *pmc_config) 767206089Sfabient{ 768206089Sfabient (void) pe; 769206089Sfabient (void) ctrspec; 770206089Sfabient 771206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 772206089Sfabient pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0; 773206089Sfabient 774206089Sfabient return (0); 775206089Sfabient} 776206089Sfabient 777206089Sfabient#define UCP_KW_CMASK "cmask" 778206089Sfabient#define UCP_KW_EDGE "edge" 779206089Sfabient#define UCP_KW_INV "inv" 780206089Sfabient 781206089Sfabientstatic int 782206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec, 783206089Sfabient struct pmc_op_pmcallocate *pmc_config) 784206089Sfabient{ 785206089Sfabient char *e, *p, *q; 786206089Sfabient int count, n; 787206089Sfabient 788206089Sfabient (void) pe; 789206089Sfabient 790206089Sfabient pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | 791206089Sfabient PMC_CAP_QUALIFIER); 792206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config = 0; 793206089Sfabient 794206089Sfabient /* Parse additional modifiers if present */ 795206089Sfabient while ((p = strsep(&ctrspec, ",")) != NULL) { 796206089Sfabient 797206089Sfabient n = 0; 798206089Sfabient if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) { 799206089Sfabient q = strchr(p, '='); 800206089Sfabient if (*++q == '\0') /* skip '=' */ 801206089Sfabient return (-1); 802206089Sfabient count = strtol(q, &e, 0); 803206089Sfabient if (e == q || *e != '\0') 804206089Sfabient return (-1); 805206089Sfabient pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 806206089Sfabient pmc_config->pm_md.pm_ucp.pm_ucp_config |= 807206089Sfabient UCP_CMASK(count); 808206089Sfabient } else if (KWMATCH(p, UCP_KW_EDGE)) { 809206089Sfabient pmc_config->pm_caps |= PMC_CAP_EDGE; 810206089Sfabient } else if (KWMATCH(p, UCP_KW_INV)) { 811206089Sfabient pmc_config->pm_caps |= PMC_CAP_INVERT; 812206089Sfabient } else 813206089Sfabient return (-1); 814206089Sfabient 815206089Sfabient if (n < 0) /* Parsing failed. */ 816206089Sfabient return (-1); 817206089Sfabient } 818206089Sfabient 819206089Sfabient return (0); 820206089Sfabient} 821206089Sfabient 822206089Sfabient/* 823147191Sjkoshy * AMD K8 PMCs. 824147191Sjkoshy * 825147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 826147191Sjkoshy * events. 827147191Sjkoshy */ 828147191Sjkoshy 829147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 830147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 831147191Sjkoshy EV_ALIAS("branch-mispredicts", 832147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 833147191Sjkoshy EV_ALIAS("cycles", "tsc"), 834147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 835147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 836183107Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 837147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 838155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 839147191Sjkoshy EV_ALIAS(NULL, NULL) 840147191Sjkoshy}; 841147191Sjkoshy 842147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 843147191Sjkoshy 844147191Sjkoshy/* 845147191Sjkoshy * Parsing tables 846147191Sjkoshy */ 847147191Sjkoshy 848147191Sjkoshy/* fp dispatched fpu ops */ 849147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 850147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 851147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 852147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 853147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 854147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 855147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 856147191Sjkoshy NULLMASK 857147191Sjkoshy}; 858147191Sjkoshy 859147191Sjkoshy/* ls segment register loads */ 860147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 861147191Sjkoshy __K8MASK(es, 0), 862147191Sjkoshy __K8MASK(cs, 1), 863147191Sjkoshy __K8MASK(ss, 2), 864147191Sjkoshy __K8MASK(ds, 3), 865147191Sjkoshy __K8MASK(fs, 4), 866147191Sjkoshy __K8MASK(gs, 5), 867147191Sjkoshy __K8MASK(hs, 6), 868147191Sjkoshy NULLMASK 869147191Sjkoshy}; 870147191Sjkoshy 871147191Sjkoshy/* ls locked operation */ 872147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 873147191Sjkoshy __K8MASK(locked-instructions, 0), 874147191Sjkoshy __K8MASK(cycles-in-request, 1), 875147191Sjkoshy __K8MASK(cycles-to-complete, 2), 876147191Sjkoshy NULLMASK 877147191Sjkoshy}; 878147191Sjkoshy 879147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 880147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 881147191Sjkoshy __K8MASK(invalid, 0), 882147191Sjkoshy __K8MASK(shared, 1), 883147191Sjkoshy __K8MASK(exclusive, 2), 884147191Sjkoshy __K8MASK(owner, 3), 885147191Sjkoshy __K8MASK(modified, 4), 886147191Sjkoshy NULLMASK 887147191Sjkoshy}; 888147191Sjkoshy 889147191Sjkoshy/* dc one bit ecc error */ 890147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 891147191Sjkoshy __K8MASK(scrubber, 0), 892147191Sjkoshy __K8MASK(piggyback, 1), 893147191Sjkoshy NULLMASK 894147191Sjkoshy}; 895147191Sjkoshy 896147191Sjkoshy/* dc dispatched prefetch instructions */ 897147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 898147191Sjkoshy __K8MASK(load, 0), 899147191Sjkoshy __K8MASK(store, 1), 900147191Sjkoshy __K8MASK(nta, 2), 901147191Sjkoshy NULLMASK 902147191Sjkoshy}; 903147191Sjkoshy 904147191Sjkoshy/* dc dcache accesses by locks */ 905147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 906147191Sjkoshy __K8MASK(accesses, 0), 907147191Sjkoshy __K8MASK(misses, 1), 908147191Sjkoshy NULLMASK 909147191Sjkoshy}; 910147191Sjkoshy 911147191Sjkoshy/* bu internal l2 request */ 912147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 913147191Sjkoshy __K8MASK(ic-fill, 0), 914147191Sjkoshy __K8MASK(dc-fill, 1), 915147191Sjkoshy __K8MASK(tlb-reload, 2), 916147191Sjkoshy __K8MASK(tag-snoop, 3), 917147191Sjkoshy __K8MASK(cancelled, 4), 918147191Sjkoshy NULLMASK 919147191Sjkoshy}; 920147191Sjkoshy 921147191Sjkoshy/* bu fill request l2 miss */ 922147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 923147191Sjkoshy __K8MASK(ic-fill, 0), 924147191Sjkoshy __K8MASK(dc-fill, 1), 925147191Sjkoshy __K8MASK(tlb-reload, 2), 926147191Sjkoshy NULLMASK 927147191Sjkoshy}; 928147191Sjkoshy 929147191Sjkoshy/* bu fill into l2 */ 930147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 931147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 932147191Sjkoshy __K8MASK(victim-from-l2, 1), 933147191Sjkoshy NULLMASK 934147191Sjkoshy}; 935147191Sjkoshy 936147191Sjkoshy/* fr retired fpu instructions */ 937147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 938147191Sjkoshy __K8MASK(x87, 0), 939147191Sjkoshy __K8MASK(mmx-3dnow, 1), 940147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 941147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 942147191Sjkoshy NULLMASK 943147191Sjkoshy}; 944147191Sjkoshy 945147191Sjkoshy/* fr retired fastpath double op instructions */ 946147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 947147191Sjkoshy __K8MASK(low-op-pos-0, 0), 948147191Sjkoshy __K8MASK(low-op-pos-1, 1), 949147191Sjkoshy __K8MASK(low-op-pos-2, 2), 950147191Sjkoshy NULLMASK 951147191Sjkoshy}; 952147191Sjkoshy 953147191Sjkoshy/* fr fpu exceptions */ 954147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 955147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 956147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 957147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 958147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 959147191Sjkoshy NULLMASK 960147191Sjkoshy}; 961147191Sjkoshy 962147191Sjkoshy/* nb memory controller page access event */ 963147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 964147191Sjkoshy __K8MASK(page-hit, 0), 965147191Sjkoshy __K8MASK(page-miss, 1), 966147191Sjkoshy __K8MASK(page-conflict, 2), 967147191Sjkoshy NULLMASK 968147191Sjkoshy}; 969147191Sjkoshy 970147191Sjkoshy/* nb memory controller turnaround */ 971147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 972147191Sjkoshy __K8MASK(dimm-turnaround, 0), 973147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 974147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 975147191Sjkoshy NULLMASK 976147191Sjkoshy}; 977147191Sjkoshy 978147191Sjkoshy/* nb memory controller bypass saturation */ 979147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 980147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 981147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 982147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 983147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 984147191Sjkoshy NULLMASK 985147191Sjkoshy}; 986147191Sjkoshy 987147191Sjkoshy/* nb sized commands */ 988147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 989147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 990147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 991147191Sjkoshy __K8MASK(postwrszbyte, 2), 992147191Sjkoshy __K8MASK(postwrszdword, 3), 993147191Sjkoshy __K8MASK(rdszbyte, 4), 994147191Sjkoshy __K8MASK(rdszdword, 5), 995147191Sjkoshy __K8MASK(rdmodwr, 6), 996147191Sjkoshy NULLMASK 997147191Sjkoshy}; 998147191Sjkoshy 999147191Sjkoshy/* nb probe result */ 1000147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1001147191Sjkoshy __K8MASK(probe-miss, 0), 1002147191Sjkoshy __K8MASK(probe-hit, 1), 1003147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1004147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1005147191Sjkoshy NULLMASK 1006147191Sjkoshy}; 1007147191Sjkoshy 1008147191Sjkoshy/* nb hypertransport bus bandwidth */ 1009147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1010147191Sjkoshy __K8MASK(command, 0), 1011183107Sjkoshy __K8MASK(data, 1), 1012147191Sjkoshy __K8MASK(buffer-release, 2), 1013147191Sjkoshy __K8MASK(nop, 3), 1014147191Sjkoshy NULLMASK 1015147191Sjkoshy}; 1016147191Sjkoshy 1017147191Sjkoshy#undef __K8MASK 1018147191Sjkoshy 1019147191Sjkoshy#define K8_KW_COUNT "count" 1020147191Sjkoshy#define K8_KW_EDGE "edge" 1021147191Sjkoshy#define K8_KW_INV "inv" 1022147191Sjkoshy#define K8_KW_MASK "mask" 1023147191Sjkoshy#define K8_KW_OS "os" 1024147191Sjkoshy#define K8_KW_USR "usr" 1025147191Sjkoshy 1026147191Sjkoshystatic int 1027147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1028147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1029147191Sjkoshy{ 1030183107Sjkoshy char *e, *p, *q; 1031183107Sjkoshy int n; 1032147191Sjkoshy uint32_t count, evmask; 1033147191Sjkoshy const struct pmc_masks *pm, *pmask; 1034147191Sjkoshy 1035183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1036147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 1037147191Sjkoshy 1038147191Sjkoshy pmask = NULL; 1039147191Sjkoshy evmask = 0; 1040147191Sjkoshy 1041147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1042147191Sjkoshy 1043147191Sjkoshy /* setup parsing tables */ 1044147191Sjkoshy switch (pe) { 1045147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1046147191Sjkoshy __K8SETMASK(fdfo); 1047147191Sjkoshy break; 1048147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1049147191Sjkoshy __K8SETMASK(lsrl); 1050147191Sjkoshy break; 1051147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1052147191Sjkoshy __K8SETMASK(llo); 1053147191Sjkoshy break; 1054147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1055147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1056147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1057147191Sjkoshy __K8SETMASK(dc); 1058147191Sjkoshy break; 1059147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1060147191Sjkoshy __K8SETMASK(dobee); 1061147191Sjkoshy break; 1062147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1063147191Sjkoshy __K8SETMASK(ddpi); 1064147191Sjkoshy break; 1065147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1066147191Sjkoshy __K8SETMASK(dabl); 1067147191Sjkoshy break; 1068147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1069147191Sjkoshy __K8SETMASK(bilr); 1070147191Sjkoshy break; 1071147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1072147191Sjkoshy __K8SETMASK(bfrlm); 1073147191Sjkoshy break; 1074147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1075147191Sjkoshy __K8SETMASK(bfil); 1076147191Sjkoshy break; 1077147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1078147191Sjkoshy __K8SETMASK(frfi); 1079147191Sjkoshy break; 1080147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1081147191Sjkoshy __K8SETMASK(frfdoi); 1082147191Sjkoshy break; 1083147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1084147191Sjkoshy __K8SETMASK(ffe); 1085147191Sjkoshy break; 1086147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1087147191Sjkoshy __K8SETMASK(nmcpae); 1088147191Sjkoshy break; 1089147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1090147191Sjkoshy __K8SETMASK(nmct); 1091147191Sjkoshy break; 1092147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1093147191Sjkoshy __K8SETMASK(nmcbs); 1094147191Sjkoshy break; 1095147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1096147191Sjkoshy __K8SETMASK(nsc); 1097147191Sjkoshy break; 1098147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1099147191Sjkoshy __K8SETMASK(npr); 1100147191Sjkoshy break; 1101147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1102147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1103147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1104147191Sjkoshy __K8SETMASK(nhbb); 1105147191Sjkoshy break; 1106147191Sjkoshy 1107147191Sjkoshy default: 1108147191Sjkoshy break; /* no options defined */ 1109147191Sjkoshy } 1110147191Sjkoshy 1111147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1112147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1113147191Sjkoshy q = strchr(p, '='); 1114147191Sjkoshy if (*++q == '\0') /* skip '=' */ 1115174406Sjkoshy return (-1); 1116147191Sjkoshy 1117147191Sjkoshy count = strtol(q, &e, 0); 1118147191Sjkoshy if (e == q || *e != '\0') 1119174406Sjkoshy return (-1); 1120147191Sjkoshy 1121147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1122147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 1123147191Sjkoshy AMD_PMC_TO_COUNTER(count); 1124147191Sjkoshy 1125147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1126147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1127147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1128147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1129147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1130147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1131174406Sjkoshy return (-1); 1132147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1133147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1134147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1135147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1136147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1137147191Sjkoshy } else 1138174406Sjkoshy return (-1); 1139147191Sjkoshy } 1140147191Sjkoshy 1141147191Sjkoshy /* other post processing */ 1142147191Sjkoshy switch (pe) { 1143147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1144147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1145147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1146147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1147147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1148147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1149147191Sjkoshy /* XXX only available in rev B and later */ 1150147191Sjkoshy break; 1151147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1152147191Sjkoshy /* XXX only available in rev C and later */ 1153147191Sjkoshy break; 1154147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1155147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1156147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1157174406Sjkoshy return (-1); 1158147191Sjkoshy if (evmask == 0) { 1159147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1160147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1161147191Sjkoshy } 1162147191Sjkoshy break; 1163147191Sjkoshy default: 1164147191Sjkoshy if (evmask == 0 && pmask != NULL) { 1165147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1166147191Sjkoshy evmask |= pm->pm_value; 1167147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1168147191Sjkoshy } 1169147191Sjkoshy } 1170147191Sjkoshy 1171147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1172147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 1173147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 1174147191Sjkoshy 1175174406Sjkoshy return (0); 1176147191Sjkoshy} 1177147191Sjkoshy 1178147191Sjkoshy#endif 1179147191Sjkoshy 1180147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1181147191Sjkoshy 1182147191Sjkoshy/* 1183145256Sjkoshy * Intel P4 PMCs 1184145256Sjkoshy */ 1185145256Sjkoshy 1186145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 1187145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 1188145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 1189145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1190145351Sjkoshy EV_ALIAS("instructions", 1191145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 1192155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 1193145256Sjkoshy EV_ALIAS(NULL, NULL) 1194145256Sjkoshy}; 1195145256Sjkoshy 1196145256Sjkoshy#define P4_KW_ACTIVE "active" 1197145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 1198145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 1199145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 1200145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 1201145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 1202145256Sjkoshy#define P4_KW_CASCADE "cascade" 1203145256Sjkoshy#define P4_KW_EDGE "edge" 1204145256Sjkoshy#define P4_KW_INV "complement" 1205145256Sjkoshy#define P4_KW_OS "os" 1206145256Sjkoshy#define P4_KW_MASK "mask" 1207145256Sjkoshy#define P4_KW_PRECISE "precise" 1208145256Sjkoshy#define P4_KW_TAG "tag" 1209145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 1210145256Sjkoshy#define P4_KW_USR "usr" 1211145256Sjkoshy 1212145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 1213145256Sjkoshy 1214145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 1215145256Sjkoshy __P4MASK(dd, 0), 1216145256Sjkoshy __P4MASK(db, 1), 1217145256Sjkoshy __P4MASK(di, 2), 1218145256Sjkoshy __P4MASK(bd, 3), 1219145256Sjkoshy __P4MASK(bb, 4), 1220145256Sjkoshy __P4MASK(bi, 5), 1221145256Sjkoshy __P4MASK(id, 6), 1222145256Sjkoshy __P4MASK(ib, 7), 1223145256Sjkoshy NULLMASK 1224145256Sjkoshy}; 1225145256Sjkoshy 1226145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 1227145256Sjkoshy __P4MASK(tcmiss, 0), 1228145256Sjkoshy NULLMASK, 1229145256Sjkoshy}; 1230145256Sjkoshy 1231145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 1232145256Sjkoshy __P4MASK(hit, 0), 1233145256Sjkoshy __P4MASK(miss, 1), 1234145256Sjkoshy __P4MASK(hit-uc, 2), 1235145256Sjkoshy NULLMASK 1236145256Sjkoshy}; 1237145256Sjkoshy 1238145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 1239145256Sjkoshy __P4MASK(st-rb-full, 2), 1240145256Sjkoshy __P4MASK(64k-conf, 3), 1241145256Sjkoshy NULLMASK 1242145256Sjkoshy}; 1243145256Sjkoshy 1244145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 1245145256Sjkoshy __P4MASK(lsc, 0), 1246145256Sjkoshy __P4MASK(ssc, 1), 1247145256Sjkoshy NULLMASK 1248145256Sjkoshy}; 1249145256Sjkoshy 1250145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 1251145256Sjkoshy __P4MASK(split-ld, 1), 1252145256Sjkoshy NULLMASK 1253145256Sjkoshy}; 1254145256Sjkoshy 1255145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 1256145256Sjkoshy __P4MASK(split-st, 1), 1257145256Sjkoshy NULLMASK 1258145256Sjkoshy}; 1259145256Sjkoshy 1260145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 1261145256Sjkoshy __P4MASK(no-sta, 1), 1262145256Sjkoshy __P4MASK(no-std, 3), 1263145256Sjkoshy __P4MASK(partial-data, 4), 1264145256Sjkoshy __P4MASK(unalgn-addr, 5), 1265145256Sjkoshy NULLMASK 1266145256Sjkoshy}; 1267145256Sjkoshy 1268145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 1269145256Sjkoshy __P4MASK(dtmiss, 0), 1270145256Sjkoshy __P4MASK(itmiss, 1), 1271145256Sjkoshy NULLMASK 1272145256Sjkoshy}; 1273145256Sjkoshy 1274145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 1275145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 1276145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 1277145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 1278145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 1279145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 1280145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 1281145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 1282145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 1283145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 1284145256Sjkoshy NULLMASK 1285145256Sjkoshy}; 1286145256Sjkoshy 1287145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 1288145256Sjkoshy __P4MASK(all-read, 5), 1289145256Sjkoshy __P4MASK(all-write, 6), 1290145256Sjkoshy __P4MASK(mem-uc, 7), 1291145256Sjkoshy __P4MASK(mem-wc, 8), 1292145256Sjkoshy __P4MASK(mem-wt, 9), 1293145256Sjkoshy __P4MASK(mem-wp, 10), 1294145256Sjkoshy __P4MASK(mem-wb, 11), 1295145256Sjkoshy __P4MASK(own, 13), 1296145256Sjkoshy __P4MASK(other, 14), 1297145256Sjkoshy __P4MASK(prefetch, 15), 1298145256Sjkoshy NULLMASK 1299145256Sjkoshy}; 1300145256Sjkoshy 1301145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 1302145256Sjkoshy __P4MASK(all-read, 5), 1303145256Sjkoshy __P4MASK(all-write, 6), 1304145256Sjkoshy __P4MASK(mem-uc, 7), 1305145256Sjkoshy __P4MASK(mem-wc, 8), 1306145256Sjkoshy __P4MASK(mem-wt, 9), 1307145256Sjkoshy __P4MASK(mem-wp, 10), 1308145256Sjkoshy __P4MASK(mem-wb, 11), 1309145256Sjkoshy __P4MASK(own, 13), 1310145256Sjkoshy __P4MASK(other, 14), 1311145256Sjkoshy __P4MASK(prefetch, 15), 1312145256Sjkoshy NULLMASK 1313145256Sjkoshy}; 1314145256Sjkoshy 1315145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 1316145256Sjkoshy __P4MASK(drdy-drv, 0), 1317145256Sjkoshy __P4MASK(drdy-own, 1), 1318145256Sjkoshy __P4MASK(drdy-other, 2), 1319145256Sjkoshy __P4MASK(dbsy-drv, 3), 1320145256Sjkoshy __P4MASK(dbsy-own, 4), 1321145256Sjkoshy __P4MASK(dbsy-other, 5), 1322145256Sjkoshy NULLMASK 1323145256Sjkoshy}; 1324145256Sjkoshy 1325145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 1326145256Sjkoshy __P4MASK(req-type0, 0), 1327145256Sjkoshy __P4MASK(req-type1, 1), 1328145256Sjkoshy __P4MASK(req-len0, 2), 1329145256Sjkoshy __P4MASK(req-len1, 3), 1330145256Sjkoshy __P4MASK(req-io-type, 5), 1331145256Sjkoshy __P4MASK(req-lock-type, 6), 1332145256Sjkoshy __P4MASK(req-cache-type, 7), 1333145256Sjkoshy __P4MASK(req-split-type, 8), 1334145256Sjkoshy __P4MASK(req-dem-type, 9), 1335145256Sjkoshy __P4MASK(req-ord-type, 10), 1336145256Sjkoshy __P4MASK(mem-type0, 11), 1337145256Sjkoshy __P4MASK(mem-type1, 12), 1338145256Sjkoshy __P4MASK(mem-type2, 13), 1339145256Sjkoshy NULLMASK 1340145256Sjkoshy}; 1341145256Sjkoshy 1342145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 1343145256Sjkoshy __P4MASK(all, 15), 1344145256Sjkoshy NULLMASK 1345145256Sjkoshy}; 1346145256Sjkoshy 1347145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 1348145256Sjkoshy __P4MASK(all, 15), 1349145256Sjkoshy NULLMASK 1350145256Sjkoshy}; 1351145256Sjkoshy 1352145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 1353145256Sjkoshy __P4MASK(all, 15), 1354145256Sjkoshy NULLMASK 1355145256Sjkoshy}; 1356145256Sjkoshy 1357145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 1358145256Sjkoshy __P4MASK(all, 15), 1359145256Sjkoshy NULLMASK 1360145256Sjkoshy}; 1361145256Sjkoshy 1362145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 1363145256Sjkoshy __P4MASK(all, 15), 1364145256Sjkoshy NULLMASK 1365145256Sjkoshy}; 1366145256Sjkoshy 1367145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 1368145256Sjkoshy __P4MASK(all, 15), 1369145256Sjkoshy NULLMASK 1370145256Sjkoshy}; 1371145256Sjkoshy 1372145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 1373145256Sjkoshy __P4MASK(all, 15), 1374145256Sjkoshy NULLMASK 1375145256Sjkoshy}; 1376145256Sjkoshy 1377145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 1378145256Sjkoshy __P4MASK(all, 15), 1379145256Sjkoshy NULLMASK 1380145256Sjkoshy}; 1381145256Sjkoshy 1382145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 1383145256Sjkoshy __P4MASK(allp0, 3), 1384145256Sjkoshy __P4MASK(allp2, 4), 1385145256Sjkoshy NULLMASK 1386145256Sjkoshy}; 1387145256Sjkoshy 1388145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 1389145256Sjkoshy __P4MASK(running, 0), 1390145256Sjkoshy NULLMASK 1391145256Sjkoshy}; 1392145256Sjkoshy 1393145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 1394145256Sjkoshy __P4MASK(cisc, 0), 1395145256Sjkoshy NULLMASK 1396145256Sjkoshy}; 1397145256Sjkoshy 1398145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 1399145256Sjkoshy __P4MASK(from-tc-build, 0), 1400145256Sjkoshy __P4MASK(from-tc-deliver, 1), 1401145256Sjkoshy __P4MASK(from-rom, 2), 1402145256Sjkoshy NULLMASK 1403145256Sjkoshy}; 1404145256Sjkoshy 1405145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 1406145351Sjkoshy /* retired mispred branch type */ 1407145256Sjkoshy __P4MASK(conditional, 1), 1408145256Sjkoshy __P4MASK(call, 2), 1409145256Sjkoshy __P4MASK(return, 3), 1410145256Sjkoshy __P4MASK(indirect, 4), 1411145256Sjkoshy NULLMASK 1412145256Sjkoshy}; 1413145256Sjkoshy 1414145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 1415145256Sjkoshy __P4MASK(conditional, 1), 1416145256Sjkoshy __P4MASK(call, 2), 1417145256Sjkoshy __P4MASK(retired, 3), 1418145256Sjkoshy __P4MASK(indirect, 4), 1419145256Sjkoshy NULLMASK 1420145256Sjkoshy}; 1421145256Sjkoshy 1422145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 1423145256Sjkoshy __P4MASK(sbfull, 5), 1424145256Sjkoshy NULLMASK 1425145256Sjkoshy}; 1426145256Sjkoshy 1427145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 1428145256Sjkoshy __P4MASK(wcb-evicts, 0), 1429145256Sjkoshy __P4MASK(wcb-full-evict, 1), 1430145256Sjkoshy NULLMASK 1431145256Sjkoshy}; 1432145256Sjkoshy 1433145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 1434145256Sjkoshy __P4MASK(nbogus, 0), 1435145256Sjkoshy __P4MASK(bogus, 1), 1436145256Sjkoshy NULLMASK 1437145256Sjkoshy}; 1438145256Sjkoshy 1439145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 1440145256Sjkoshy __P4MASK(nbogus0, 0), 1441145256Sjkoshy __P4MASK(nbogus1, 1), 1442145256Sjkoshy __P4MASK(nbogus2, 2), 1443145256Sjkoshy __P4MASK(nbogus3, 3), 1444145256Sjkoshy __P4MASK(bogus0, 4), 1445145256Sjkoshy __P4MASK(bogus1, 5), 1446145256Sjkoshy __P4MASK(bogus2, 6), 1447145256Sjkoshy __P4MASK(bogus3, 7), 1448145256Sjkoshy NULLMASK 1449145256Sjkoshy}; 1450145256Sjkoshy 1451145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 1452145256Sjkoshy __P4MASK(nbogus, 0), 1453145256Sjkoshy __P4MASK(bogus, 1), 1454145256Sjkoshy NULLMASK 1455145256Sjkoshy}; 1456145256Sjkoshy 1457145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 1458145256Sjkoshy __P4MASK(nbogusntag, 0), 1459145256Sjkoshy __P4MASK(nbogustag, 1), 1460145256Sjkoshy __P4MASK(bogusntag, 2), 1461145256Sjkoshy __P4MASK(bogustag, 3), 1462145256Sjkoshy NULLMASK 1463145256Sjkoshy}; 1464145256Sjkoshy 1465145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 1466145256Sjkoshy __P4MASK(nbogus, 0), 1467145256Sjkoshy __P4MASK(bogus, 1), 1468145256Sjkoshy NULLMASK 1469145256Sjkoshy}; 1470145256Sjkoshy 1471145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 1472145256Sjkoshy __P4MASK(tagloads, 1), 1473145256Sjkoshy __P4MASK(tagstores, 2), 1474145256Sjkoshy NULLMASK 1475145256Sjkoshy}; 1476145256Sjkoshy 1477145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 1478145256Sjkoshy __P4MASK(mmnp, 0), 1479145256Sjkoshy __P4MASK(mmnm, 1), 1480145256Sjkoshy __P4MASK(mmtp, 2), 1481145256Sjkoshy __P4MASK(mmtm, 3), 1482145256Sjkoshy NULLMASK 1483145256Sjkoshy}; 1484145256Sjkoshy 1485145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 1486145256Sjkoshy __P4MASK(nbogus, 0), 1487145256Sjkoshy NULLMASK 1488145256Sjkoshy}; 1489145256Sjkoshy 1490145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 1491145256Sjkoshy __P4MASK(fpsu, 0), 1492145256Sjkoshy __P4MASK(fpso, 1), 1493145256Sjkoshy __P4MASK(poao, 2), 1494145256Sjkoshy __P4MASK(poau, 3), 1495145256Sjkoshy __P4MASK(prea, 4), 1496145256Sjkoshy NULLMASK 1497145256Sjkoshy}; 1498145256Sjkoshy 1499145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 1500145256Sjkoshy __P4MASK(clear, 0), 1501145256Sjkoshy __P4MASK(moclear, 2), 1502145256Sjkoshy __P4MASK(smclear, 3), 1503145256Sjkoshy NULLMASK 1504145256Sjkoshy}; 1505145256Sjkoshy 1506145256Sjkoshy/* P4 event parser */ 1507145256Sjkoshystatic int 1508145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1509145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1510145256Sjkoshy{ 1511145256Sjkoshy 1512145256Sjkoshy char *e, *p, *q; 1513145256Sjkoshy int count, has_tag, has_busreqtype, n; 1514145256Sjkoshy uint32_t evmask, cccractivemask; 1515145256Sjkoshy const struct pmc_masks *pm, *pmask; 1516145256Sjkoshy 1517183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1518147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1519147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1520145256Sjkoshy 1521145256Sjkoshy pmask = NULL; 1522145256Sjkoshy evmask = 0; 1523145256Sjkoshy cccractivemask = 0x3; 1524145256Sjkoshy has_tag = has_busreqtype = 0; 1525145256Sjkoshy 1526145256Sjkoshy#define __P4SETMASK(M) do { \ 1527183107Sjkoshy pmask = p4_mask_##M; \ 1528145256Sjkoshy} while (0) 1529145256Sjkoshy 1530145256Sjkoshy switch (pe) { 1531145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1532145256Sjkoshy __P4SETMASK(tcdm); 1533145256Sjkoshy break; 1534145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1535145256Sjkoshy __P4SETMASK(bfr); 1536145256Sjkoshy break; 1537145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1538145256Sjkoshy __P4SETMASK(ir); 1539145256Sjkoshy break; 1540145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1541145256Sjkoshy __P4SETMASK(memcan); 1542145256Sjkoshy break; 1543145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1544145256Sjkoshy __P4SETMASK(memcomp); 1545145256Sjkoshy break; 1546145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1547145256Sjkoshy __P4SETMASK(lpr); 1548145256Sjkoshy break; 1549145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1550145256Sjkoshy __P4SETMASK(spr); 1551145256Sjkoshy break; 1552145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1553145256Sjkoshy __P4SETMASK(mlr); 1554145256Sjkoshy break; 1555145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1556145256Sjkoshy __P4SETMASK(pwt); 1557145256Sjkoshy break; 1558145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1559145256Sjkoshy __P4SETMASK(bcr); 1560145256Sjkoshy break; 1561145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1562145256Sjkoshy __P4SETMASK(ia); 1563145256Sjkoshy has_busreqtype = 1; 1564145256Sjkoshy break; 1565145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1566145256Sjkoshy __P4SETMASK(iae); 1567145256Sjkoshy has_busreqtype = 1; 1568145256Sjkoshy break; 1569145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1570145256Sjkoshy __P4SETMASK(fda); 1571145256Sjkoshy break; 1572145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1573145256Sjkoshy __P4SETMASK(ba); 1574145256Sjkoshy break; 1575145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1576145256Sjkoshy __P4SETMASK(sia); 1577145256Sjkoshy break; 1578145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1579145256Sjkoshy __P4SETMASK(psu); 1580145256Sjkoshy break; 1581145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1582145256Sjkoshy __P4SETMASK(pdu); 1583145256Sjkoshy break; 1584145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1585145256Sjkoshy __P4SETMASK(ssu); 1586145256Sjkoshy break; 1587145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1588145256Sjkoshy __P4SETMASK(sdu); 1589145256Sjkoshy break; 1590145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1591145256Sjkoshy __P4SETMASK(64bmu); 1592145256Sjkoshy break; 1593145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1594145256Sjkoshy __P4SETMASK(128bmu); 1595145256Sjkoshy break; 1596145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1597145256Sjkoshy __P4SETMASK(xfu); 1598145256Sjkoshy break; 1599145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1600145256Sjkoshy __P4SETMASK(xsmu); 1601145256Sjkoshy break; 1602145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1603145256Sjkoshy __P4SETMASK(gpe); 1604145256Sjkoshy break; 1605145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1606145256Sjkoshy __P4SETMASK(tmx); 1607145256Sjkoshy break; 1608145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1609145256Sjkoshy __P4SETMASK(uqw); 1610145256Sjkoshy break; 1611145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1612145256Sjkoshy __P4SETMASK(rmbt); 1613145256Sjkoshy break; 1614145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1615145256Sjkoshy __P4SETMASK(rbt); 1616145256Sjkoshy break; 1617145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1618145256Sjkoshy __P4SETMASK(rs); 1619145256Sjkoshy break; 1620145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1621145256Sjkoshy __P4SETMASK(wb); 1622145256Sjkoshy break; 1623145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1624145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1625145256Sjkoshy case PMC_EV_P4_BNR: 1626145256Sjkoshy case PMC_EV_P4_SNOOP: 1627145256Sjkoshy case PMC_EV_P4_RESPONSE: 1628145256Sjkoshy break; 1629145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1630145256Sjkoshy __P4SETMASK(fee); 1631145256Sjkoshy break; 1632145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1633145256Sjkoshy __P4SETMASK(ee); 1634145256Sjkoshy break; 1635145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1636145256Sjkoshy __P4SETMASK(re); 1637145256Sjkoshy break; 1638145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1639145256Sjkoshy __P4SETMASK(insret); 1640145256Sjkoshy break; 1641145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1642145256Sjkoshy __P4SETMASK(ur); 1643145256Sjkoshy break; 1644145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1645145256Sjkoshy __P4SETMASK(ut); 1646145256Sjkoshy break; 1647145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1648145256Sjkoshy __P4SETMASK(br); 1649145256Sjkoshy break; 1650145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1651145256Sjkoshy __P4SETMASK(mbr); 1652145256Sjkoshy break; 1653145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1654145256Sjkoshy __P4SETMASK(xa); 1655145256Sjkoshy break; 1656145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1657145256Sjkoshy __P4SETMASK(machclr); 1658145256Sjkoshy break; 1659145256Sjkoshy default: 1660174406Sjkoshy return (-1); 1661145256Sjkoshy } 1662145256Sjkoshy 1663145256Sjkoshy /* process additional flags */ 1664145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1665145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1666145256Sjkoshy q = strchr(p, '='); 1667145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1668174406Sjkoshy return (-1); 1669145256Sjkoshy 1670183725Sjkoshy if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) 1671145256Sjkoshy cccractivemask = 0x0; 1672183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1673145256Sjkoshy cccractivemask = 0x1; 1674183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) 1675145256Sjkoshy cccractivemask = 0x2; 1676183725Sjkoshy else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) 1677145256Sjkoshy cccractivemask = 0x3; 1678145256Sjkoshy else 1679174406Sjkoshy return (-1); 1680145256Sjkoshy 1681145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1682145256Sjkoshy if (has_busreqtype == 0) 1683174406Sjkoshy return (-1); 1684145256Sjkoshy 1685145256Sjkoshy q = strchr(p, '='); 1686145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1687174406Sjkoshy return (-1); 1688145256Sjkoshy 1689145256Sjkoshy count = strtol(q, &e, 0); 1690145256Sjkoshy if (e == q || *e != '\0') 1691174406Sjkoshy return (-1); 1692145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1693145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1694145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1695145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1696145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1697145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1698145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1699145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1700145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1701174406Sjkoshy return (-1); 1702145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1703145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1704145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1705145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1706145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1707145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1708145256Sjkoshy if (has_tag == 0) 1709174406Sjkoshy return (-1); 1710145256Sjkoshy 1711145256Sjkoshy q = strchr(p, '='); 1712145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1713174406Sjkoshy return (-1); 1714145256Sjkoshy 1715145256Sjkoshy count = strtol(q, &e, 0); 1716145256Sjkoshy if (e == q || *e != '\0') 1717174406Sjkoshy return (-1); 1718145256Sjkoshy 1719145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1720147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1721145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1722145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1723145256Sjkoshy q = strchr(p, '='); 1724145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1725174406Sjkoshy return (-1); 1726145256Sjkoshy 1727145256Sjkoshy count = strtol(q, &e, 0); 1728145256Sjkoshy if (e == q || *e != '\0') 1729174406Sjkoshy return (-1); 1730145256Sjkoshy 1731145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1732147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1733147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1734147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1735147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1736145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1737145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1738145256Sjkoshy else 1739174406Sjkoshy return (-1); 1740145256Sjkoshy } 1741145256Sjkoshy 1742145256Sjkoshy /* other post processing */ 1743145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1744145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1745145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1746145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1747145256Sjkoshy 1748145256Sjkoshy /* fill in thread activity mask */ 1749147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1750145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1751145256Sjkoshy 1752145256Sjkoshy if (evmask) 1753145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1754145256Sjkoshy 1755145256Sjkoshy switch (pe) { 1756145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1757145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1758145256Sjkoshy (evmask & 0x18) == 0x18) 1759174406Sjkoshy return (-1); /* can't have own+other bits together */ 1760145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1761145256Sjkoshy evmask = 0x1D; 1762145256Sjkoshy break; 1763145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1764145256Sjkoshy /* only one bit is allowed to be set */ 1765145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1766174406Sjkoshy return (-1); 1767145256Sjkoshy if (evmask == 0) { 1768183107Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1769145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1770145256Sjkoshy } 1771145256Sjkoshy break; 1772145256Sjkoshy default: 1773145256Sjkoshy if (evmask == 0 && pmask) { 1774145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1775145256Sjkoshy evmask |= pm->pm_value; 1776145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1777145256Sjkoshy } 1778145256Sjkoshy } 1779145256Sjkoshy 1780147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1781147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1782145256Sjkoshy 1783174406Sjkoshy return (0); 1784145256Sjkoshy} 1785145256Sjkoshy 1786147759Sjkoshy#endif 1787147759Sjkoshy 1788147759Sjkoshy#if defined(__i386__) 1789147759Sjkoshy 1790145256Sjkoshy/* 1791147191Sjkoshy * Pentium style PMCs 1792147191Sjkoshy */ 1793147191Sjkoshy 1794147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1795183105Sjkoshy EV_ALIAS("branches", "p5-taken-branches"), 1796183105Sjkoshy EV_ALIAS("cycles", "tsc"), 1797183105Sjkoshy EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), 1798183105Sjkoshy EV_ALIAS("ic-misses", "p5-code-cache-miss"), 1799183105Sjkoshy EV_ALIAS("instructions", "p5-instructions-executed"), 1800183105Sjkoshy EV_ALIAS("interrupts", "p5-hardware-interrupts"), 1801183105Sjkoshy EV_ALIAS("unhalted-cycles", 1802183105Sjkoshy "p5-number-of-cycles-not-in-halt-state"), 1803147191Sjkoshy EV_ALIAS(NULL, NULL) 1804147191Sjkoshy}; 1805147191Sjkoshy 1806147191Sjkoshystatic int 1807147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1808147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1809147191Sjkoshy{ 1810174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1811147191Sjkoshy} 1812147191Sjkoshy 1813147191Sjkoshy/* 1814145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1815145256Sjkoshy * and Pentium M CPUs. 1816145256Sjkoshy */ 1817145256Sjkoshy 1818145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1819145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1820145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1821145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1822145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1823168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1824145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1825145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1826155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1827145351Sjkoshy EV_ALIAS(NULL, NULL) 1828145256Sjkoshy}; 1829145256Sjkoshy 1830145256Sjkoshy#define P6_KW_CMASK "cmask" 1831145256Sjkoshy#define P6_KW_EDGE "edge" 1832145256Sjkoshy#define P6_KW_INV "inv" 1833145256Sjkoshy#define P6_KW_OS "os" 1834145256Sjkoshy#define P6_KW_UMASK "umask" 1835145256Sjkoshy#define P6_KW_USR "usr" 1836145256Sjkoshy 1837145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1838145256Sjkoshy PMCMASK(m, 0x01), 1839145256Sjkoshy PMCMASK(e, 0x02), 1840145256Sjkoshy PMCMASK(s, 0x04), 1841145256Sjkoshy PMCMASK(i, 0x08), 1842145256Sjkoshy NULLMASK 1843145256Sjkoshy}; 1844145256Sjkoshy 1845145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1846145256Sjkoshy PMCMASK(m, 0x01), 1847145256Sjkoshy PMCMASK(e, 0x02), 1848145256Sjkoshy PMCMASK(s, 0x04), 1849145256Sjkoshy PMCMASK(i, 0x08), 1850145256Sjkoshy PMCMASK(nonhw, 0x00), 1851145256Sjkoshy PMCMASK(hw, 0x10), 1852145256Sjkoshy PMCMASK(both, 0x30), 1853145256Sjkoshy NULLMASK 1854145256Sjkoshy}; 1855145256Sjkoshy 1856145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1857145256Sjkoshy PMCMASK(nonhw, 0x00), 1858145256Sjkoshy PMCMASK(hw, 0x10), 1859145256Sjkoshy PMCMASK(both, 0x30), 1860145256Sjkoshy NULLMASK 1861145256Sjkoshy}; 1862145256Sjkoshy 1863145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1864145256Sjkoshy PMCMASK(self, 0x00), 1865145256Sjkoshy PMCMASK(any, 0x20), 1866145256Sjkoshy NULLMASK 1867145256Sjkoshy}; 1868145256Sjkoshy 1869145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1870145256Sjkoshy PMCMASK(nta, 0x00), 1871145256Sjkoshy PMCMASK(t1, 0x01), 1872145256Sjkoshy PMCMASK(t2, 0x02), 1873145256Sjkoshy PMCMASK(wos, 0x03), 1874145256Sjkoshy NULLMASK 1875145256Sjkoshy}; 1876145256Sjkoshy 1877145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1878145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1879145256Sjkoshy PMCMASK(scalar, 0x01), 1880145256Sjkoshy NULLMASK 1881145256Sjkoshy}; 1882145256Sjkoshy 1883145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1884145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1885145256Sjkoshy PMCMASK(packed-shift, 0x02), 1886145256Sjkoshy PMCMASK(pack, 0x04), 1887145256Sjkoshy PMCMASK(unpack, 0x08), 1888145256Sjkoshy PMCMASK(packed-logical, 0x10), 1889145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1890145256Sjkoshy NULLMASK 1891145256Sjkoshy}; 1892145256Sjkoshy 1893145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1894145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1895145256Sjkoshy PMCMASK(fptommx, 0x01), 1896145256Sjkoshy NULLMASK 1897145256Sjkoshy}; 1898145256Sjkoshy 1899145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1900145256Sjkoshy PMCMASK(es, 0x01), 1901145256Sjkoshy PMCMASK(ds, 0x02), 1902145256Sjkoshy PMCMASK(fs, 0x04), 1903145256Sjkoshy PMCMASK(gs, 0x08), 1904145256Sjkoshy NULLMASK 1905145256Sjkoshy}; 1906145256Sjkoshy 1907145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1908145256Sjkoshy PMCMASK(all, 0x00), 1909145256Sjkoshy PMCMASK(freq, 0x02), 1910145256Sjkoshy NULLMASK 1911145256Sjkoshy}; 1912145256Sjkoshy 1913145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1914145256Sjkoshy PMCMASK(all, 0x00), 1915145256Sjkoshy PMCMASK(loadop, 0x01), 1916145256Sjkoshy PMCMASK(stdsta, 0x02), 1917145256Sjkoshy NULLMASK 1918145256Sjkoshy}; 1919145256Sjkoshy 1920145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1921145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1922145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1923145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1924145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1925145256Sjkoshy NULLMASK 1926145256Sjkoshy}; 1927145256Sjkoshy 1928145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1929145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1930145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1931145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1932145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1933145256Sjkoshy NULLMASK 1934145256Sjkoshy}; 1935145256Sjkoshy 1936145256Sjkoshy/* P6 event parser */ 1937145256Sjkoshystatic int 1938145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1939145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1940145256Sjkoshy{ 1941145256Sjkoshy char *e, *p, *q; 1942145256Sjkoshy uint32_t evmask; 1943145256Sjkoshy int count, n; 1944145256Sjkoshy const struct pmc_masks *pm, *pmask; 1945145256Sjkoshy 1946183725Sjkoshy pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 1947147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1948145256Sjkoshy 1949145256Sjkoshy evmask = 0; 1950145256Sjkoshy 1951145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1952145256Sjkoshy 1953145256Sjkoshy switch(pe) { 1954183107Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1955145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1956145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1957145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1958145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1959145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1960145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1961145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1962145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1963145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1964145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1965145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1966145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1967145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1968145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1969145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1970145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1971145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1972145256Sjkoshy P6MASKSET(any); break; 1973145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1974145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1975145256Sjkoshy P6MASKSET(ekp); break; 1976145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1977145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1978145256Sjkoshy P6MASKSET(pps); break; 1979145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 1980145256Sjkoshy P6MASKSET(mite); break; 1981145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1982145256Sjkoshy P6MASKSET(fmt); break; 1983145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 1984145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 1985145256Sjkoshy P6MASKSET(sr); break; 1986145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1987145256Sjkoshy P6MASKSET(eet); break; 1988145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1989145256Sjkoshy P6MASKSET(efur); break; 1990145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1991145256Sjkoshy P6MASKSET(essir); break; 1992145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1993145256Sjkoshy P6MASKSET(esscir); break; 1994145256Sjkoshy default: 1995145256Sjkoshy pmask = NULL; 1996145256Sjkoshy break; 1997145256Sjkoshy } 1998145256Sjkoshy 1999145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 2000145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 2001145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 2002145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 2003145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 2004145256Sjkoshy P6MASKSET(mesihw); 2005145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 2006145256Sjkoshy P6MASKSET(hw); 2007145256Sjkoshy } 2008145256Sjkoshy 2009145256Sjkoshy /* Parse additional modifiers if present */ 2010145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 2011145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 2012145256Sjkoshy q = strchr(p, '='); 2013145256Sjkoshy if (*++q == '\0') /* skip '=' */ 2014174406Sjkoshy return (-1); 2015145256Sjkoshy count = strtol(q, &e, 0); 2016145256Sjkoshy if (e == q || *e != '\0') 2017174406Sjkoshy return (-1); 2018145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 2019147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2020147191Sjkoshy P6_EVSEL_TO_CMASK(count); 2021145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 2022145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 2023145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 2024145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 2025145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 2026145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2027145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 2028145256Sjkoshy evmask = 0; 2029145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 2030174406Sjkoshy return (-1); 2031145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 2032145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 2033145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 2034145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 2035145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 2036145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 2037145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 2038145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 2039145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 2040145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 2041145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 2042145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 2043145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 2044145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 2045145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 2046145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 2047145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 2048145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 2049145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 2050145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 2051145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 2052145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 2053145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 2054174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 2055174406Sjkoshy return (-1); 2056145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2057145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 2058145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 2059145256Sjkoshy } else 2060174406Sjkoshy return (-1); 2061145256Sjkoshy } 2062145256Sjkoshy 2063145256Sjkoshy /* post processing */ 2064145256Sjkoshy switch (pe) { 2065145256Sjkoshy 2066145256Sjkoshy /* 2067145256Sjkoshy * The following events default to an evmask of 0 2068145256Sjkoshy */ 2069145256Sjkoshy 2070145256Sjkoshy /* default => 'self' */ 2071145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 2072145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 2073145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 2074145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 2075145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 2076145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 2077145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 2078145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 2079145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 2080145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 2081145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 2082145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 2083145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 2084145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 2085145256Sjkoshy 2086145256Sjkoshy /* default => 'nta' */ 2087145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 2088145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 2089145256Sjkoshy 2090145256Sjkoshy /* default => 'packed and scalar' */ 2091145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 2092145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 2093145256Sjkoshy 2094145256Sjkoshy /* default => 'mmx to fp transitions' */ 2095145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 2096145256Sjkoshy 2097145256Sjkoshy /* default => 'SSE Packed Single' */ 2098145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 2099145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 2100145256Sjkoshy 2101145256Sjkoshy /* default => 'all fused micro-ops' */ 2102145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 2103145256Sjkoshy 2104145256Sjkoshy /* default => 'all transitions' */ 2105145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 2106145256Sjkoshy break; 2107145256Sjkoshy 2108145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 2109145256Sjkoshy evmask = 0x0F; /* only value allowed */ 2110145256Sjkoshy break; 2111145256Sjkoshy 2112145256Sjkoshy default: 2113145256Sjkoshy /* 2114145256Sjkoshy * For all other events, set the default event mask 2115145256Sjkoshy * to a logical OR of all the allowed event mask bits. 2116145256Sjkoshy */ 2117145256Sjkoshy if (evmask == 0 && pmask) { 2118145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 2119145256Sjkoshy evmask |= pm->pm_value; 2120145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 2121145256Sjkoshy } 2122145256Sjkoshy 2123145256Sjkoshy break; 2124145256Sjkoshy } 2125145256Sjkoshy 2126145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 2127147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 2128147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 2129145256Sjkoshy 2130174406Sjkoshy return (0); 2131145256Sjkoshy} 2132145256Sjkoshy 2133147191Sjkoshy#endif 2134147191Sjkoshy 2135183725Sjkoshy#if defined(__i386__) || defined(__amd64__) 2136183725Sjkoshystatic int 2137183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec, 2138183725Sjkoshy struct pmc_op_pmcallocate *pmc_config) 2139183725Sjkoshy{ 2140183725Sjkoshy if (pe != PMC_EV_TSC_TSC) 2141183725Sjkoshy return (-1); 2142183725Sjkoshy 2143183725Sjkoshy /* TSC events must be unqualified. */ 2144183725Sjkoshy if (ctrspec && *ctrspec != '\0') 2145183725Sjkoshy return (-1); 2146183725Sjkoshy 2147183725Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 2148183725Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 2149183725Sjkoshy 2150183725Sjkoshy return (0); 2151183725Sjkoshy} 2152183725Sjkoshy#endif 2153183725Sjkoshy 2154200928Srpaulo#if defined(__XSCALE__) 2155200928Srpaulo 2156200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = { 2157200928Srpaulo EV_ALIAS("branches", "BRANCH_RETIRED"), 2158200928Srpaulo EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2159200928Srpaulo EV_ALIAS("dc-misses", "DC_MISS"), 2160200928Srpaulo EV_ALIAS("ic-misses", "IC_MISS"), 2161200928Srpaulo EV_ALIAS("instructions", "INSTR_RETIRED"), 2162200928Srpaulo EV_ALIAS(NULL, NULL) 2163200928Srpaulo}; 2164200928Srpaulostatic int 2165200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2166200928Srpaulo struct pmc_op_pmcallocate *pmc_config __unused) 2167200928Srpaulo{ 2168200928Srpaulo switch (pe) { 2169200928Srpaulo default: 2170200928Srpaulo break; 2171200928Srpaulo } 2172200928Srpaulo 2173200928Srpaulo return (0); 2174200928Srpaulo} 2175200928Srpaulo#endif 2176200928Srpaulo 2177204635Sgnn#if defined(__mips__) 2178204635Sgnn 2179204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = { 2180204635Sgnn EV_ALIAS("instructions", "INSTR_EXECUTED"), 2181204635Sgnn EV_ALIAS("branches", "BRANCH_COMPLETED"), 2182204635Sgnn EV_ALIAS("branch-mispredicts", "BRANCH_MISPRED"), 2183204635Sgnn EV_ALIAS(NULL, NULL) 2184204635Sgnn}; 2185204635Sgnn 2186204635Sgnn#define MIPS24K_KW_OS "os" 2187204635Sgnn#define MIPS24K_KW_USR "usr" 2188204635Sgnn#define MIPS24K_KW_ANYTHREAD "anythread" 2189204635Sgnn 2190204635Sgnnstatic int 2191204635Sgnnmips24k_allocate_pmc(enum pmc_event pe, char *ctrspec __unused, 2192204635Sgnn struct pmc_op_pmcallocate *pmc_config __unused) 2193204635Sgnn{ 2194204635Sgnn char *p; 2195204635Sgnn 2196204635Sgnn (void) pe; 2197204635Sgnn 2198204635Sgnn pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 2199204635Sgnn 2200204635Sgnn while ((p = strsep(&ctrspec, ",")) != NULL) { 2201204635Sgnn if (KWMATCH(p, MIPS24K_KW_OS)) 2202204635Sgnn pmc_config->pm_caps |= PMC_CAP_SYSTEM; 2203204635Sgnn else if (KWMATCH(p, MIPS24K_KW_USR)) 2204204635Sgnn pmc_config->pm_caps |= PMC_CAP_USER; 2205204635Sgnn else if (KWMATCH(p, MIPS24K_KW_ANYTHREAD)) 2206204635Sgnn pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM); 2207204635Sgnn else 2208204635Sgnn return (-1); 2209204635Sgnn } 2210204635Sgnn 2211204635Sgnn return (0); 2212204635Sgnn} 2213204635Sgnn#endif /* __mips__ */ 2214204635Sgnn 2215204635Sgnn 2216145256Sjkoshy/* 2217183725Sjkoshy * Match an event name `name' with its canonical form. 2218183725Sjkoshy * 2219185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and 2220185363Sjkoshy * hyphen characters are considered to match each other. 2221185363Sjkoshy * 2222183725Sjkoshy * Returns 1 for a match, 0 otherwise. 2223183725Sjkoshy */ 2224183725Sjkoshy 2225183725Sjkoshystatic int 2226183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname) 2227183725Sjkoshy{ 2228183725Sjkoshy int cc, nc; 2229183725Sjkoshy const unsigned char *c, *n; 2230183725Sjkoshy 2231183725Sjkoshy c = (const unsigned char *) canonicalname; 2232183725Sjkoshy n = (const unsigned char *) name; 2233183725Sjkoshy 2234183725Sjkoshy for (; (nc = *n) && (cc = *c); n++, c++) { 2235183725Sjkoshy 2236185363Sjkoshy if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') && 2237185363Sjkoshy (cc == ' ' || cc == '_' || cc == '-' || cc == '.')) 2238183725Sjkoshy continue; 2239183725Sjkoshy 2240185363Sjkoshy if (toupper(nc) == toupper(cc)) 2241183725Sjkoshy continue; 2242183725Sjkoshy 2243185363Sjkoshy 2244183725Sjkoshy return (0); 2245183725Sjkoshy } 2246183725Sjkoshy 2247183725Sjkoshy if (*n == '\0' && *c == '\0') 2248183725Sjkoshy return (1); 2249183725Sjkoshy 2250183725Sjkoshy return (0); 2251183725Sjkoshy} 2252183725Sjkoshy 2253183725Sjkoshy/* 2254183725Sjkoshy * Match an event name against all the event named supported by a 2255183725Sjkoshy * PMC class. 2256183725Sjkoshy * 2257183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise. 2258183725Sjkoshy */ 2259183725Sjkoshystatic const struct pmc_event_descr * 2260183725Sjkoshypmc_match_event_class(const char *name, 2261183725Sjkoshy const struct pmc_class_descr *pcd) 2262183725Sjkoshy{ 2263183725Sjkoshy size_t n; 2264183725Sjkoshy const struct pmc_event_descr *ev; 2265185363Sjkoshy 2266183725Sjkoshy ev = pcd->pm_evc_event_table; 2267183725Sjkoshy for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++) 2268183725Sjkoshy if (pmc_match_event_name(name, ev->pm_ev_name)) 2269183725Sjkoshy return (ev); 2270183725Sjkoshy 2271183725Sjkoshy return (NULL); 2272183725Sjkoshy} 2273183725Sjkoshy 2274183725Sjkoshystatic int 2275183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc) 2276183725Sjkoshy{ 2277183725Sjkoshy size_t n; 2278183725Sjkoshy 2279183725Sjkoshy for (n = 0; n < pmc_mdep_class_list_size; n++) 2280183725Sjkoshy if (pmc_mdep_class_list[n] == pc) 2281183725Sjkoshy return (1); 2282183725Sjkoshy return (0); 2283183725Sjkoshy} 2284183725Sjkoshy 2285183725Sjkoshy/* 2286147191Sjkoshy * API entry points 2287145256Sjkoshy */ 2288145256Sjkoshy 2289147191Sjkoshyint 2290147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 2291147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 2292145256Sjkoshy{ 2293183725Sjkoshy size_t n; 2294147191Sjkoshy int retval; 2295147191Sjkoshy char *r, *spec_copy; 2296147191Sjkoshy const char *ctrname; 2297183725Sjkoshy const struct pmc_event_descr *ev; 2298183725Sjkoshy const struct pmc_event_alias *alias; 2299147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 2300183725Sjkoshy const struct pmc_class_descr *pcd; 2301145256Sjkoshy 2302147191Sjkoshy spec_copy = NULL; 2303147191Sjkoshy retval = -1; 2304145256Sjkoshy 2305147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 2306147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 2307147191Sjkoshy errno = EINVAL; 2308147191Sjkoshy goto out; 2309147191Sjkoshy } 2310145256Sjkoshy 2311147191Sjkoshy /* replace an event alias with the canonical event specifier */ 2312147191Sjkoshy if (pmc_mdep_event_aliases) 2313183725Sjkoshy for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++) 2314183725Sjkoshy if (!strcasecmp(ctrspec, alias->pm_alias)) { 2315183725Sjkoshy spec_copy = strdup(alias->pm_spec); 2316147191Sjkoshy break; 2317147191Sjkoshy } 2318145256Sjkoshy 2319147191Sjkoshy if (spec_copy == NULL) 2320147191Sjkoshy spec_copy = strdup(ctrspec); 2321145256Sjkoshy 2322147191Sjkoshy r = spec_copy; 2323147191Sjkoshy ctrname = strsep(&r, ","); 2324145256Sjkoshy 2325183725Sjkoshy /* 2326183725Sjkoshy * If a explicit class prefix was given by the user, restrict the 2327183725Sjkoshy * search for the event to the specified PMC class. 2328183725Sjkoshy */ 2329183725Sjkoshy ev = NULL; 2330185363Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) { 2331185363Sjkoshy pcd = pmc_class_table[n]; 2332183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) && 2333183725Sjkoshy strncasecmp(ctrname, pcd->pm_evc_name, 2334183725Sjkoshy pcd->pm_evc_name_size) == 0) { 2335183725Sjkoshy if ((ev = pmc_match_event_class(ctrname + 2336183725Sjkoshy pcd->pm_evc_name_size, pcd)) == NULL) { 2337183725Sjkoshy errno = EINVAL; 2338183725Sjkoshy goto out; 2339183725Sjkoshy } 2340147191Sjkoshy break; 2341183725Sjkoshy } 2342183725Sjkoshy } 2343145256Sjkoshy 2344183725Sjkoshy /* 2345183725Sjkoshy * Otherwise, search for this event in all compatible PMC 2346183725Sjkoshy * classes. 2347183725Sjkoshy */ 2348185363Sjkoshy for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) { 2349185363Sjkoshy pcd = pmc_class_table[n]; 2350183725Sjkoshy if (pmc_mdep_is_compatible_class(pcd->pm_evc_class)) 2351183725Sjkoshy ev = pmc_match_event_class(ctrname, pcd); 2352183725Sjkoshy } 2353183725Sjkoshy 2354183725Sjkoshy if (ev == NULL) { 2355147191Sjkoshy errno = EINVAL; 2356147191Sjkoshy goto out; 2357147191Sjkoshy } 2358145256Sjkoshy 2359147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 2360183725Sjkoshy pmc_config.pm_ev = ev->pm_ev_code; 2361183725Sjkoshy pmc_config.pm_class = pcd->pm_evc_class; 2362147191Sjkoshy pmc_config.pm_cpu = cpu; 2363147191Sjkoshy pmc_config.pm_mode = mode; 2364147191Sjkoshy pmc_config.pm_flags = flags; 2365145256Sjkoshy 2366147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 2367147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 2368145256Sjkoshy 2369183725Sjkoshy if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) { 2370147191Sjkoshy errno = EINVAL; 2371147191Sjkoshy goto out; 2372147191Sjkoshy } 2373145256Sjkoshy 2374147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 2375147191Sjkoshy goto out; 2376145256Sjkoshy 2377147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 2378145256Sjkoshy 2379147191Sjkoshy retval = 0; 2380145256Sjkoshy 2381147191Sjkoshy out: 2382147191Sjkoshy if (spec_copy) 2383147191Sjkoshy free(spec_copy); 2384145256Sjkoshy 2385174406Sjkoshy return (retval); 2386147191Sjkoshy} 2387145256Sjkoshy 2388147191Sjkoshyint 2389147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 2390147191Sjkoshy{ 2391147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 2392145256Sjkoshy 2393147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 2394147191Sjkoshy pmc_attach_args.pm_pid = pid; 2395145256Sjkoshy 2396174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 2397147191Sjkoshy} 2398145256Sjkoshy 2399147191Sjkoshyint 2400147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2401147191Sjkoshy{ 2402147191Sjkoshy unsigned int i; 2403147191Sjkoshy enum pmc_class cl; 2404145256Sjkoshy 2405147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2406147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2407147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2408147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2409174406Sjkoshy return (0); 2410147191Sjkoshy } 2411177107Sjkoshy errno = EINVAL; 2412177107Sjkoshy return (-1); 2413147191Sjkoshy} 2414145256Sjkoshy 2415147191Sjkoshyint 2416147191Sjkoshypmc_configure_logfile(int fd) 2417147191Sjkoshy{ 2418147191Sjkoshy struct pmc_op_configurelog cla; 2419145256Sjkoshy 2420147191Sjkoshy cla.pm_logfd = fd; 2421147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 2422174406Sjkoshy return (-1); 2423174406Sjkoshy return (0); 2424147191Sjkoshy} 2425145256Sjkoshy 2426147191Sjkoshyint 2427147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 2428147191Sjkoshy{ 2429147191Sjkoshy if (pmc_syscall == -1) { 2430147191Sjkoshy errno = ENXIO; 2431174406Sjkoshy return (-1); 2432147191Sjkoshy } 2433145256Sjkoshy 2434147219Sjkoshy *pci = &cpu_info; 2435174406Sjkoshy return (0); 2436147191Sjkoshy} 2437145256Sjkoshy 2438147191Sjkoshyint 2439147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 2440147191Sjkoshy{ 2441147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 2442145256Sjkoshy 2443147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 2444147191Sjkoshy pmc_detach_args.pm_pid = pid; 2445174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 2446147191Sjkoshy} 2447147191Sjkoshy 2448147191Sjkoshyint 2449147191Sjkoshypmc_disable(int cpu, int pmc) 2450145256Sjkoshy{ 2451147191Sjkoshy struct pmc_op_pmcadmin ssa; 2452145256Sjkoshy 2453147191Sjkoshy ssa.pm_cpu = cpu; 2454147191Sjkoshy ssa.pm_pmc = pmc; 2455147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 2456174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2457147191Sjkoshy} 2458145256Sjkoshy 2459147191Sjkoshyint 2460147191Sjkoshypmc_enable(int cpu, int pmc) 2461147191Sjkoshy{ 2462147191Sjkoshy struct pmc_op_pmcadmin ssa; 2463145256Sjkoshy 2464147191Sjkoshy ssa.pm_cpu = cpu; 2465147191Sjkoshy ssa.pm_pmc = pmc; 2466147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 2467174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 2468147191Sjkoshy} 2469145256Sjkoshy 2470147191Sjkoshy/* 2471147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2472147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2473147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2474147191Sjkoshy * the number of event name pointers returned. 2475147191Sjkoshy * 2476147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2477147191Sjkoshy * is responsible for freeing this space when done. 2478147191Sjkoshy */ 2479147191Sjkoshyint 2480147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2481147191Sjkoshy int *nevents) 2482147191Sjkoshy{ 2483147191Sjkoshy int count; 2484147191Sjkoshy const char **names; 2485147191Sjkoshy const struct pmc_event_descr *ev; 2486147191Sjkoshy 2487147191Sjkoshy switch (cl) 2488147191Sjkoshy { 2489185363Sjkoshy case PMC_CLASS_IAF: 2490185363Sjkoshy ev = iaf_event_table; 2491185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(iaf); 2492185363Sjkoshy break; 2493185363Sjkoshy case PMC_CLASS_IAP: 2494185363Sjkoshy /* 2495185363Sjkoshy * Return the most appropriate set of event name 2496185363Sjkoshy * spellings for the current CPU. 2497185363Sjkoshy */ 2498185363Sjkoshy switch (cpu_info.pm_cputype) { 2499185363Sjkoshy default: 2500185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2501185363Sjkoshy ev = atom_event_table; 2502185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(atom); 2503185363Sjkoshy break; 2504185363Sjkoshy case PMC_CPU_INTEL_CORE: 2505185363Sjkoshy ev = core_event_table; 2506185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core); 2507185363Sjkoshy break; 2508185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2509185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2510185363Sjkoshy ev = core2_event_table; 2511185363Sjkoshy count = PMC_EVENT_TABLE_SIZE(core2); 2512185363Sjkoshy break; 2513187761Sjeff case PMC_CPU_INTEL_COREI7: 2514187761Sjeff ev = corei7_event_table; 2515187761Sjeff count = PMC_EVENT_TABLE_SIZE(corei7); 2516187761Sjeff break; 2517206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2518206089Sfabient ev = westmere_event_table; 2519206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmere); 2520206089Sfabient break; 2521185363Sjkoshy } 2522185363Sjkoshy break; 2523206089Sfabient case PMC_CLASS_UCF: 2524206089Sfabient ev = ucf_event_table; 2525206089Sfabient count = PMC_EVENT_TABLE_SIZE(ucf); 2526206089Sfabient break; 2527206089Sfabient case PMC_CLASS_UCP: 2528206089Sfabient /* 2529206089Sfabient * Return the most appropriate set of event name 2530206089Sfabient * spellings for the current CPU. 2531206089Sfabient */ 2532206089Sfabient switch (cpu_info.pm_cputype) { 2533206089Sfabient default: 2534206089Sfabient case PMC_CPU_INTEL_COREI7: 2535206089Sfabient ev = corei7uc_event_table; 2536206089Sfabient count = PMC_EVENT_TABLE_SIZE(corei7uc); 2537206089Sfabient break; 2538206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2539206089Sfabient ev = westmereuc_event_table; 2540206089Sfabient count = PMC_EVENT_TABLE_SIZE(westmereuc); 2541206089Sfabient break; 2542206089Sfabient } 2543206089Sfabient break; 2544147191Sjkoshy case PMC_CLASS_TSC: 2545183725Sjkoshy ev = tsc_event_table; 2546183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(tsc); 2547145256Sjkoshy break; 2548147191Sjkoshy case PMC_CLASS_K7: 2549183725Sjkoshy ev = k7_event_table; 2550183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k7); 2551145256Sjkoshy break; 2552147191Sjkoshy case PMC_CLASS_K8: 2553183725Sjkoshy ev = k8_event_table; 2554183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(k8); 2555145256Sjkoshy break; 2556183725Sjkoshy case PMC_CLASS_P4: 2557183725Sjkoshy ev = p4_event_table; 2558183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p4); 2559183725Sjkoshy break; 2560147191Sjkoshy case PMC_CLASS_P5: 2561183725Sjkoshy ev = p5_event_table; 2562183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p5); 2563145256Sjkoshy break; 2564147191Sjkoshy case PMC_CLASS_P6: 2565183725Sjkoshy ev = p6_event_table; 2566183725Sjkoshy count = PMC_EVENT_TABLE_SIZE(p6); 2567145256Sjkoshy break; 2568200928Srpaulo case PMC_CLASS_XSCALE: 2569200928Srpaulo ev = xscale_event_table; 2570200928Srpaulo count = PMC_EVENT_TABLE_SIZE(xscale); 2571200928Srpaulo break; 2572204635Sgnn case PMC_CLASS_MIPS24K: 2573204635Sgnn ev = mips24k_event_table; 2574204635Sgnn count = PMC_EVENT_TABLE_SIZE(mips24k); 2575204635Sgnn break; 2576145256Sjkoshy default: 2577147191Sjkoshy errno = EINVAL; 2578174406Sjkoshy return (-1); 2579145256Sjkoshy } 2580145256Sjkoshy 2581147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2582174406Sjkoshy return (-1); 2583145256Sjkoshy 2584147191Sjkoshy *eventnames = names; 2585147191Sjkoshy *nevents = count; 2586145256Sjkoshy 2587147191Sjkoshy for (;count--; ev++, names++) 2588147191Sjkoshy *names = ev->pm_ev_name; 2589174406Sjkoshy return (0); 2590147191Sjkoshy} 2591145256Sjkoshy 2592147191Sjkoshyint 2593147191Sjkoshypmc_flush_logfile(void) 2594147191Sjkoshy{ 2595174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 2596147191Sjkoshy} 2597145256Sjkoshy 2598147191Sjkoshyint 2599226514Sfabientpmc_close_logfile(void) 2600226514Sfabient{ 2601226514Sfabient return (PMC_CALL(CLOSELOG,0)); 2602226514Sfabient} 2603226514Sfabient 2604226514Sfabientint 2605147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 2606147191Sjkoshy{ 2607147191Sjkoshy struct pmc_op_getdriverstats gms; 2608145256Sjkoshy 2609147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 2610174406Sjkoshy return (-1); 2611145256Sjkoshy 2612147191Sjkoshy /* copy out fields in the current userland<->library interface */ 2613147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 2614147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 2615147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 2616147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 2617147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 2618147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 2619147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 2620147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 2621174406Sjkoshy return (0); 2622147191Sjkoshy} 2623145256Sjkoshy 2624147191Sjkoshyint 2625147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 2626147191Sjkoshy{ 2627147191Sjkoshy struct pmc_op_getmsr gm; 2628147191Sjkoshy 2629147191Sjkoshy gm.pm_pmcid = pmc; 2630147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 2631174406Sjkoshy return (-1); 2632147191Sjkoshy *msr = gm.pm_msr; 2633174406Sjkoshy return (0); 2634145256Sjkoshy} 2635145256Sjkoshy 2636145256Sjkoshyint 2637145256Sjkoshypmc_init(void) 2638145256Sjkoshy{ 2639145256Sjkoshy int error, pmc_mod_id; 2640147219Sjkoshy unsigned int n; 2641145256Sjkoshy uint32_t abi_version; 2642145256Sjkoshy struct module_stat pmc_modstat; 2643147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 2644198433Sjkoshy#if defined(__amd64__) || defined(__i386__) 2645198433Sjkoshy int cpu_has_iaf_counters; 2646198433Sjkoshy unsigned int t; 2647198433Sjkoshy#endif 2648145256Sjkoshy 2649145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 2650174406Sjkoshy return (0); 2651145256Sjkoshy 2652145256Sjkoshy /* retrieve the system call number from the KLD */ 2653145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 2654174406Sjkoshy return (-1); 2655145256Sjkoshy 2656145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 2657145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 2658174406Sjkoshy return (-1); 2659145256Sjkoshy 2660145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 2661145256Sjkoshy 2662147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 2663147191Sjkoshy abi_version = PMC_VERSION; 2664145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 2665145256Sjkoshy return (pmc_syscall = -1); 2666145256Sjkoshy 2667147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 2668147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 2669145256Sjkoshy errno = EPROGMISMATCH; 2670145256Sjkoshy return (pmc_syscall = -1); 2671145256Sjkoshy } 2672145256Sjkoshy 2673147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 2674145256Sjkoshy return (pmc_syscall = -1); 2675145256Sjkoshy 2676147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 2677147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 2678147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 2679147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 2680147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 2681147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 2682147219Sjkoshy 2683185363Sjkoshy pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE * 2684185363Sjkoshy sizeof(struct pmc_class_descr *)); 2685185363Sjkoshy 2686185363Sjkoshy if (pmc_class_table == NULL) 2687185363Sjkoshy return (-1); 2688185363Sjkoshy 2689198433Sjkoshy for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) 2690198433Sjkoshy pmc_class_table[n] = NULL; 2691185363Sjkoshy 2692185363Sjkoshy /* 2693185363Sjkoshy * Fill in the class table. 2694185363Sjkoshy */ 2695185363Sjkoshy n = 0; 2696185363Sjkoshy#if defined(__amd64__) || defined(__i386__) 2697185363Sjkoshy pmc_class_table[n++] = &tsc_class_table_descr; 2698198433Sjkoshy 2699198433Sjkoshy /* 2700198433Sjkoshy * Check if this CPU has fixed function counters. 2701198433Sjkoshy */ 2702198433Sjkoshy cpu_has_iaf_counters = 0; 2703198433Sjkoshy for (t = 0; t < cpu_info.pm_nclass; t++) 2704212224Sfabient if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF && 2705212224Sfabient cpu_info.pm_classes[t].pm_num > 0) 2706198433Sjkoshy cpu_has_iaf_counters = 1; 2707185363Sjkoshy#endif 2708185363Sjkoshy 2709183725Sjkoshy#define PMC_MDEP_INIT(C) do { \ 2710183725Sjkoshy pmc_mdep_event_aliases = C##_aliases; \ 2711183725Sjkoshy pmc_mdep_class_list = C##_pmc_classes; \ 2712183725Sjkoshy pmc_mdep_class_list_size = \ 2713183725Sjkoshy PMC_TABLE_SIZE(C##_pmc_classes); \ 2714183725Sjkoshy } while (0) 2715183725Sjkoshy 2716198433Sjkoshy#define PMC_MDEP_INIT_INTEL_V2(C) do { \ 2717198433Sjkoshy PMC_MDEP_INIT(C); \ 2718212224Sfabient pmc_class_table[n++] = &iaf_class_table_descr; \ 2719212224Sfabient if (!cpu_has_iaf_counters) \ 2720198433Sjkoshy pmc_mdep_event_aliases = \ 2721198433Sjkoshy C##_aliases_without_iaf; \ 2722198433Sjkoshy pmc_class_table[n] = &C##_class_table_descr; \ 2723198433Sjkoshy } while (0) 2724198433Sjkoshy 2725183725Sjkoshy /* Configure the event name parser. */ 2726145256Sjkoshy switch (cpu_info.pm_cputype) { 2727145340Smarcel#if defined(__i386__) 2728145256Sjkoshy case PMC_CPU_AMD_K7: 2729183725Sjkoshy PMC_MDEP_INIT(k7); 2730185363Sjkoshy pmc_class_table[n] = &k7_class_table_descr; 2731145256Sjkoshy break; 2732145256Sjkoshy case PMC_CPU_INTEL_P5: 2733183725Sjkoshy PMC_MDEP_INIT(p5); 2734185363Sjkoshy pmc_class_table[n] = &p5_class_table_descr; 2735145256Sjkoshy break; 2736145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 2737145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 2738145256Sjkoshy case PMC_CPU_INTEL_PIII: 2739145256Sjkoshy case PMC_CPU_INTEL_PM: 2740183725Sjkoshy PMC_MDEP_INIT(p6); 2741185363Sjkoshy pmc_class_table[n] = &p6_class_table_descr; 2742145256Sjkoshy break; 2743147759Sjkoshy#endif 2744147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 2745183725Sjkoshy case PMC_CPU_AMD_K8: 2746183725Sjkoshy PMC_MDEP_INIT(k8); 2747185363Sjkoshy pmc_class_table[n] = &k8_class_table_descr; 2748183725Sjkoshy break; 2749185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2750198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(atom); 2751185363Sjkoshy break; 2752185363Sjkoshy case PMC_CPU_INTEL_CORE: 2753185363Sjkoshy PMC_MDEP_INIT(core); 2754202157Sjkoshy pmc_class_table[n] = &core_class_table_descr; 2755185363Sjkoshy break; 2756185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2757185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2758198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(core2); 2759185363Sjkoshy break; 2760187761Sjeff case PMC_CPU_INTEL_COREI7: 2761206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2762206089Sfabient pmc_class_table[n++] = &corei7uc_class_table_descr; 2763198433Sjkoshy PMC_MDEP_INIT_INTEL_V2(corei7); 2764187761Sjeff break; 2765206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2766206089Sfabient pmc_class_table[n++] = &ucf_class_table_descr; 2767206089Sfabient pmc_class_table[n++] = &westmereuc_class_table_descr; 2768206089Sfabient PMC_MDEP_INIT_INTEL_V2(westmere); 2769206089Sfabient break; 2770145256Sjkoshy case PMC_CPU_INTEL_PIV: 2771183725Sjkoshy PMC_MDEP_INIT(p4); 2772185363Sjkoshy pmc_class_table[n] = &p4_class_table_descr; 2773145256Sjkoshy break; 2774145256Sjkoshy#endif 2775200928Srpaulo#if defined(__XSCALE__) 2776200928Srpaulo case PMC_CPU_INTEL_XSCALE: 2777200928Srpaulo PMC_MDEP_INIT(xscale); 2778200928Srpaulo pmc_class_table[n] = &xscale_class_table_descr; 2779200928Srpaulo break; 2780200928Srpaulo#endif 2781204635Sgnn#if defined(__mips__) 2782204635Sgnn case PMC_CPU_MIPS_24K: 2783204635Sgnn PMC_MDEP_INIT(mips24k); 2784204635Sgnn pmc_class_table[n] = &mips24k_class_table_descr; 2785204635Sgnn break; 2786204635Sgnn#endif /* __mips__ */ 2787145256Sjkoshy default: 2788145256Sjkoshy /* 2789145256Sjkoshy * Some kind of CPU this version of the library knows nothing 2790145256Sjkoshy * about. This shouldn't happen since the abi version check 2791145256Sjkoshy * should have caught this. 2792145256Sjkoshy */ 2793145256Sjkoshy errno = ENXIO; 2794145256Sjkoshy return (pmc_syscall = -1); 2795145256Sjkoshy } 2796145256Sjkoshy 2797174406Sjkoshy return (0); 2798145256Sjkoshy} 2799145256Sjkoshy 2800147191Sjkoshyconst char * 2801147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 2802145256Sjkoshy{ 2803147191Sjkoshy int i; 2804145256Sjkoshy 2805147191Sjkoshy /* 2806147191Sjkoshy * 'cap' should have a single bit set and should be in 2807147191Sjkoshy * range. 2808147191Sjkoshy */ 2809147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 2810147191Sjkoshy cap > PMC_CAP_LAST) { 2811145256Sjkoshy errno = EINVAL; 2812174406Sjkoshy return (NULL); 2813145256Sjkoshy } 2814145256Sjkoshy 2815147191Sjkoshy i = ffs(cap); 2816174406Sjkoshy return (pmc_capability_names[i - 1]); 2817147191Sjkoshy} 2818145256Sjkoshy 2819147191Sjkoshyconst char * 2820147191Sjkoshypmc_name_of_class(enum pmc_class pc) 2821147191Sjkoshy{ 2822147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 2823147191Sjkoshy pc <= PMC_CLASS_LAST) 2824174406Sjkoshy return (pmc_class_names[pc]); 2825145256Sjkoshy 2826147191Sjkoshy errno = EINVAL; 2827174406Sjkoshy return (NULL); 2828147191Sjkoshy} 2829145256Sjkoshy 2830147191Sjkoshyconst char * 2831147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2832147191Sjkoshy{ 2833183725Sjkoshy size_t n; 2834183725Sjkoshy 2835183725Sjkoshy for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++) 2836183725Sjkoshy if (cp == pmc_cputype_names[n].pm_cputype) 2837183725Sjkoshy return (pmc_cputype_names[n].pm_name); 2838183725Sjkoshy 2839147191Sjkoshy errno = EINVAL; 2840174406Sjkoshy return (NULL); 2841147191Sjkoshy} 2842145256Sjkoshy 2843147191Sjkoshyconst char * 2844147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2845147191Sjkoshy{ 2846147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2847147191Sjkoshy pd <= PMC_DISP_LAST) 2848174406Sjkoshy return (pmc_disposition_names[pd]); 2849145256Sjkoshy 2850147191Sjkoshy errno = EINVAL; 2851174406Sjkoshy return (NULL); 2852147191Sjkoshy} 2853145256Sjkoshy 2854147191Sjkoshyconst char * 2855185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu) 2856147191Sjkoshy{ 2857183725Sjkoshy const struct pmc_event_descr *ev, *evfence; 2858145256Sjkoshy 2859183725Sjkoshy ev = evfence = NULL; 2860185363Sjkoshy if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) { 2861185363Sjkoshy ev = iaf_event_table; 2862185363Sjkoshy evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf); 2863185363Sjkoshy } else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) { 2864185363Sjkoshy switch (cpu) { 2865185363Sjkoshy case PMC_CPU_INTEL_ATOM: 2866185363Sjkoshy ev = atom_event_table; 2867185363Sjkoshy evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom); 2868185363Sjkoshy break; 2869185363Sjkoshy case PMC_CPU_INTEL_CORE: 2870185363Sjkoshy ev = core_event_table; 2871185363Sjkoshy evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core); 2872185363Sjkoshy break; 2873185363Sjkoshy case PMC_CPU_INTEL_CORE2: 2874185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 2875185363Sjkoshy ev = core2_event_table; 2876185363Sjkoshy evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2); 2877185363Sjkoshy break; 2878187761Sjeff case PMC_CPU_INTEL_COREI7: 2879187761Sjeff ev = corei7_event_table; 2880187761Sjeff evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7); 2881187761Sjeff break; 2882206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2883206089Sfabient ev = westmere_event_table; 2884206089Sfabient evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere); 2885206089Sfabient break; 2886185363Sjkoshy default: /* Unknown CPU type. */ 2887185363Sjkoshy break; 2888185363Sjkoshy } 2889206089Sfabient } else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) { 2890206089Sfabient ev = ucf_event_table; 2891206089Sfabient evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf); 2892206089Sfabient } else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) { 2893206089Sfabient switch (cpu) { 2894206089Sfabient case PMC_CPU_INTEL_COREI7: 2895206089Sfabient ev = corei7uc_event_table; 2896206089Sfabient evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc); 2897206089Sfabient break; 2898206089Sfabient case PMC_CPU_INTEL_WESTMERE: 2899206089Sfabient ev = westmereuc_event_table; 2900206089Sfabient evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc); 2901206089Sfabient break; 2902206089Sfabient default: /* Unknown CPU type. */ 2903206089Sfabient break; 2904206089Sfabient } 2905206089Sfabient } else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) { 2906183725Sjkoshy ev = k7_event_table; 2907183725Sjkoshy evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7); 2908183725Sjkoshy } else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) { 2909183725Sjkoshy ev = k8_event_table; 2910183725Sjkoshy evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8); 2911183725Sjkoshy } else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) { 2912183725Sjkoshy ev = p4_event_table; 2913183725Sjkoshy evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4); 2914183725Sjkoshy } else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) { 2915183725Sjkoshy ev = p5_event_table; 2916183725Sjkoshy evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5); 2917183725Sjkoshy } else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) { 2918183725Sjkoshy ev = p6_event_table; 2919183725Sjkoshy evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6); 2920200928Srpaulo } else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) { 2921200928Srpaulo ev = xscale_event_table; 2922200928Srpaulo evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale); 2923204635Sgnn } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { 2924204635Sgnn ev = mips24k_event_table; 2925204635Sgnn evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k 2926204635Sgnn); 2927183725Sjkoshy } else if (pe == PMC_EV_TSC_TSC) { 2928183725Sjkoshy ev = tsc_event_table; 2929183725Sjkoshy evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); 2930183725Sjkoshy } 2931183725Sjkoshy 2932183725Sjkoshy for (; ev != evfence; ev++) 2933183725Sjkoshy if (pe == ev->pm_ev_code) 2934183725Sjkoshy return (ev->pm_ev_name); 2935183725Sjkoshy 2936185363Sjkoshy return (NULL); 2937185363Sjkoshy} 2938185363Sjkoshy 2939185363Sjkoshyconst char * 2940185363Sjkoshypmc_name_of_event(enum pmc_event pe) 2941185363Sjkoshy{ 2942185363Sjkoshy const char *n; 2943185363Sjkoshy 2944185363Sjkoshy if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL) 2945185363Sjkoshy return (n); 2946185363Sjkoshy 2947147191Sjkoshy errno = EINVAL; 2948174406Sjkoshy return (NULL); 2949147191Sjkoshy} 2950145256Sjkoshy 2951147191Sjkoshyconst char * 2952147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 2953147191Sjkoshy{ 2954147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 2955147191Sjkoshy pm <= PMC_MODE_LAST) 2956174406Sjkoshy return (pmc_mode_names[pm]); 2957145256Sjkoshy 2958147191Sjkoshy errno = EINVAL; 2959174406Sjkoshy return (NULL); 2960147191Sjkoshy} 2961145256Sjkoshy 2962147191Sjkoshyconst char * 2963147191Sjkoshypmc_name_of_state(enum pmc_state ps) 2964147191Sjkoshy{ 2965147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 2966147191Sjkoshy ps <= PMC_STATE_LAST) 2967174406Sjkoshy return (pmc_state_names[ps]); 2968145256Sjkoshy 2969147191Sjkoshy errno = EINVAL; 2970174406Sjkoshy return (NULL); 2971145256Sjkoshy} 2972145256Sjkoshy 2973145256Sjkoshyint 2974147191Sjkoshypmc_ncpu(void) 2975145256Sjkoshy{ 2976147191Sjkoshy if (pmc_syscall == -1) { 2977147191Sjkoshy errno = ENXIO; 2978174406Sjkoshy return (-1); 2979147191Sjkoshy } 2980145256Sjkoshy 2981174406Sjkoshy return (cpu_info.pm_ncpu); 2982145256Sjkoshy} 2983145256Sjkoshy 2984145256Sjkoshyint 2985147191Sjkoshypmc_npmc(int cpu) 2986145256Sjkoshy{ 2987147191Sjkoshy if (pmc_syscall == -1) { 2988147191Sjkoshy errno = ENXIO; 2989174406Sjkoshy return (-1); 2990147191Sjkoshy } 2991145256Sjkoshy 2992147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 2993147191Sjkoshy errno = EINVAL; 2994174406Sjkoshy return (-1); 2995147191Sjkoshy } 2996145256Sjkoshy 2997174406Sjkoshy return (cpu_info.pm_npmc); 2998145256Sjkoshy} 2999145256Sjkoshy 3000145256Sjkoshyint 3001147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 3002145256Sjkoshy{ 3003147191Sjkoshy int nbytes, npmc; 3004147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 3005145256Sjkoshy 3006147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 3007174406Sjkoshy return (-1); 3008145256Sjkoshy 3009147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 3010147191Sjkoshy npmc * sizeof(struct pmc_info); 3011145256Sjkoshy 3012147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 3013174406Sjkoshy return (-1); 3014145256Sjkoshy 3015147191Sjkoshy pmci->pm_cpu = cpu; 3016145256Sjkoshy 3017147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 3018147191Sjkoshy free(pmci); 3019174406Sjkoshy return (-1); 3020147191Sjkoshy } 3021145256Sjkoshy 3022147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 3023147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 3024174406Sjkoshy return (0); 3025145256Sjkoshy} 3026145256Sjkoshy 3027145256Sjkoshyint 3028145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 3029145256Sjkoshy{ 3030145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 3031145256Sjkoshy 3032145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 3033145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 3034145256Sjkoshy pmc_read_op.pm_value = -1; 3035145256Sjkoshy 3036145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 3037174406Sjkoshy return (-1); 3038145256Sjkoshy 3039145256Sjkoshy *value = pmc_read_op.pm_value; 3040174406Sjkoshy return (0); 3041145256Sjkoshy} 3042145256Sjkoshy 3043145256Sjkoshyint 3044147191Sjkoshypmc_release(pmc_id_t pmc) 3045145256Sjkoshy{ 3046147191Sjkoshy struct pmc_op_simple pmc_release_args; 3047145256Sjkoshy 3048147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 3049174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 3050145256Sjkoshy} 3051145256Sjkoshy 3052145256Sjkoshyint 3053145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 3054145256Sjkoshy{ 3055145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 3056145256Sjkoshy 3057145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 3058145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 3059145256Sjkoshy pmc_rw_op.pm_value = newvalue; 3060145256Sjkoshy 3061145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 3062174406Sjkoshy return (-1); 3063145256Sjkoshy 3064145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 3065174406Sjkoshy return (0); 3066145256Sjkoshy} 3067145256Sjkoshy 3068145256Sjkoshyint 3069145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 3070145256Sjkoshy{ 3071145256Sjkoshy struct pmc_op_pmcsetcount sc; 3072145256Sjkoshy 3073145256Sjkoshy sc.pm_pmcid = pmc; 3074145256Sjkoshy sc.pm_count = value; 3075145256Sjkoshy 3076145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 3077174406Sjkoshy return (-1); 3078174406Sjkoshy return (0); 3079145256Sjkoshy} 3080145256Sjkoshy 3081145256Sjkoshyint 3082147191Sjkoshypmc_start(pmc_id_t pmc) 3083145256Sjkoshy{ 3084147191Sjkoshy struct pmc_op_simple pmc_start_args; 3085145256Sjkoshy 3086147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 3087174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 3088145256Sjkoshy} 3089145256Sjkoshy 3090145256Sjkoshyint 3091147191Sjkoshypmc_stop(pmc_id_t pmc) 3092145256Sjkoshy{ 3093147191Sjkoshy struct pmc_op_simple pmc_stop_args; 3094145256Sjkoshy 3095147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 3096174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 3097145256Sjkoshy} 3098145256Sjkoshy 3099145256Sjkoshyint 3100145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 3101145774Sjkoshy{ 3102145774Sjkoshy unsigned int i; 3103145774Sjkoshy enum pmc_class cl; 3104145774Sjkoshy 3105145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 3106145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 3107145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 3108145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 3109174406Sjkoshy return (0); 3110145774Sjkoshy } 3111177107Sjkoshy errno = EINVAL; 3112177107Sjkoshy return (-1); 3113145774Sjkoshy} 3114145774Sjkoshy 3115145774Sjkoshyint 3116147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 3117145774Sjkoshy{ 3118147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 3119145774Sjkoshy 3120147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 3121147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 3122147191Sjkoshy pmc_write_op.pm_value = value; 3123174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 3124145256Sjkoshy} 3125145256Sjkoshy 3126145256Sjkoshyint 3127147191Sjkoshypmc_writelog(uint32_t userdata) 3128145256Sjkoshy{ 3129147191Sjkoshy struct pmc_op_writelog wl; 3130145256Sjkoshy 3131147191Sjkoshy wl.pm_userdata = userdata; 3132174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 3133145256Sjkoshy} 3134