libpmc.c revision 145774
1145256Sjkoshy/*- 2145256Sjkoshy * Copyright (c) 2003,2004 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 145774 2005-05-01 14:11:49Z jkoshy $"); 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 45145256Sjkoshy/* Function prototypes */ 46145340Smarcel#if defined(__i386__) 47145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 48145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 49145256Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 50145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 51145256Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 52145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 53145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 54145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 55145340Smarcel#elif defined(__amd64__) 56145256Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 57145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 58145256Sjkoshy#endif 59145256Sjkoshy 60145256Sjkoshy#define PMC_CALL(cmd, params) \ 61145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 62145256Sjkoshy 63145256Sjkoshy/* 64145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 65145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 66145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 67145256Sjkoshy * lookup table. 68145256Sjkoshy */ 69145256Sjkoshy 70145256Sjkoshystruct pmc_event_alias { 71145256Sjkoshy const char *pm_alias; 72145256Sjkoshy const char *pm_spec; 73145256Sjkoshy}; 74145256Sjkoshy 75145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 76145256Sjkoshy 77145256Sjkoshy/* 78145256Sjkoshy * The pmc_event_descr table maps symbolic names known to the user 79145256Sjkoshy * to integer codes used by the PMC KLD. 80145256Sjkoshy */ 81145256Sjkoshy 82145256Sjkoshystruct pmc_event_descr { 83145256Sjkoshy const char *pm_ev_name; 84145256Sjkoshy enum pmc_event pm_ev_code; 85145256Sjkoshy enum pmc_class pm_ev_class; 86145256Sjkoshy}; 87145256Sjkoshy 88145256Sjkoshystatic const struct pmc_event_descr 89145256Sjkoshypmc_event_table[] = 90145256Sjkoshy{ 91145256Sjkoshy#undef __PMC_EV 92145256Sjkoshy#define __PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C }, 93145256Sjkoshy __PMC_EVENTS() 94145256Sjkoshy}; 95145256Sjkoshy 96145256Sjkoshy/* 97145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 98145256Sjkoshy * strings. 99145256Sjkoshy */ 100145256Sjkoshy 101145256Sjkoshystatic const char * pmc_capability_names[] = { 102145256Sjkoshy#undef __PMC_CAP 103145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 104145256Sjkoshy __PMC_CAPS() 105145256Sjkoshy}; 106145256Sjkoshy 107145256Sjkoshystatic const char * pmc_class_names[] = { 108145256Sjkoshy#undef __PMC_CLASS 109145256Sjkoshy#define __PMC_CLASS(C) #C , 110145256Sjkoshy __PMC_CLASSES() 111145256Sjkoshy}; 112145256Sjkoshy 113145256Sjkoshystatic const char * pmc_cputype_names[] = { 114145256Sjkoshy#undef __PMC_CPU 115145256Sjkoshy#define __PMC_CPU(S, D) #S , 116145256Sjkoshy __PMC_CPUS() 117145256Sjkoshy}; 118145256Sjkoshy 119145256Sjkoshystatic const char * pmc_disposition_names[] = { 120145256Sjkoshy#undef __PMC_DISP 121145256Sjkoshy#define __PMC_DISP(D) #D , 122145256Sjkoshy __PMC_DISPOSITIONS() 123145256Sjkoshy}; 124145256Sjkoshy 125145256Sjkoshystatic const char * pmc_mode_names[] = { 126145256Sjkoshy#undef __PMC_MODE 127145256Sjkoshy#define __PMC_MODE(M,N) #M , 128145256Sjkoshy __PMC_MODES() 129145256Sjkoshy}; 130145256Sjkoshy 131145256Sjkoshystatic const char * pmc_state_names[] = { 132145256Sjkoshy#undef __PMC_STATE 133145256Sjkoshy#define __PMC_STATE(S) #S , 134145256Sjkoshy __PMC_STATES() 135145256Sjkoshy}; 136145256Sjkoshy 137145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 138145256Sjkoshy 139145256Sjkoshystruct pmc_op_getcpuinfo cpu_info; /* filled in by pmc_init() */ 140145256Sjkoshy 141145256Sjkoshy/* Architecture dependent event parsing */ 142145256Sjkoshystatic int (*pmc_mdep_allocate_pmc)(enum pmc_event _pe, char *_ctrspec, 143145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 144145256Sjkoshy 145145256Sjkoshy/* Event masks for events */ 146145256Sjkoshystruct pmc_masks { 147145256Sjkoshy const char *pm_name; 148145256Sjkoshy const uint32_t pm_value; 149145256Sjkoshy}; 150145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 151145256Sjkoshy#define NULLMASK PMCMASK(NULL,0) 152145256Sjkoshy 153145340Smarcel#if defined(__i386__) || defined(__amd64__) 154145256Sjkoshystatic int 155145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 156145256Sjkoshy{ 157145256Sjkoshy const struct pmc_masks *pm; 158145256Sjkoshy char *q, *r; 159145256Sjkoshy int c; 160145256Sjkoshy 161145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 162145256Sjkoshy return -1; 163145256Sjkoshy q = strchr(p, '='); /* skip '=' */ 164145256Sjkoshy if (*++q == '\0') /* no more data */ 165145256Sjkoshy return -1; 166145256Sjkoshy c = 0; /* count of mask keywords seen */ 167145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 168145256Sjkoshy for (pm = pmask; pm->pm_name && strcmp(r, pm->pm_name); pm++) 169145256Sjkoshy ; 170145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 171145256Sjkoshy return -1; 172145256Sjkoshy *evmask |= pm->pm_value; 173145256Sjkoshy c++; 174145256Sjkoshy } 175145256Sjkoshy return c; 176145256Sjkoshy} 177145340Smarcel#endif 178145256Sjkoshy 179145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 180145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 181145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 182145256Sjkoshy 183145340Smarcel#if defined(__i386__) 184145256Sjkoshy 185145256Sjkoshy/* 186145256Sjkoshy * AMD K7 (Athlon) CPUs. 187145256Sjkoshy */ 188145256Sjkoshy 189145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 190145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 191145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 192145351Sjkoshy EV_ALIAS("cycles", "tsc"), 193145351Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses,mask=moesi"), 194145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 195145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 196145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 197145351Sjkoshy EV_ALIAS(NULL, NULL) 198145256Sjkoshy}; 199145256Sjkoshy 200145256Sjkoshy#define K7_KW_COUNT "count" 201145256Sjkoshy#define K7_KW_EDGE "edge" 202145256Sjkoshy#define K7_KW_INV "inv" 203145256Sjkoshy#define K7_KW_OS "os" 204145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 205145256Sjkoshy#define K7_KW_USR "usr" 206145256Sjkoshy 207145256Sjkoshystatic int 208145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 209145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 210145256Sjkoshy{ 211145256Sjkoshy char *e, *p, *q; 212145256Sjkoshy int c, has_unitmask; 213145256Sjkoshy uint32_t count, unitmask; 214145256Sjkoshy 215145256Sjkoshy pmc_config->pm_amd_config = 0; 216145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 217145256Sjkoshy 218145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 219145256Sjkoshy /* TSC events must be unqualified. */ 220145256Sjkoshy if (ctrspec && *ctrspec != '\0') 221145256Sjkoshy return -1; 222145256Sjkoshy return 0; 223145256Sjkoshy } 224145256Sjkoshy 225145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 226145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 227145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 228145256Sjkoshy has_unitmask = 1; 229145256Sjkoshy unitmask = K7_PMC_UNITMASK_MOESI; 230145256Sjkoshy } else 231145256Sjkoshy unitmask = has_unitmask = 0; 232145256Sjkoshy 233145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 234145256Sjkoshy 235145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 236145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 237145256Sjkoshy q = strchr(p, '='); 238145256Sjkoshy if (*++q == '\0') /* skip '=' */ 239145256Sjkoshy return -1; 240145256Sjkoshy 241145256Sjkoshy count = strtol(q, &e, 0); 242145256Sjkoshy if (e == q || *e != '\0') 243145256Sjkoshy return -1; 244145256Sjkoshy 245145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 246145256Sjkoshy pmc_config->pm_amd_config |= K7_PMC_TO_COUNTER(count); 247145256Sjkoshy 248145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 249145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 250145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 251145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 252145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 253145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 254145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 255145256Sjkoshy if (has_unitmask == 0) 256145256Sjkoshy return -1; 257145256Sjkoshy unitmask = 0; 258145256Sjkoshy q = strchr(p, '='); 259145256Sjkoshy if (*++q == '\0') /* skip '=' */ 260145256Sjkoshy return -1; 261145256Sjkoshy 262145256Sjkoshy while ((c = tolower(*q++)) != 0) 263145256Sjkoshy if (c == 'm') 264145256Sjkoshy unitmask |= K7_PMC_UNITMASK_M; 265145256Sjkoshy else if (c == 'o') 266145256Sjkoshy unitmask |= K7_PMC_UNITMASK_O; 267145256Sjkoshy else if (c == 'e') 268145256Sjkoshy unitmask |= K7_PMC_UNITMASK_E; 269145256Sjkoshy else if (c == 's') 270145256Sjkoshy unitmask |= K7_PMC_UNITMASK_S; 271145256Sjkoshy else if (c == 'i') 272145256Sjkoshy unitmask |= K7_PMC_UNITMASK_I; 273145256Sjkoshy else if (c == '+') 274145256Sjkoshy continue; 275145256Sjkoshy else 276145256Sjkoshy return -1; 277145256Sjkoshy 278145256Sjkoshy if (unitmask == 0) 279145256Sjkoshy return -1; 280145256Sjkoshy 281145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 282145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 283145256Sjkoshy } else 284145256Sjkoshy return -1; 285145256Sjkoshy } 286145256Sjkoshy 287145256Sjkoshy if (has_unitmask) { 288145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 289145256Sjkoshy pmc_config->pm_amd_config |= 290145256Sjkoshy K7_PMC_TO_UNITMASK(unitmask); 291145256Sjkoshy } 292145256Sjkoshy 293145256Sjkoshy return 0; 294145256Sjkoshy 295145256Sjkoshy} 296145256Sjkoshy 297145256Sjkoshy/* 298145256Sjkoshy * Intel P4 PMCs 299145256Sjkoshy */ 300145256Sjkoshy 301145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 302145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 303145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 304145351Sjkoshy EV_ALIAS("cycles", "tsc"), 305145351Sjkoshy EV_ALIAS("instructions", 306145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 307145256Sjkoshy EV_ALIAS(NULL, NULL) 308145256Sjkoshy}; 309145256Sjkoshy 310145256Sjkoshy#define P4_KW_ACTIVE "active" 311145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 312145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 313145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 314145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 315145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 316145256Sjkoshy#define P4_KW_CASCADE "cascade" 317145256Sjkoshy#define P4_KW_EDGE "edge" 318145256Sjkoshy#define P4_KW_INV "complement" 319145256Sjkoshy#define P4_KW_OS "os" 320145256Sjkoshy#define P4_KW_MASK "mask" 321145256Sjkoshy#define P4_KW_PRECISE "precise" 322145256Sjkoshy#define P4_KW_TAG "tag" 323145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 324145256Sjkoshy#define P4_KW_USR "usr" 325145256Sjkoshy 326145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 327145256Sjkoshy 328145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 329145256Sjkoshy __P4MASK(dd, 0), 330145256Sjkoshy __P4MASK(db, 1), 331145256Sjkoshy __P4MASK(di, 2), 332145256Sjkoshy __P4MASK(bd, 3), 333145256Sjkoshy __P4MASK(bb, 4), 334145256Sjkoshy __P4MASK(bi, 5), 335145256Sjkoshy __P4MASK(id, 6), 336145256Sjkoshy __P4MASK(ib, 7), 337145256Sjkoshy NULLMASK 338145256Sjkoshy}; 339145256Sjkoshy 340145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 341145256Sjkoshy __P4MASK(tcmiss, 0), 342145256Sjkoshy NULLMASK, 343145256Sjkoshy}; 344145256Sjkoshy 345145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 346145256Sjkoshy __P4MASK(hit, 0), 347145256Sjkoshy __P4MASK(miss, 1), 348145256Sjkoshy __P4MASK(hit-uc, 2), 349145256Sjkoshy NULLMASK 350145256Sjkoshy}; 351145256Sjkoshy 352145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 353145256Sjkoshy __P4MASK(st-rb-full, 2), 354145256Sjkoshy __P4MASK(64k-conf, 3), 355145256Sjkoshy NULLMASK 356145256Sjkoshy}; 357145256Sjkoshy 358145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 359145256Sjkoshy __P4MASK(lsc, 0), 360145256Sjkoshy __P4MASK(ssc, 1), 361145256Sjkoshy NULLMASK 362145256Sjkoshy}; 363145256Sjkoshy 364145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 365145256Sjkoshy __P4MASK(split-ld, 1), 366145256Sjkoshy NULLMASK 367145256Sjkoshy}; 368145256Sjkoshy 369145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 370145256Sjkoshy __P4MASK(split-st, 1), 371145256Sjkoshy NULLMASK 372145256Sjkoshy}; 373145256Sjkoshy 374145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 375145256Sjkoshy __P4MASK(no-sta, 1), 376145256Sjkoshy __P4MASK(no-std, 3), 377145256Sjkoshy __P4MASK(partial-data, 4), 378145256Sjkoshy __P4MASK(unalgn-addr, 5), 379145256Sjkoshy NULLMASK 380145256Sjkoshy}; 381145256Sjkoshy 382145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 383145256Sjkoshy __P4MASK(dtmiss, 0), 384145256Sjkoshy __P4MASK(itmiss, 1), 385145256Sjkoshy NULLMASK 386145256Sjkoshy}; 387145256Sjkoshy 388145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 389145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 390145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 391145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 392145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 393145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 394145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 395145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 396145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 397145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 398145256Sjkoshy NULLMASK 399145256Sjkoshy}; 400145256Sjkoshy 401145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 402145256Sjkoshy __P4MASK(all-read, 5), 403145256Sjkoshy __P4MASK(all-write, 6), 404145256Sjkoshy __P4MASK(mem-uc, 7), 405145256Sjkoshy __P4MASK(mem-wc, 8), 406145256Sjkoshy __P4MASK(mem-wt, 9), 407145256Sjkoshy __P4MASK(mem-wp, 10), 408145256Sjkoshy __P4MASK(mem-wb, 11), 409145256Sjkoshy __P4MASK(own, 13), 410145256Sjkoshy __P4MASK(other, 14), 411145256Sjkoshy __P4MASK(prefetch, 15), 412145256Sjkoshy NULLMASK 413145256Sjkoshy}; 414145256Sjkoshy 415145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 416145256Sjkoshy __P4MASK(all-read, 5), 417145256Sjkoshy __P4MASK(all-write, 6), 418145256Sjkoshy __P4MASK(mem-uc, 7), 419145256Sjkoshy __P4MASK(mem-wc, 8), 420145256Sjkoshy __P4MASK(mem-wt, 9), 421145256Sjkoshy __P4MASK(mem-wp, 10), 422145256Sjkoshy __P4MASK(mem-wb, 11), 423145256Sjkoshy __P4MASK(own, 13), 424145256Sjkoshy __P4MASK(other, 14), 425145256Sjkoshy __P4MASK(prefetch, 15), 426145256Sjkoshy NULLMASK 427145256Sjkoshy}; 428145256Sjkoshy 429145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 430145256Sjkoshy __P4MASK(drdy-drv, 0), 431145256Sjkoshy __P4MASK(drdy-own, 1), 432145256Sjkoshy __P4MASK(drdy-other, 2), 433145256Sjkoshy __P4MASK(dbsy-drv, 3), 434145256Sjkoshy __P4MASK(dbsy-own, 4), 435145256Sjkoshy __P4MASK(dbsy-other, 5), 436145256Sjkoshy NULLMASK 437145256Sjkoshy}; 438145256Sjkoshy 439145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 440145256Sjkoshy __P4MASK(req-type0, 0), 441145256Sjkoshy __P4MASK(req-type1, 1), 442145256Sjkoshy __P4MASK(req-len0, 2), 443145256Sjkoshy __P4MASK(req-len1, 3), 444145256Sjkoshy __P4MASK(req-io-type, 5), 445145256Sjkoshy __P4MASK(req-lock-type, 6), 446145256Sjkoshy __P4MASK(req-cache-type, 7), 447145256Sjkoshy __P4MASK(req-split-type, 8), 448145256Sjkoshy __P4MASK(req-dem-type, 9), 449145256Sjkoshy __P4MASK(req-ord-type, 10), 450145256Sjkoshy __P4MASK(mem-type0, 11), 451145256Sjkoshy __P4MASK(mem-type1, 12), 452145256Sjkoshy __P4MASK(mem-type2, 13), 453145256Sjkoshy NULLMASK 454145256Sjkoshy}; 455145256Sjkoshy 456145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 457145256Sjkoshy __P4MASK(all, 15), 458145256Sjkoshy NULLMASK 459145256Sjkoshy}; 460145256Sjkoshy 461145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 462145256Sjkoshy __P4MASK(all, 15), 463145256Sjkoshy NULLMASK 464145256Sjkoshy}; 465145256Sjkoshy 466145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 467145256Sjkoshy __P4MASK(all, 15), 468145256Sjkoshy NULLMASK 469145256Sjkoshy}; 470145256Sjkoshy 471145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 472145256Sjkoshy __P4MASK(all, 15), 473145256Sjkoshy NULLMASK 474145256Sjkoshy}; 475145256Sjkoshy 476145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 477145256Sjkoshy __P4MASK(all, 15), 478145256Sjkoshy NULLMASK 479145256Sjkoshy}; 480145256Sjkoshy 481145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 482145256Sjkoshy __P4MASK(all, 15), 483145256Sjkoshy NULLMASK 484145256Sjkoshy}; 485145256Sjkoshy 486145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 487145256Sjkoshy __P4MASK(all, 15), 488145256Sjkoshy NULLMASK 489145256Sjkoshy}; 490145256Sjkoshy 491145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 492145256Sjkoshy __P4MASK(all, 15), 493145256Sjkoshy NULLMASK 494145256Sjkoshy}; 495145256Sjkoshy 496145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 497145256Sjkoshy __P4MASK(allp0, 3), 498145256Sjkoshy __P4MASK(allp2, 4), 499145256Sjkoshy NULLMASK 500145256Sjkoshy}; 501145256Sjkoshy 502145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 503145256Sjkoshy __P4MASK(running, 0), 504145256Sjkoshy NULLMASK 505145256Sjkoshy}; 506145256Sjkoshy 507145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 508145256Sjkoshy __P4MASK(cisc, 0), 509145256Sjkoshy NULLMASK 510145256Sjkoshy}; 511145256Sjkoshy 512145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 513145256Sjkoshy __P4MASK(from-tc-build, 0), 514145256Sjkoshy __P4MASK(from-tc-deliver, 1), 515145256Sjkoshy __P4MASK(from-rom, 2), 516145256Sjkoshy NULLMASK 517145256Sjkoshy}; 518145256Sjkoshy 519145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 520145351Sjkoshy /* retired mispred branch type */ 521145256Sjkoshy __P4MASK(conditional, 1), 522145256Sjkoshy __P4MASK(call, 2), 523145256Sjkoshy __P4MASK(return, 3), 524145256Sjkoshy __P4MASK(indirect, 4), 525145256Sjkoshy NULLMASK 526145256Sjkoshy}; 527145256Sjkoshy 528145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 529145256Sjkoshy __P4MASK(conditional, 1), 530145256Sjkoshy __P4MASK(call, 2), 531145256Sjkoshy __P4MASK(retired, 3), 532145256Sjkoshy __P4MASK(indirect, 4), 533145256Sjkoshy NULLMASK 534145256Sjkoshy}; 535145256Sjkoshy 536145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 537145256Sjkoshy __P4MASK(sbfull, 5), 538145256Sjkoshy NULLMASK 539145256Sjkoshy}; 540145256Sjkoshy 541145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 542145256Sjkoshy __P4MASK(wcb-evicts, 0), 543145256Sjkoshy __P4MASK(wcb-full-evict, 1), 544145256Sjkoshy NULLMASK 545145256Sjkoshy}; 546145256Sjkoshy 547145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 548145256Sjkoshy __P4MASK(nbogus, 0), 549145256Sjkoshy __P4MASK(bogus, 1), 550145256Sjkoshy NULLMASK 551145256Sjkoshy}; 552145256Sjkoshy 553145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 554145256Sjkoshy __P4MASK(nbogus0, 0), 555145256Sjkoshy __P4MASK(nbogus1, 1), 556145256Sjkoshy __P4MASK(nbogus2, 2), 557145256Sjkoshy __P4MASK(nbogus3, 3), 558145256Sjkoshy __P4MASK(bogus0, 4), 559145256Sjkoshy __P4MASK(bogus1, 5), 560145256Sjkoshy __P4MASK(bogus2, 6), 561145256Sjkoshy __P4MASK(bogus3, 7), 562145256Sjkoshy NULLMASK 563145256Sjkoshy}; 564145256Sjkoshy 565145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 566145256Sjkoshy __P4MASK(nbogus, 0), 567145256Sjkoshy __P4MASK(bogus, 1), 568145256Sjkoshy NULLMASK 569145256Sjkoshy}; 570145256Sjkoshy 571145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 572145256Sjkoshy __P4MASK(nbogusntag, 0), 573145256Sjkoshy __P4MASK(nbogustag, 1), 574145256Sjkoshy __P4MASK(bogusntag, 2), 575145256Sjkoshy __P4MASK(bogustag, 3), 576145256Sjkoshy NULLMASK 577145256Sjkoshy}; 578145256Sjkoshy 579145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 580145256Sjkoshy __P4MASK(nbogus, 0), 581145256Sjkoshy __P4MASK(bogus, 1), 582145256Sjkoshy NULLMASK 583145256Sjkoshy}; 584145256Sjkoshy 585145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 586145256Sjkoshy __P4MASK(tagloads, 1), 587145256Sjkoshy __P4MASK(tagstores, 2), 588145256Sjkoshy NULLMASK 589145256Sjkoshy}; 590145256Sjkoshy 591145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 592145256Sjkoshy __P4MASK(mmnp, 0), 593145256Sjkoshy __P4MASK(mmnm, 1), 594145256Sjkoshy __P4MASK(mmtp, 2), 595145256Sjkoshy __P4MASK(mmtm, 3), 596145256Sjkoshy NULLMASK 597145256Sjkoshy}; 598145256Sjkoshy 599145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 600145256Sjkoshy __P4MASK(nbogus, 0), 601145256Sjkoshy NULLMASK 602145256Sjkoshy}; 603145256Sjkoshy 604145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 605145256Sjkoshy __P4MASK(fpsu, 0), 606145256Sjkoshy __P4MASK(fpso, 1), 607145256Sjkoshy __P4MASK(poao, 2), 608145256Sjkoshy __P4MASK(poau, 3), 609145256Sjkoshy __P4MASK(prea, 4), 610145256Sjkoshy NULLMASK 611145256Sjkoshy}; 612145256Sjkoshy 613145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 614145256Sjkoshy __P4MASK(clear, 0), 615145256Sjkoshy __P4MASK(moclear, 2), 616145256Sjkoshy __P4MASK(smclear, 3), 617145256Sjkoshy NULLMASK 618145256Sjkoshy}; 619145256Sjkoshy 620145256Sjkoshy/* P4 event parser */ 621145256Sjkoshystatic int 622145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 623145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 624145256Sjkoshy{ 625145256Sjkoshy 626145256Sjkoshy char *e, *p, *q; 627145256Sjkoshy int count, has_tag, has_busreqtype, n; 628145256Sjkoshy uint32_t evmask, cccractivemask; 629145256Sjkoshy const struct pmc_masks *pm, *pmask; 630145256Sjkoshy 631145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 632145256Sjkoshy pmc_config->pm_p4_cccrconfig = pmc_config->pm_p4_escrconfig = 0; 633145256Sjkoshy 634145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 635145256Sjkoshy /* TSC must not be further qualified */ 636145256Sjkoshy if (ctrspec && *ctrspec != '\0') 637145256Sjkoshy return -1; 638145256Sjkoshy return 0; 639145256Sjkoshy } 640145256Sjkoshy 641145256Sjkoshy pmask = NULL; 642145256Sjkoshy evmask = 0; 643145256Sjkoshy cccractivemask = 0x3; 644145256Sjkoshy has_tag = has_busreqtype = 0; 645145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 646145256Sjkoshy 647145256Sjkoshy#define __P4SETMASK(M) do { \ 648145256Sjkoshy pmask = p4_mask_##M; \ 649145256Sjkoshy} while (0) 650145256Sjkoshy 651145256Sjkoshy switch (pe) { 652145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 653145256Sjkoshy __P4SETMASK(tcdm); 654145256Sjkoshy break; 655145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 656145256Sjkoshy __P4SETMASK(bfr); 657145256Sjkoshy break; 658145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 659145256Sjkoshy __P4SETMASK(ir); 660145256Sjkoshy break; 661145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 662145256Sjkoshy __P4SETMASK(memcan); 663145256Sjkoshy break; 664145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 665145256Sjkoshy __P4SETMASK(memcomp); 666145256Sjkoshy break; 667145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 668145256Sjkoshy __P4SETMASK(lpr); 669145256Sjkoshy break; 670145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 671145256Sjkoshy __P4SETMASK(spr); 672145256Sjkoshy break; 673145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 674145256Sjkoshy __P4SETMASK(mlr); 675145256Sjkoshy break; 676145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 677145256Sjkoshy __P4SETMASK(pwt); 678145256Sjkoshy break; 679145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 680145256Sjkoshy __P4SETMASK(bcr); 681145256Sjkoshy break; 682145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 683145256Sjkoshy __P4SETMASK(ia); 684145256Sjkoshy has_busreqtype = 1; 685145256Sjkoshy break; 686145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 687145256Sjkoshy __P4SETMASK(iae); 688145256Sjkoshy has_busreqtype = 1; 689145256Sjkoshy break; 690145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 691145256Sjkoshy __P4SETMASK(fda); 692145256Sjkoshy break; 693145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 694145256Sjkoshy __P4SETMASK(ba); 695145256Sjkoshy break; 696145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 697145256Sjkoshy __P4SETMASK(sia); 698145256Sjkoshy break; 699145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 700145256Sjkoshy __P4SETMASK(psu); 701145256Sjkoshy break; 702145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 703145256Sjkoshy __P4SETMASK(pdu); 704145256Sjkoshy break; 705145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 706145256Sjkoshy __P4SETMASK(ssu); 707145256Sjkoshy break; 708145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 709145256Sjkoshy __P4SETMASK(sdu); 710145256Sjkoshy break; 711145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 712145256Sjkoshy __P4SETMASK(64bmu); 713145256Sjkoshy break; 714145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 715145256Sjkoshy __P4SETMASK(128bmu); 716145256Sjkoshy break; 717145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 718145256Sjkoshy __P4SETMASK(xfu); 719145256Sjkoshy break; 720145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 721145256Sjkoshy __P4SETMASK(xsmu); 722145256Sjkoshy break; 723145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 724145256Sjkoshy __P4SETMASK(gpe); 725145256Sjkoshy break; 726145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 727145256Sjkoshy __P4SETMASK(tmx); 728145256Sjkoshy break; 729145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 730145256Sjkoshy __P4SETMASK(uqw); 731145256Sjkoshy break; 732145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 733145256Sjkoshy __P4SETMASK(rmbt); 734145256Sjkoshy break; 735145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 736145256Sjkoshy __P4SETMASK(rbt); 737145256Sjkoshy break; 738145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 739145256Sjkoshy __P4SETMASK(rs); 740145256Sjkoshy break; 741145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 742145256Sjkoshy __P4SETMASK(wb); 743145256Sjkoshy break; 744145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 745145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 746145256Sjkoshy case PMC_EV_P4_BNR: 747145256Sjkoshy case PMC_EV_P4_SNOOP: 748145256Sjkoshy case PMC_EV_P4_RESPONSE: 749145256Sjkoshy break; 750145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 751145256Sjkoshy __P4SETMASK(fee); 752145256Sjkoshy break; 753145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 754145256Sjkoshy __P4SETMASK(ee); 755145256Sjkoshy break; 756145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 757145256Sjkoshy __P4SETMASK(re); 758145256Sjkoshy break; 759145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 760145256Sjkoshy __P4SETMASK(insret); 761145256Sjkoshy break; 762145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 763145256Sjkoshy __P4SETMASK(ur); 764145256Sjkoshy break; 765145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 766145256Sjkoshy __P4SETMASK(ut); 767145256Sjkoshy break; 768145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 769145256Sjkoshy __P4SETMASK(br); 770145256Sjkoshy break; 771145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 772145256Sjkoshy __P4SETMASK(mbr); 773145256Sjkoshy break; 774145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 775145256Sjkoshy __P4SETMASK(xa); 776145256Sjkoshy break; 777145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 778145256Sjkoshy __P4SETMASK(machclr); 779145256Sjkoshy break; 780145256Sjkoshy default: 781145256Sjkoshy return -1; 782145256Sjkoshy } 783145256Sjkoshy 784145256Sjkoshy /* process additional flags */ 785145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 786145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 787145256Sjkoshy q = strchr(p, '='); 788145256Sjkoshy if (*++q == '\0') /* skip '=' */ 789145256Sjkoshy return -1; 790145256Sjkoshy 791145256Sjkoshy if (strcmp(q, P4_KW_ACTIVE_NONE) == 0) 792145256Sjkoshy cccractivemask = 0x0; 793145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_SINGLE) == 0) 794145256Sjkoshy cccractivemask = 0x1; 795145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_BOTH) == 0) 796145256Sjkoshy cccractivemask = 0x2; 797145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_ANY) == 0) 798145256Sjkoshy cccractivemask = 0x3; 799145256Sjkoshy else 800145256Sjkoshy return -1; 801145256Sjkoshy 802145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 803145256Sjkoshy if (has_busreqtype == 0) 804145256Sjkoshy return -1; 805145256Sjkoshy 806145256Sjkoshy q = strchr(p, '='); 807145256Sjkoshy if (*++q == '\0') /* skip '=' */ 808145256Sjkoshy return -1; 809145256Sjkoshy 810145256Sjkoshy count = strtol(q, &e, 0); 811145256Sjkoshy if (e == q || *e != '\0') 812145256Sjkoshy return -1; 813145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 814145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 815145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 816145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 817145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 818145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 819145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 820145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 821145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 822145256Sjkoshy return -1; 823145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 824145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 825145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 826145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 827145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 828145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 829145256Sjkoshy if (has_tag == 0) 830145256Sjkoshy return -1; 831145256Sjkoshy 832145256Sjkoshy q = strchr(p, '='); 833145256Sjkoshy if (*++q == '\0') /* skip '=' */ 834145256Sjkoshy return -1; 835145256Sjkoshy 836145256Sjkoshy count = strtol(q, &e, 0); 837145256Sjkoshy if (e == q || *e != '\0') 838145256Sjkoshy return -1; 839145256Sjkoshy 840145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 841145256Sjkoshy pmc_config->pm_p4_escrconfig |= 842145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 843145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 844145256Sjkoshy q = strchr(p, '='); 845145256Sjkoshy if (*++q == '\0') /* skip '=' */ 846145256Sjkoshy return -1; 847145256Sjkoshy 848145256Sjkoshy count = strtol(q, &e, 0); 849145256Sjkoshy if (e == q || *e != '\0') 850145256Sjkoshy return -1; 851145256Sjkoshy 852145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 853145256Sjkoshy pmc_config->pm_p4_cccrconfig &= ~P4_CCCR_THRESHOLD_MASK; 854145256Sjkoshy pmc_config->pm_p4_cccrconfig |= P4_CCCR_TO_THRESHOLD(count); 855145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 856145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 857145256Sjkoshy else 858145256Sjkoshy return -1; 859145256Sjkoshy } 860145256Sjkoshy 861145256Sjkoshy /* other post processing */ 862145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 863145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 864145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 865145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 866145256Sjkoshy 867145256Sjkoshy /* fill in thread activity mask */ 868145256Sjkoshy pmc_config->pm_p4_cccrconfig |= 869145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 870145256Sjkoshy 871145256Sjkoshy if (evmask) 872145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 873145256Sjkoshy 874145256Sjkoshy switch (pe) { 875145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 876145256Sjkoshy if ((evmask & 0x06) == 0x06 || 877145256Sjkoshy (evmask & 0x18) == 0x18) 878145256Sjkoshy return -1; /* can't have own+other bits together */ 879145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 880145256Sjkoshy evmask = 0x1D; 881145256Sjkoshy break; 882145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 883145256Sjkoshy /* only one bit is allowed to be set */ 884145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 885145256Sjkoshy return -1; 886145256Sjkoshy if (evmask == 0) { 887145256Sjkoshy evmask = 0x1; /* 'CLEAR' */ 888145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 889145256Sjkoshy } 890145256Sjkoshy break; 891145256Sjkoshy default: 892145256Sjkoshy if (evmask == 0 && pmask) { 893145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 894145256Sjkoshy evmask |= pm->pm_value; 895145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 896145256Sjkoshy } 897145256Sjkoshy } 898145256Sjkoshy 899145256Sjkoshy pmc_config->pm_p4_escrconfig = P4_ESCR_TO_EVENT_MASK(evmask); 900145256Sjkoshy 901145256Sjkoshy return 0; 902145256Sjkoshy} 903145256Sjkoshy 904145256Sjkoshy/* 905145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 906145256Sjkoshy * and Pentium M CPUs. 907145256Sjkoshy */ 908145256Sjkoshy 909145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 910145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 911145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 912145351Sjkoshy EV_ALIAS("cycles", "tsc"), 913145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 914145351Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-ifetch-miss"), 915145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 916145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 917145351Sjkoshy EV_ALIAS(NULL, NULL) 918145256Sjkoshy}; 919145256Sjkoshy 920145256Sjkoshy#define P6_KW_CMASK "cmask" 921145256Sjkoshy#define P6_KW_EDGE "edge" 922145256Sjkoshy#define P6_KW_INV "inv" 923145256Sjkoshy#define P6_KW_OS "os" 924145256Sjkoshy#define P6_KW_UMASK "umask" 925145256Sjkoshy#define P6_KW_USR "usr" 926145256Sjkoshy 927145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 928145256Sjkoshy PMCMASK(m, 0x01), 929145256Sjkoshy PMCMASK(e, 0x02), 930145256Sjkoshy PMCMASK(s, 0x04), 931145256Sjkoshy PMCMASK(i, 0x08), 932145256Sjkoshy NULLMASK 933145256Sjkoshy}; 934145256Sjkoshy 935145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 936145256Sjkoshy PMCMASK(m, 0x01), 937145256Sjkoshy PMCMASK(e, 0x02), 938145256Sjkoshy PMCMASK(s, 0x04), 939145256Sjkoshy PMCMASK(i, 0x08), 940145256Sjkoshy PMCMASK(nonhw, 0x00), 941145256Sjkoshy PMCMASK(hw, 0x10), 942145256Sjkoshy PMCMASK(both, 0x30), 943145256Sjkoshy NULLMASK 944145256Sjkoshy}; 945145256Sjkoshy 946145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 947145256Sjkoshy PMCMASK(nonhw, 0x00), 948145256Sjkoshy PMCMASK(hw, 0x10), 949145256Sjkoshy PMCMASK(both, 0x30), 950145256Sjkoshy NULLMASK 951145256Sjkoshy}; 952145256Sjkoshy 953145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 954145256Sjkoshy PMCMASK(self, 0x00), 955145256Sjkoshy PMCMASK(any, 0x20), 956145256Sjkoshy NULLMASK 957145256Sjkoshy}; 958145256Sjkoshy 959145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 960145256Sjkoshy PMCMASK(nta, 0x00), 961145256Sjkoshy PMCMASK(t1, 0x01), 962145256Sjkoshy PMCMASK(t2, 0x02), 963145256Sjkoshy PMCMASK(wos, 0x03), 964145256Sjkoshy NULLMASK 965145256Sjkoshy}; 966145256Sjkoshy 967145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 968145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 969145256Sjkoshy PMCMASK(scalar, 0x01), 970145256Sjkoshy NULLMASK 971145256Sjkoshy}; 972145256Sjkoshy 973145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 974145256Sjkoshy PMCMASK(packed-multiply, 0x01), 975145256Sjkoshy PMCMASK(packed-shift, 0x02), 976145256Sjkoshy PMCMASK(pack, 0x04), 977145256Sjkoshy PMCMASK(unpack, 0x08), 978145256Sjkoshy PMCMASK(packed-logical, 0x10), 979145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 980145256Sjkoshy NULLMASK 981145256Sjkoshy}; 982145256Sjkoshy 983145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 984145256Sjkoshy PMCMASK(mmxtofp, 0x00), 985145256Sjkoshy PMCMASK(fptommx, 0x01), 986145256Sjkoshy NULLMASK 987145256Sjkoshy}; 988145256Sjkoshy 989145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 990145256Sjkoshy PMCMASK(es, 0x01), 991145256Sjkoshy PMCMASK(ds, 0x02), 992145256Sjkoshy PMCMASK(fs, 0x04), 993145256Sjkoshy PMCMASK(gs, 0x08), 994145256Sjkoshy NULLMASK 995145256Sjkoshy}; 996145256Sjkoshy 997145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 998145256Sjkoshy PMCMASK(all, 0x00), 999145256Sjkoshy PMCMASK(freq, 0x02), 1000145256Sjkoshy NULLMASK 1001145256Sjkoshy}; 1002145256Sjkoshy 1003145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1004145256Sjkoshy PMCMASK(all, 0x00), 1005145256Sjkoshy PMCMASK(loadop, 0x01), 1006145256Sjkoshy PMCMASK(stdsta, 0x02), 1007145256Sjkoshy NULLMASK 1008145256Sjkoshy}; 1009145256Sjkoshy 1010145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1011145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1012145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1013145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1014145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1015145256Sjkoshy NULLMASK 1016145256Sjkoshy}; 1017145256Sjkoshy 1018145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1019145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1020145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1021145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1022145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1023145256Sjkoshy NULLMASK 1024145256Sjkoshy}; 1025145256Sjkoshy 1026145256Sjkoshy/* P6 event parser */ 1027145256Sjkoshystatic int 1028145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1029145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1030145256Sjkoshy{ 1031145256Sjkoshy char *e, *p, *q; 1032145256Sjkoshy uint32_t evmask; 1033145256Sjkoshy int count, n; 1034145256Sjkoshy const struct pmc_masks *pm, *pmask; 1035145256Sjkoshy 1036145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1037145256Sjkoshy pmc_config->pm_p6_config = 0; 1038145256Sjkoshy 1039145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1040145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1041145256Sjkoshy return -1; 1042145256Sjkoshy return 0; 1043145256Sjkoshy } 1044145256Sjkoshy 1045145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1046145256Sjkoshy evmask = 0; 1047145256Sjkoshy 1048145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1049145256Sjkoshy 1050145256Sjkoshy switch(pe) { 1051145256Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1052145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1053145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1054145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1055145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1056145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1057145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1058145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1059145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1060145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1061145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1062145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1063145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1064145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1065145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1066145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1067145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1068145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1069145256Sjkoshy P6MASKSET(any); break; 1070145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1071145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1072145256Sjkoshy P6MASKSET(ekp); break; 1073145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1074145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1075145256Sjkoshy P6MASKSET(pps); break; 1076145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 1077145256Sjkoshy P6MASKSET(mite); break; 1078145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1079145256Sjkoshy P6MASKSET(fmt); break; 1080145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 1081145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 1082145256Sjkoshy P6MASKSET(sr); break; 1083145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1084145256Sjkoshy P6MASKSET(eet); break; 1085145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1086145256Sjkoshy P6MASKSET(efur); break; 1087145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1088145256Sjkoshy P6MASKSET(essir); break; 1089145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1090145256Sjkoshy P6MASKSET(esscir); break; 1091145256Sjkoshy default: 1092145256Sjkoshy pmask = NULL; 1093145256Sjkoshy break; 1094145256Sjkoshy } 1095145256Sjkoshy 1096145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 1097145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 1098145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 1099145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 1100145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 1101145256Sjkoshy P6MASKSET(mesihw); 1102145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 1103145256Sjkoshy P6MASKSET(hw); 1104145256Sjkoshy } 1105145256Sjkoshy 1106145256Sjkoshy /* Parse additional modifiers if present */ 1107145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1108145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 1109145256Sjkoshy q = strchr(p, '='); 1110145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1111145256Sjkoshy return -1; 1112145256Sjkoshy count = strtol(q, &e, 0); 1113145256Sjkoshy if (e == q || *e != '\0') 1114145256Sjkoshy return -1; 1115145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1116145256Sjkoshy pmc_config->pm_p6_config |= P6_EVSEL_TO_CMASK(count); 1117145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 1118145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1119145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 1120145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1121145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 1122145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1123145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 1124145256Sjkoshy evmask = 0; 1125145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1126145256Sjkoshy return -1; 1127145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 1128145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 1129145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 1130145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 1131145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 1132145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 1133145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 1134145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 1135145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 1136145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 1137145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 1138145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 1139145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 1140145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 1141145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 1142145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 1143145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 1144145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 1145145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 1146145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 1147145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 1148145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 1149145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 1150145256Sjkoshy && (n > 1)) 1151145256Sjkoshy return -1; /* only one mask keyword allowed */ 1152145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1153145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 1154145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1155145256Sjkoshy } else 1156145256Sjkoshy return -1; 1157145256Sjkoshy } 1158145256Sjkoshy 1159145256Sjkoshy /* post processing */ 1160145256Sjkoshy switch (pe) { 1161145256Sjkoshy 1162145256Sjkoshy /* 1163145256Sjkoshy * The following events default to an evmask of 0 1164145256Sjkoshy */ 1165145256Sjkoshy 1166145256Sjkoshy /* default => 'self' */ 1167145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1168145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1169145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1170145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1171145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1172145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1173145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1174145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1175145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1176145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1177145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1178145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1179145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1180145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1181145256Sjkoshy 1182145256Sjkoshy /* default => 'nta' */ 1183145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1184145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1185145256Sjkoshy 1186145256Sjkoshy /* default => 'packed and scalar' */ 1187145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1188145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1189145256Sjkoshy 1190145256Sjkoshy /* default => 'mmx to fp transitions' */ 1191145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1192145256Sjkoshy 1193145256Sjkoshy /* default => 'SSE Packed Single' */ 1194145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1195145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1196145256Sjkoshy 1197145256Sjkoshy /* default => 'all fused micro-ops' */ 1198145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1199145256Sjkoshy 1200145256Sjkoshy /* default => 'all transitions' */ 1201145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1202145256Sjkoshy break; 1203145256Sjkoshy 1204145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 1205145256Sjkoshy evmask = 0x0F; /* only value allowed */ 1206145256Sjkoshy break; 1207145256Sjkoshy 1208145256Sjkoshy default: 1209145256Sjkoshy 1210145256Sjkoshy /* 1211145256Sjkoshy * For all other events, set the default event mask 1212145256Sjkoshy * to a logical OR of all the allowed event mask bits. 1213145256Sjkoshy */ 1214145256Sjkoshy 1215145256Sjkoshy if (evmask == 0 && pmask) { 1216145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1217145256Sjkoshy evmask |= pm->pm_value; 1218145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1219145256Sjkoshy } 1220145256Sjkoshy 1221145256Sjkoshy break; 1222145256Sjkoshy } 1223145256Sjkoshy 1224145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1225145256Sjkoshy pmc_config->pm_p6_config |= P6_EVSEL_TO_UMASK(evmask); 1226145256Sjkoshy 1227145256Sjkoshy return 0; 1228145256Sjkoshy} 1229145256Sjkoshy 1230145256Sjkoshy/* 1231145256Sjkoshy * Pentium style PMCs 1232145256Sjkoshy */ 1233145256Sjkoshy 1234145256Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1235145256Sjkoshy EV_ALIAS("cycles", "tsc"), 1236145256Sjkoshy EV_ALIAS(NULL, NULL) 1237145256Sjkoshy}; 1238145256Sjkoshy 1239145256Sjkoshystatic int 1240145256Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1241145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1242145256Sjkoshy{ 1243145256Sjkoshy return -1 || pe || ctrspec || pmc_config; /* shut up gcc */ 1244145256Sjkoshy} 1245145256Sjkoshy 1246145340Smarcel#elif defined(__amd64__) 1247145256Sjkoshy 1248145256Sjkoshy/* 1249145256Sjkoshy * AMD K8 PMCs. 1250145256Sjkoshy * 1251145256Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 1252145256Sjkoshy * events. 1253145256Sjkoshy */ 1254145256Sjkoshy 1255145256Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 1256145351Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 1257145351Sjkoshy EV_ALIAS("branch-mispredicts", 1258145351Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 1259145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1260145351Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 1261145351Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 1262145351Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 1263145351Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 1264145256Sjkoshy EV_ALIAS(NULL, NULL) 1265145256Sjkoshy}; 1266145256Sjkoshy 1267145256Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 1268145256Sjkoshy 1269145256Sjkoshy/* 1270145256Sjkoshy * Parsing tables 1271145256Sjkoshy */ 1272145256Sjkoshy 1273145256Sjkoshy/* fp dispatched fpu ops */ 1274145256Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 1275145256Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 1276145256Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 1277145256Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 1278145256Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 1279145256Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 1280145256Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 1281145256Sjkoshy NULLMASK 1282145256Sjkoshy}; 1283145256Sjkoshy 1284145256Sjkoshy/* ls segment register loads */ 1285145256Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 1286145256Sjkoshy __K8MASK(es, 0), 1287145256Sjkoshy __K8MASK(cs, 1), 1288145256Sjkoshy __K8MASK(ss, 2), 1289145256Sjkoshy __K8MASK(ds, 3), 1290145256Sjkoshy __K8MASK(fs, 4), 1291145256Sjkoshy __K8MASK(gs, 5), 1292145256Sjkoshy __K8MASK(hs, 6), 1293145256Sjkoshy NULLMASK 1294145256Sjkoshy}; 1295145256Sjkoshy 1296145256Sjkoshy/* ls locked operation */ 1297145256Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 1298145256Sjkoshy __K8MASK(locked-instructions, 0), 1299145256Sjkoshy __K8MASK(cycles-in-request, 1), 1300145256Sjkoshy __K8MASK(cycles-to-complete, 2), 1301145256Sjkoshy NULLMASK 1302145256Sjkoshy}; 1303145256Sjkoshy 1304145256Sjkoshy/* dc refill from {l2,system} and dc copyback */ 1305145256Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 1306145256Sjkoshy __K8MASK(invalid, 0), 1307145256Sjkoshy __K8MASK(shared, 1), 1308145256Sjkoshy __K8MASK(exclusive, 2), 1309145256Sjkoshy __K8MASK(owner, 3), 1310145256Sjkoshy __K8MASK(modified, 4), 1311145256Sjkoshy NULLMASK 1312145256Sjkoshy}; 1313145256Sjkoshy 1314145256Sjkoshy/* dc one bit ecc error */ 1315145256Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 1316145256Sjkoshy __K8MASK(scrubber, 0), 1317145256Sjkoshy __K8MASK(piggyback, 1), 1318145256Sjkoshy NULLMASK 1319145256Sjkoshy}; 1320145256Sjkoshy 1321145256Sjkoshy/* dc dispatched prefetch instructions */ 1322145256Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 1323145256Sjkoshy __K8MASK(load, 0), 1324145256Sjkoshy __K8MASK(store, 1), 1325145256Sjkoshy __K8MASK(nta, 2), 1326145256Sjkoshy NULLMASK 1327145256Sjkoshy}; 1328145256Sjkoshy 1329145256Sjkoshy/* dc dcache accesses by locks */ 1330145256Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 1331145256Sjkoshy __K8MASK(accesses, 0), 1332145256Sjkoshy __K8MASK(misses, 1), 1333145256Sjkoshy NULLMASK 1334145256Sjkoshy}; 1335145256Sjkoshy 1336145256Sjkoshy/* bu internal l2 request */ 1337145256Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 1338145256Sjkoshy __K8MASK(ic-fill, 0), 1339145256Sjkoshy __K8MASK(dc-fill, 1), 1340145256Sjkoshy __K8MASK(tlb-reload, 2), 1341145256Sjkoshy __K8MASK(tag-snoop, 3), 1342145256Sjkoshy __K8MASK(cancelled, 4), 1343145256Sjkoshy NULLMASK 1344145256Sjkoshy}; 1345145256Sjkoshy 1346145256Sjkoshy/* bu fill request l2 miss */ 1347145256Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 1348145256Sjkoshy __K8MASK(ic-fill, 0), 1349145256Sjkoshy __K8MASK(dc-fill, 1), 1350145256Sjkoshy __K8MASK(tlb-reload, 2), 1351145256Sjkoshy NULLMASK 1352145256Sjkoshy}; 1353145256Sjkoshy 1354145256Sjkoshy/* bu fill into l2 */ 1355145256Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 1356145256Sjkoshy __K8MASK(dirty-l2-victim, 0), 1357145256Sjkoshy __K8MASK(victim-from-l2, 1), 1358145256Sjkoshy NULLMASK 1359145256Sjkoshy}; 1360145256Sjkoshy 1361145256Sjkoshy/* fr retired fpu instructions */ 1362145256Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 1363145256Sjkoshy __K8MASK(x87, 0), 1364145256Sjkoshy __K8MASK(mmx-3dnow, 1), 1365145256Sjkoshy __K8MASK(packed-sse-sse2, 2), 1366145256Sjkoshy __K8MASK(scalar-sse-sse2, 3), 1367145256Sjkoshy NULLMASK 1368145256Sjkoshy}; 1369145256Sjkoshy 1370145256Sjkoshy/* fr retired fastpath double op instructions */ 1371145256Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 1372145256Sjkoshy __K8MASK(low-op-pos-0, 0), 1373145256Sjkoshy __K8MASK(low-op-pos-1, 1), 1374145256Sjkoshy __K8MASK(low-op-pos-2, 2), 1375145256Sjkoshy NULLMASK 1376145256Sjkoshy}; 1377145256Sjkoshy 1378145256Sjkoshy/* fr fpu exceptions */ 1379145256Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 1380145256Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 1381145256Sjkoshy __K8MASK(sse-retype-microfaults, 1), 1382145256Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 1383145256Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 1384145256Sjkoshy NULLMASK 1385145256Sjkoshy}; 1386145256Sjkoshy 1387145256Sjkoshy/* nb memory controller page access event */ 1388145256Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 1389145256Sjkoshy __K8MASK(page-hit, 0), 1390145256Sjkoshy __K8MASK(page-miss, 1), 1391145256Sjkoshy __K8MASK(page-conflict, 2), 1392145256Sjkoshy NULLMASK 1393145256Sjkoshy}; 1394145256Sjkoshy 1395145256Sjkoshy/* nb memory controller turnaround */ 1396145256Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 1397145256Sjkoshy __K8MASK(dimm-turnaround, 0), 1398145256Sjkoshy __K8MASK(read-to-write-turnaround, 1), 1399145256Sjkoshy __K8MASK(write-to-read-turnaround, 2), 1400145256Sjkoshy NULLMASK 1401145256Sjkoshy}; 1402145256Sjkoshy 1403145256Sjkoshy/* nb memory controller bypass saturation */ 1404145256Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 1405145256Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 1406145256Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 1407145256Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 1408145256Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 1409145256Sjkoshy NULLMASK 1410145256Sjkoshy}; 1411145256Sjkoshy 1412145256Sjkoshy/* nb sized commands */ 1413145256Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 1414145256Sjkoshy __K8MASK(nonpostwrszbyte, 0), 1415145256Sjkoshy __K8MASK(nonpostwrszdword, 1), 1416145256Sjkoshy __K8MASK(postwrszbyte, 2), 1417145256Sjkoshy __K8MASK(postwrszdword, 3), 1418145256Sjkoshy __K8MASK(rdszbyte, 4), 1419145256Sjkoshy __K8MASK(rdszdword, 5), 1420145256Sjkoshy __K8MASK(rdmodwr, 6), 1421145256Sjkoshy NULLMASK 1422145256Sjkoshy}; 1423145256Sjkoshy 1424145256Sjkoshy/* nb probe result */ 1425145256Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 1426145256Sjkoshy __K8MASK(probe-miss, 0), 1427145256Sjkoshy __K8MASK(probe-hit, 1), 1428145256Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 1429145256Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 1430145256Sjkoshy NULLMASK 1431145256Sjkoshy}; 1432145256Sjkoshy 1433145256Sjkoshy/* nb hypertransport bus bandwidth */ 1434145256Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 1435145256Sjkoshy __K8MASK(command, 0), 1436145256Sjkoshy __K8MASK(data, 1), 1437145256Sjkoshy __K8MASK(buffer-release, 2), 1438145256Sjkoshy __K8MASK(nop, 3), 1439145256Sjkoshy NULLMASK 1440145256Sjkoshy}; 1441145256Sjkoshy 1442145256Sjkoshy#undef __K8MASK 1443145256Sjkoshy 1444145256Sjkoshy#define K8_KW_COUNT "count" 1445145256Sjkoshy#define K8_KW_EDGE "edge" 1446145256Sjkoshy#define K8_KW_INV "inv" 1447145256Sjkoshy#define K8_KW_MASK "mask" 1448145256Sjkoshy#define K8_KW_OS "os" 1449145256Sjkoshy#define K8_KW_USR "usr" 1450145256Sjkoshy 1451145256Sjkoshystatic int 1452145256Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 1453145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1454145256Sjkoshy{ 1455145256Sjkoshy char *e, *p, *q; 1456145256Sjkoshy int n; 1457145256Sjkoshy uint32_t count, evmask; 1458145256Sjkoshy const struct pmc_masks *pm, *pmask; 1459145256Sjkoshy 1460145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1461145256Sjkoshy pmc_config->pm_amd_config = 0; 1462145256Sjkoshy 1463145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1464145256Sjkoshy /* TSC events must be unqualified. */ 1465145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1466145256Sjkoshy return -1; 1467145256Sjkoshy return 0; 1468145256Sjkoshy } 1469145256Sjkoshy 1470145256Sjkoshy pmask = NULL; 1471145256Sjkoshy evmask = 0; 1472145256Sjkoshy 1473145256Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 1474145256Sjkoshy 1475145256Sjkoshy /* setup parsing tables */ 1476145256Sjkoshy switch (pe) { 1477145256Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1478145256Sjkoshy __K8SETMASK(fdfo); 1479145256Sjkoshy break; 1480145256Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 1481145256Sjkoshy __K8SETMASK(lsrl); 1482145256Sjkoshy break; 1483145256Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1484145256Sjkoshy __K8SETMASK(llo); 1485145256Sjkoshy break; 1486145256Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 1487145256Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 1488145256Sjkoshy case PMC_EV_K8_DC_COPYBACK: 1489145256Sjkoshy __K8SETMASK(dc); 1490145256Sjkoshy break; 1491145256Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 1492145256Sjkoshy __K8SETMASK(dobee); 1493145256Sjkoshy break; 1494145256Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 1495145256Sjkoshy __K8SETMASK(ddpi); 1496145256Sjkoshy break; 1497145256Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1498145256Sjkoshy __K8SETMASK(dabl); 1499145256Sjkoshy break; 1500145256Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 1501145256Sjkoshy __K8SETMASK(bilr); 1502145256Sjkoshy break; 1503145256Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 1504145256Sjkoshy __K8SETMASK(bfrlm); 1505145256Sjkoshy break; 1506145256Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 1507145256Sjkoshy __K8SETMASK(bfil); 1508145256Sjkoshy break; 1509145256Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1510145256Sjkoshy __K8SETMASK(frfi); 1511145256Sjkoshy break; 1512145256Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1513145256Sjkoshy __K8SETMASK(frfdoi); 1514145256Sjkoshy break; 1515145256Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1516145256Sjkoshy __K8SETMASK(ffe); 1517145256Sjkoshy break; 1518145256Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 1519145256Sjkoshy __K8SETMASK(nmcpae); 1520145256Sjkoshy break; 1521145256Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 1522145256Sjkoshy __K8SETMASK(nmct); 1523145256Sjkoshy break; 1524145256Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 1525145256Sjkoshy __K8SETMASK(nmcbs); 1526145256Sjkoshy break; 1527145256Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 1528145256Sjkoshy __K8SETMASK(nsc); 1529145256Sjkoshy break; 1530145256Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 1531145256Sjkoshy __K8SETMASK(npr); 1532145256Sjkoshy break; 1533145256Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 1534145256Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 1535145256Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 1536145256Sjkoshy __K8SETMASK(nhbb); 1537145256Sjkoshy break; 1538145256Sjkoshy 1539145256Sjkoshy default: 1540145256Sjkoshy break; /* no options defined */ 1541145256Sjkoshy } 1542145256Sjkoshy 1543145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1544145256Sjkoshy 1545145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1546145256Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 1547145256Sjkoshy q = strchr(p, '='); 1548145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1549145256Sjkoshy return -1; 1550145256Sjkoshy 1551145256Sjkoshy count = strtol(q, &e, 0); 1552145256Sjkoshy if (e == q || *e != '\0') 1553145256Sjkoshy return -1; 1554145256Sjkoshy 1555145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1556145256Sjkoshy pmc_config->pm_amd_config |= K8_PMC_TO_COUNTER(count); 1557145256Sjkoshy 1558145256Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 1559145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1560145256Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 1561145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1562145256Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 1563145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1564145256Sjkoshy return -1; 1565145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1566145256Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 1567145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1568145256Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 1569145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1570145256Sjkoshy } else 1571145256Sjkoshy return -1; 1572145256Sjkoshy } 1573145256Sjkoshy 1574145256Sjkoshy /* other post processing */ 1575145256Sjkoshy 1576145256Sjkoshy switch (pe) { 1577145256Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 1578145256Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 1579145256Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 1580145256Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 1581145256Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 1582145256Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 1583145256Sjkoshy /* XXX only available in rev B and later */ 1584145256Sjkoshy break; 1585145256Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 1586145256Sjkoshy /* XXX only available in rev C and later */ 1587145256Sjkoshy break; 1588145256Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 1589145256Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 1590145256Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 1591145256Sjkoshy return -1; 1592145256Sjkoshy if (evmask == 0) { 1593145256Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 1594145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1595145256Sjkoshy } 1596145256Sjkoshy break; 1597145256Sjkoshy default: 1598145256Sjkoshy if (evmask == 0 && pmask != NULL) { 1599145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1600145256Sjkoshy evmask |= pm->pm_value; 1601145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1602145256Sjkoshy } 1603145256Sjkoshy } 1604145256Sjkoshy 1605145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1606145256Sjkoshy pmc_config->pm_amd_config = K8_PMC_TO_UNITMASK(evmask); 1607145256Sjkoshy 1608145256Sjkoshy return 0; 1609145256Sjkoshy} 1610145256Sjkoshy#endif 1611145256Sjkoshy 1612145256Sjkoshy/* 1613145256Sjkoshy * API entry points 1614145256Sjkoshy */ 1615145256Sjkoshy 1616145256Sjkoshyint 1617145256Sjkoshypmc_init(void) 1618145256Sjkoshy{ 1619145256Sjkoshy int error, pmc_mod_id; 1620145256Sjkoshy uint32_t abi_version; 1621145256Sjkoshy struct module_stat pmc_modstat; 1622145256Sjkoshy 1623145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 1624145256Sjkoshy return 0; 1625145256Sjkoshy 1626145256Sjkoshy /* retrieve the system call number from the KLD */ 1627145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 1628145256Sjkoshy return -1; 1629145256Sjkoshy 1630145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 1631145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 1632145256Sjkoshy return -1; 1633145256Sjkoshy 1634145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 1635145256Sjkoshy 1636145256Sjkoshy /* check ABI version against compiled-in version */ 1637145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 1638145256Sjkoshy return (pmc_syscall = -1); 1639145256Sjkoshy 1640145256Sjkoshy /* ignore patch numbers for the comparision */ 1641145256Sjkoshy if ((abi_version & 0xFFFF0000) != (PMC_VERSION & 0xFFFF0000)) { 1642145256Sjkoshy errno = EPROGMISMATCH; 1643145256Sjkoshy return (pmc_syscall = -1); 1644145256Sjkoshy } 1645145256Sjkoshy 1646145256Sjkoshy if (PMC_CALL(GETCPUINFO, &cpu_info) < 0) 1647145256Sjkoshy return (pmc_syscall = -1); 1648145256Sjkoshy 1649145256Sjkoshy /* set parser pointer */ 1650145256Sjkoshy switch (cpu_info.pm_cputype) { 1651145340Smarcel#if defined(__i386__) 1652145256Sjkoshy case PMC_CPU_AMD_K7: 1653145256Sjkoshy pmc_mdep_event_aliases = k7_aliases; 1654145256Sjkoshy pmc_mdep_allocate_pmc = k7_allocate_pmc; 1655145256Sjkoshy break; 1656145256Sjkoshy case PMC_CPU_INTEL_P5: 1657145256Sjkoshy pmc_mdep_event_aliases = p5_aliases; 1658145256Sjkoshy pmc_mdep_allocate_pmc = p5_allocate_pmc; 1659145256Sjkoshy break; 1660145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 1661145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 1662145256Sjkoshy case PMC_CPU_INTEL_PIII: 1663145256Sjkoshy case PMC_CPU_INTEL_PM: 1664145256Sjkoshy pmc_mdep_event_aliases = p6_aliases; 1665145256Sjkoshy pmc_mdep_allocate_pmc = p6_allocate_pmc; 1666145256Sjkoshy break; 1667145256Sjkoshy case PMC_CPU_INTEL_PIV: 1668145256Sjkoshy pmc_mdep_event_aliases = p4_aliases; 1669145256Sjkoshy pmc_mdep_allocate_pmc = p4_allocate_pmc; 1670145256Sjkoshy break; 1671145340Smarcel#elif defined(__amd64__) 1672145256Sjkoshy case PMC_CPU_AMD_K8: 1673145256Sjkoshy pmc_mdep_event_aliases = k8_aliases; 1674145256Sjkoshy pmc_mdep_allocate_pmc = k8_allocate_pmc; 1675145256Sjkoshy break; 1676145256Sjkoshy#endif 1677145256Sjkoshy 1678145256Sjkoshy default: 1679145256Sjkoshy /* 1680145256Sjkoshy * Some kind of CPU this version of the library knows nothing 1681145256Sjkoshy * about. This shouldn't happen since the abi version check 1682145256Sjkoshy * should have caught this. 1683145256Sjkoshy */ 1684145256Sjkoshy errno = ENXIO; 1685145256Sjkoshy return (pmc_syscall = -1); 1686145256Sjkoshy } 1687145256Sjkoshy 1688145256Sjkoshy return 0; 1689145256Sjkoshy} 1690145256Sjkoshy 1691145256Sjkoshyint 1692145256Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 1693145256Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 1694145256Sjkoshy{ 1695145256Sjkoshy int retval; 1696145256Sjkoshy enum pmc_event pe; 1697145256Sjkoshy char *r, *spec_copy; 1698145256Sjkoshy const char *ctrname; 1699145256Sjkoshy const struct pmc_event_alias *p; 1700145256Sjkoshy struct pmc_op_pmcallocate pmc_config; 1701145256Sjkoshy 1702145256Sjkoshy spec_copy = NULL; 1703145256Sjkoshy retval = -1; 1704145256Sjkoshy 1705145256Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 1706145256Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 1707145256Sjkoshy errno = EINVAL; 1708145256Sjkoshy goto out; 1709145256Sjkoshy } 1710145256Sjkoshy 1711145256Sjkoshy /* replace an event alias with the canonical event specifier */ 1712145256Sjkoshy if (pmc_mdep_event_aliases) 1713145256Sjkoshy for (p = pmc_mdep_event_aliases; p->pm_alias; p++) 1714145256Sjkoshy if (!strcmp(ctrspec, p->pm_alias)) { 1715145256Sjkoshy spec_copy = strdup(p->pm_spec); 1716145256Sjkoshy break; 1717145256Sjkoshy } 1718145256Sjkoshy 1719145256Sjkoshy if (spec_copy == NULL) 1720145256Sjkoshy spec_copy = strdup(ctrspec); 1721145256Sjkoshy 1722145256Sjkoshy r = spec_copy; 1723145256Sjkoshy ctrname = strsep(&r, ","); 1724145256Sjkoshy 1725145256Sjkoshy /* look for the given counter name */ 1726145256Sjkoshy 1727145256Sjkoshy for (pe = PMC_EVENT_FIRST; pe < (PMC_EVENT_LAST+1); pe++) 1728145256Sjkoshy if (!strcmp(ctrname, pmc_event_table[pe].pm_ev_name)) 1729145256Sjkoshy break; 1730145256Sjkoshy 1731145256Sjkoshy if (pe > PMC_EVENT_LAST) { 1732145256Sjkoshy errno = EINVAL; 1733145256Sjkoshy goto out; 1734145256Sjkoshy } 1735145256Sjkoshy 1736145256Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 1737145256Sjkoshy pmc_config.pm_ev = pmc_event_table[pe].pm_ev_code; 1738145256Sjkoshy pmc_config.pm_class = pmc_event_table[pe].pm_ev_class; 1739145256Sjkoshy pmc_config.pm_cpu = cpu; 1740145256Sjkoshy pmc_config.pm_mode = mode; 1741145256Sjkoshy pmc_config.pm_flags = flags; 1742145256Sjkoshy 1743145256Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 1744145256Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 1745145256Sjkoshy 1746145256Sjkoshy if (pmc_mdep_allocate_pmc(pe, r, &pmc_config) < 0) { 1747145256Sjkoshy errno = EINVAL; 1748145256Sjkoshy goto out; 1749145256Sjkoshy } 1750145256Sjkoshy 1751145256Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 1752145256Sjkoshy goto out; 1753145256Sjkoshy 1754145256Sjkoshy *pmcid = pmc_config.pm_pmcid; 1755145256Sjkoshy 1756145256Sjkoshy retval = 0; 1757145256Sjkoshy 1758145256Sjkoshy out: 1759145256Sjkoshy if (spec_copy) 1760145256Sjkoshy free(spec_copy); 1761145256Sjkoshy 1762145256Sjkoshy return retval; 1763145256Sjkoshy} 1764145256Sjkoshy 1765145256Sjkoshyint 1766145256Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 1767145256Sjkoshy{ 1768145256Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 1769145256Sjkoshy 1770145256Sjkoshy pmc_attach_args.pm_pmc = pmc; 1771145256Sjkoshy pmc_attach_args.pm_pid = pid; 1772145256Sjkoshy 1773145256Sjkoshy return PMC_CALL(PMCATTACH, &pmc_attach_args); 1774145256Sjkoshy} 1775145256Sjkoshy 1776145256Sjkoshyint 1777145256Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 1778145256Sjkoshy{ 1779145256Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 1780145256Sjkoshy 1781145256Sjkoshy pmc_detach_args.pm_pmc = pmc; 1782145256Sjkoshy pmc_detach_args.pm_pid = pid; 1783145256Sjkoshy 1784145256Sjkoshy return PMC_CALL(PMCDETACH, &pmc_detach_args); 1785145256Sjkoshy} 1786145256Sjkoshy 1787145256Sjkoshyint 1788145256Sjkoshypmc_release(pmc_id_t pmc) 1789145256Sjkoshy{ 1790145256Sjkoshy struct pmc_op_simple pmc_release_args; 1791145256Sjkoshy 1792145256Sjkoshy pmc_release_args.pm_pmcid = pmc; 1793145256Sjkoshy 1794145256Sjkoshy return PMC_CALL(PMCRELEASE, &pmc_release_args); 1795145256Sjkoshy} 1796145256Sjkoshy 1797145256Sjkoshyint 1798145256Sjkoshypmc_start(pmc_id_t pmc) 1799145256Sjkoshy{ 1800145256Sjkoshy struct pmc_op_simple pmc_start_args; 1801145256Sjkoshy 1802145256Sjkoshy pmc_start_args.pm_pmcid = pmc; 1803145256Sjkoshy return PMC_CALL(PMCSTART, &pmc_start_args); 1804145256Sjkoshy} 1805145256Sjkoshy 1806145256Sjkoshyint 1807145256Sjkoshypmc_stop(pmc_id_t pmc) 1808145256Sjkoshy{ 1809145256Sjkoshy struct pmc_op_simple pmc_stop_args; 1810145256Sjkoshy 1811145256Sjkoshy pmc_stop_args.pm_pmcid = pmc; 1812145256Sjkoshy return PMC_CALL(PMCSTOP, &pmc_stop_args); 1813145256Sjkoshy} 1814145256Sjkoshy 1815145256Sjkoshyint 1816145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 1817145256Sjkoshy{ 1818145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 1819145256Sjkoshy 1820145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 1821145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 1822145256Sjkoshy pmc_read_op.pm_value = -1; 1823145256Sjkoshy 1824145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 1825145256Sjkoshy return -1; 1826145256Sjkoshy 1827145256Sjkoshy *value = pmc_read_op.pm_value; 1828145256Sjkoshy 1829145256Sjkoshy return 0; 1830145256Sjkoshy} 1831145256Sjkoshy 1832145256Sjkoshyint 1833145256Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 1834145256Sjkoshy{ 1835145256Sjkoshy struct pmc_op_pmcrw pmc_write_op; 1836145256Sjkoshy 1837145256Sjkoshy pmc_write_op.pm_pmcid = pmc; 1838145256Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 1839145256Sjkoshy pmc_write_op.pm_value = value; 1840145256Sjkoshy 1841145256Sjkoshy return PMC_CALL(PMCRW, &pmc_write_op); 1842145256Sjkoshy} 1843145256Sjkoshy 1844145256Sjkoshyint 1845145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 1846145256Sjkoshy{ 1847145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 1848145256Sjkoshy 1849145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 1850145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 1851145256Sjkoshy pmc_rw_op.pm_value = newvalue; 1852145256Sjkoshy 1853145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 1854145256Sjkoshy return -1; 1855145256Sjkoshy 1856145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 1857145256Sjkoshy 1858145256Sjkoshy return 0; 1859145256Sjkoshy} 1860145256Sjkoshy 1861145256Sjkoshyint 1862145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 1863145256Sjkoshy{ 1864145256Sjkoshy struct pmc_op_pmcsetcount sc; 1865145256Sjkoshy 1866145256Sjkoshy sc.pm_pmcid = pmc; 1867145256Sjkoshy sc.pm_count = value; 1868145256Sjkoshy 1869145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 1870145256Sjkoshy return -1; 1871145256Sjkoshy 1872145256Sjkoshy return 0; 1873145256Sjkoshy 1874145256Sjkoshy} 1875145256Sjkoshy 1876145256Sjkoshyint 1877145256Sjkoshypmc_configure_logfile(int fd) 1878145256Sjkoshy{ 1879145256Sjkoshy struct pmc_op_configurelog cla; 1880145256Sjkoshy 1881145256Sjkoshy cla.pm_logfd = fd; 1882145256Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 1883145256Sjkoshy return -1; 1884145256Sjkoshy 1885145256Sjkoshy return 0; 1886145256Sjkoshy} 1887145256Sjkoshy 1888145256Sjkoshyint 1889145256Sjkoshypmc_get_driver_stats(struct pmc_op_getdriverstats *gms) 1890145256Sjkoshy{ 1891145256Sjkoshy return PMC_CALL(GETDRIVERSTATS, gms); 1892145256Sjkoshy} 1893145256Sjkoshy 1894145256Sjkoshyint 1895145256Sjkoshypmc_ncpu(void) 1896145256Sjkoshy{ 1897145256Sjkoshy if (pmc_syscall == -1) { 1898145256Sjkoshy errno = ENXIO; 1899145256Sjkoshy return -1; 1900145256Sjkoshy } 1901145256Sjkoshy 1902145256Sjkoshy return cpu_info.pm_ncpu; 1903145256Sjkoshy} 1904145256Sjkoshy 1905145256Sjkoshyint 1906145256Sjkoshypmc_npmc(int cpu) 1907145256Sjkoshy{ 1908145256Sjkoshy if (pmc_syscall == -1) { 1909145256Sjkoshy errno = ENXIO; 1910145256Sjkoshy return -1; 1911145256Sjkoshy } 1912145256Sjkoshy 1913145256Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 1914145256Sjkoshy errno = EINVAL; 1915145256Sjkoshy return -1; 1916145256Sjkoshy } 1917145256Sjkoshy 1918145256Sjkoshy return cpu_info.pm_npmc; 1919145256Sjkoshy} 1920145256Sjkoshy 1921145256Sjkoshyint 1922145256Sjkoshypmc_enable(int cpu, int pmc) 1923145256Sjkoshy{ 1924145256Sjkoshy struct pmc_op_pmcadmin ssa; 1925145256Sjkoshy 1926145256Sjkoshy ssa.pm_cpu = cpu; 1927145256Sjkoshy ssa.pm_pmc = pmc; 1928145256Sjkoshy ssa.pm_state = PMC_STATE_FREE; 1929145256Sjkoshy return PMC_CALL(PMCADMIN, &ssa); 1930145256Sjkoshy} 1931145256Sjkoshy 1932145256Sjkoshyint 1933145256Sjkoshypmc_disable(int cpu, int pmc) 1934145256Sjkoshy{ 1935145256Sjkoshy struct pmc_op_pmcadmin ssa; 1936145256Sjkoshy 1937145256Sjkoshy ssa.pm_cpu = cpu; 1938145256Sjkoshy ssa.pm_pmc = pmc; 1939145256Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 1940145256Sjkoshy return PMC_CALL(PMCADMIN, &ssa); 1941145256Sjkoshy} 1942145256Sjkoshy 1943145256Sjkoshy 1944145256Sjkoshyint 1945145256Sjkoshypmc_pmcinfo(int cpu, struct pmc_op_getpmcinfo **ppmci) 1946145256Sjkoshy{ 1947145256Sjkoshy int nbytes, npmc, saved_errno; 1948145256Sjkoshy struct pmc_op_getpmcinfo *pmci; 1949145256Sjkoshy 1950145256Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 1951145256Sjkoshy return -1; 1952145256Sjkoshy 1953145256Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 1954145256Sjkoshy npmc * sizeof(struct pmc_info); 1955145256Sjkoshy 1956145256Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 1957145256Sjkoshy return -1; 1958145256Sjkoshy 1959145256Sjkoshy pmci->pm_cpu = cpu; 1960145256Sjkoshy 1961145256Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 1962145256Sjkoshy saved_errno = errno; 1963145256Sjkoshy free(pmci); 1964145256Sjkoshy errno = saved_errno; 1965145256Sjkoshy return -1; 1966145256Sjkoshy } 1967145256Sjkoshy 1968145256Sjkoshy *ppmci = pmci; 1969145256Sjkoshy return 0; 1970145256Sjkoshy} 1971145256Sjkoshy 1972145256Sjkoshyint 1973145256Sjkoshypmc_cpuinfo(const struct pmc_op_getcpuinfo **pci) 1974145256Sjkoshy{ 1975145256Sjkoshy if (pmc_syscall == -1) { 1976145256Sjkoshy errno = ENXIO; 1977145256Sjkoshy return -1; 1978145256Sjkoshy } 1979145256Sjkoshy 1980145256Sjkoshy *pci = &cpu_info; 1981145256Sjkoshy return 0; 1982145256Sjkoshy} 1983145256Sjkoshy 1984145774Sjkoshyint 1985145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 1986145774Sjkoshy{ 1987145774Sjkoshy unsigned int i; 1988145774Sjkoshy enum pmc_class cl; 1989145774Sjkoshy 1990145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 1991145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 1992145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 1993145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 1994145774Sjkoshy return 0; 1995145774Sjkoshy } 1996145774Sjkoshy return EINVAL; 1997145774Sjkoshy} 1998145774Sjkoshy 1999145774Sjkoshyint 2000145774Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 2001145774Sjkoshy{ 2002145774Sjkoshy unsigned int i; 2003145774Sjkoshy enum pmc_class cl; 2004145774Sjkoshy 2005145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2006145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2007145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2008145774Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 2009145774Sjkoshy return 0; 2010145774Sjkoshy } 2011145774Sjkoshy return EINVAL; 2012145774Sjkoshy} 2013145774Sjkoshy 2014145256Sjkoshyconst char * 2015145256Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2016145256Sjkoshy{ 2017145256Sjkoshy if ((int) cp >= PMC_CPU_FIRST && 2018145256Sjkoshy cp <= PMC_CPU_LAST) 2019145256Sjkoshy return pmc_cputype_names[cp]; 2020145256Sjkoshy errno = EINVAL; 2021145256Sjkoshy return NULL; 2022145256Sjkoshy} 2023145256Sjkoshy 2024145256Sjkoshyconst char * 2025145256Sjkoshypmc_name_of_class(enum pmc_class pc) 2026145256Sjkoshy{ 2027145256Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 2028145256Sjkoshy pc <= PMC_CLASS_LAST) 2029145256Sjkoshy return pmc_class_names[pc]; 2030145256Sjkoshy 2031145256Sjkoshy errno = EINVAL; 2032145256Sjkoshy return NULL; 2033145256Sjkoshy} 2034145256Sjkoshy 2035145256Sjkoshyconst char * 2036145256Sjkoshypmc_name_of_mode(enum pmc_mode pm) 2037145256Sjkoshy{ 2038145256Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 2039145256Sjkoshy pm <= PMC_MODE_LAST) 2040145256Sjkoshy return pmc_mode_names[pm]; 2041145256Sjkoshy 2042145256Sjkoshy errno = EINVAL; 2043145256Sjkoshy return NULL; 2044145256Sjkoshy} 2045145256Sjkoshy 2046145256Sjkoshyconst char * 2047145256Sjkoshypmc_name_of_event(enum pmc_event pe) 2048145256Sjkoshy{ 2049145256Sjkoshy if ((int) pe >= PMC_EVENT_FIRST && 2050145256Sjkoshy pe <= PMC_EVENT_LAST) 2051145256Sjkoshy return pmc_event_table[pe].pm_ev_name; 2052145256Sjkoshy 2053145256Sjkoshy errno = EINVAL; 2054145256Sjkoshy return NULL; 2055145256Sjkoshy} 2056145256Sjkoshy 2057145256Sjkoshyconst char * 2058145256Sjkoshypmc_name_of_state(enum pmc_state ps) 2059145256Sjkoshy{ 2060145256Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 2061145256Sjkoshy ps <= PMC_STATE_LAST) 2062145256Sjkoshy return pmc_state_names[ps]; 2063145256Sjkoshy 2064145256Sjkoshy errno = EINVAL; 2065145256Sjkoshy return NULL; 2066145256Sjkoshy} 2067145256Sjkoshy 2068145256Sjkoshyconst char * 2069145256Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2070145256Sjkoshy{ 2071145256Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2072145256Sjkoshy pd <= PMC_DISP_LAST) 2073145256Sjkoshy return pmc_disposition_names[pd]; 2074145256Sjkoshy 2075145256Sjkoshy errno = EINVAL; 2076145256Sjkoshy return NULL; 2077145256Sjkoshy} 2078145256Sjkoshy 2079145256Sjkoshyconst char * 2080145256Sjkoshypmc_name_of_capability(enum pmc_caps cap) 2081145256Sjkoshy{ 2082145256Sjkoshy int i; 2083145256Sjkoshy 2084145256Sjkoshy /* 2085145256Sjkoshy * 'cap' should have a single bit set and should be in 2086145256Sjkoshy * range. 2087145256Sjkoshy */ 2088145256Sjkoshy 2089145256Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 2090145256Sjkoshy cap > PMC_CAP_LAST) { 2091145256Sjkoshy errno = EINVAL; 2092145256Sjkoshy return NULL; 2093145256Sjkoshy } 2094145256Sjkoshy 2095145256Sjkoshy i = ffs(cap); 2096145256Sjkoshy 2097145256Sjkoshy return pmc_capability_names[i - 1]; 2098145256Sjkoshy} 2099145256Sjkoshy 2100145256Sjkoshy/* 2101145256Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 2102145256Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 2103145256Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 2104145256Sjkoshy * the number of event name pointers returned. 2105145256Sjkoshy * 2106145256Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 2107145256Sjkoshy * is responsible for freeing this space when done. 2108145256Sjkoshy */ 2109145256Sjkoshy 2110145256Sjkoshyint 2111145256Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 2112145256Sjkoshy int *nevents) 2113145256Sjkoshy{ 2114145256Sjkoshy int count; 2115145256Sjkoshy const char **names; 2116145256Sjkoshy const struct pmc_event_descr *ev; 2117145256Sjkoshy 2118145256Sjkoshy switch (cl) 2119145256Sjkoshy { 2120145256Sjkoshy case PMC_CLASS_TSC: 2121145256Sjkoshy ev = &pmc_event_table[PMC_EV_TSC_TSC]; 2122145256Sjkoshy count = 1; 2123145256Sjkoshy break; 2124145256Sjkoshy case PMC_CLASS_K7: 2125145256Sjkoshy ev = &pmc_event_table[PMC_EV_K7_FIRST]; 2126145256Sjkoshy count = PMC_EV_K7_LAST - PMC_EV_K7_FIRST + 1; 2127145256Sjkoshy break; 2128145256Sjkoshy case PMC_CLASS_K8: 2129145256Sjkoshy ev = &pmc_event_table[PMC_EV_K8_FIRST]; 2130145256Sjkoshy count = PMC_EV_K8_LAST - PMC_EV_K8_FIRST + 1; 2131145256Sjkoshy break; 2132145256Sjkoshy case PMC_CLASS_P5: 2133145256Sjkoshy ev = &pmc_event_table[PMC_EV_P5_FIRST]; 2134145256Sjkoshy count = PMC_EV_P5_LAST - PMC_EV_P5_FIRST + 1; 2135145256Sjkoshy break; 2136145256Sjkoshy case PMC_CLASS_P6: 2137145256Sjkoshy ev = &pmc_event_table[PMC_EV_P6_FIRST]; 2138145256Sjkoshy count = PMC_EV_P6_LAST - PMC_EV_P6_FIRST + 1; 2139145256Sjkoshy break; 2140145256Sjkoshy case PMC_CLASS_P4: 2141145256Sjkoshy ev = &pmc_event_table[PMC_EV_P4_FIRST]; 2142145256Sjkoshy count = PMC_EV_P4_LAST - PMC_EV_P4_FIRST + 1; 2143145256Sjkoshy break; 2144145256Sjkoshy default: 2145145256Sjkoshy errno = EINVAL; 2146145256Sjkoshy return -1; 2147145256Sjkoshy } 2148145256Sjkoshy 2149145256Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 2150145256Sjkoshy return -1; 2151145256Sjkoshy 2152145256Sjkoshy *eventnames = names; 2153145256Sjkoshy *nevents = count; 2154145256Sjkoshy 2155145256Sjkoshy for (;count--; ev++, names++) 2156145256Sjkoshy *names = ev->pm_ev_name; 2157145256Sjkoshy return 0; 2158145256Sjkoshy} 2159145256Sjkoshy 2160145256Sjkoshy/* 2161145256Sjkoshy * Architecture specific APIs 2162145256Sjkoshy */ 2163145256Sjkoshy 2164145340Smarcel#if defined(__i386__) || defined(__amd64__) 2165145256Sjkoshy 2166145256Sjkoshyint 2167145256Sjkoshypmc_x86_get_msr(pmc_id_t pmc, uint32_t *msr) 2168145256Sjkoshy{ 2169145256Sjkoshy struct pmc_op_x86_getmsr gm; 2170145256Sjkoshy 2171145256Sjkoshy gm.pm_pmcid = pmc; 2172145256Sjkoshy if (PMC_CALL(PMCX86GETMSR, &gm) < 0) 2173145256Sjkoshy return -1; 2174145256Sjkoshy *msr = gm.pm_msr; 2175145256Sjkoshy return 0; 2176145256Sjkoshy} 2177145256Sjkoshy 2178145256Sjkoshy#endif 2179