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