libpmc.c revision 155998
1145256Sjkoshy/*- 2147191Sjkoshy * Copyright (c) 2003-2005 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 155998 2006-02-25 05:34:00Z 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); 49147191Sjkoshy#endif 50147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 51147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 52145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 53147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 54147759Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 55147191Sjkoshy#endif 56147191Sjkoshy#if defined(__i386__) 57145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 58145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 59147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, 60145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 61145256Sjkoshy#endif 62145256Sjkoshy 63145256Sjkoshy#define PMC_CALL(cmd, params) \ 64145256Sjkoshy syscall(pmc_syscall, PMC_OP_##cmd, (params)) 65145256Sjkoshy 66145256Sjkoshy/* 67145256Sjkoshy * Event aliases provide a way for the user to ask for generic events 68145256Sjkoshy * like "cache-misses", or "instructions-retired". These aliases are 69145256Sjkoshy * mapped to the appropriate canonical event descriptions using a 70145256Sjkoshy * lookup table. 71145256Sjkoshy */ 72145256Sjkoshy 73145256Sjkoshystruct pmc_event_alias { 74145256Sjkoshy const char *pm_alias; 75145256Sjkoshy const char *pm_spec; 76145256Sjkoshy}; 77145256Sjkoshy 78145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 79145256Sjkoshy 80145256Sjkoshy/* 81145256Sjkoshy * The pmc_event_descr table maps symbolic names known to the user 82145256Sjkoshy * to integer codes used by the PMC KLD. 83145256Sjkoshy */ 84145256Sjkoshy 85145256Sjkoshystruct pmc_event_descr { 86145256Sjkoshy const char *pm_ev_name; 87145256Sjkoshy enum pmc_event pm_ev_code; 88145256Sjkoshy enum pmc_class pm_ev_class; 89145256Sjkoshy}; 90145256Sjkoshy 91145256Sjkoshystatic const struct pmc_event_descr 92145256Sjkoshypmc_event_table[] = 93145256Sjkoshy{ 94145256Sjkoshy#undef __PMC_EV 95145256Sjkoshy#define __PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C }, 96145256Sjkoshy __PMC_EVENTS() 97145256Sjkoshy}; 98145256Sjkoshy 99145256Sjkoshy/* 100145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 101145256Sjkoshy * strings. 102145256Sjkoshy */ 103145256Sjkoshy 104145256Sjkoshystatic const char * pmc_capability_names[] = { 105145256Sjkoshy#undef __PMC_CAP 106145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 107145256Sjkoshy __PMC_CAPS() 108145256Sjkoshy}; 109145256Sjkoshy 110145256Sjkoshystatic const char * pmc_class_names[] = { 111145256Sjkoshy#undef __PMC_CLASS 112145256Sjkoshy#define __PMC_CLASS(C) #C , 113145256Sjkoshy __PMC_CLASSES() 114145256Sjkoshy}; 115145256Sjkoshy 116145256Sjkoshystatic const char * pmc_cputype_names[] = { 117145256Sjkoshy#undef __PMC_CPU 118145256Sjkoshy#define __PMC_CPU(S, D) #S , 119145256Sjkoshy __PMC_CPUS() 120145256Sjkoshy}; 121145256Sjkoshy 122145256Sjkoshystatic const char * pmc_disposition_names[] = { 123145256Sjkoshy#undef __PMC_DISP 124145256Sjkoshy#define __PMC_DISP(D) #D , 125145256Sjkoshy __PMC_DISPOSITIONS() 126145256Sjkoshy}; 127145256Sjkoshy 128145256Sjkoshystatic const char * pmc_mode_names[] = { 129145256Sjkoshy#undef __PMC_MODE 130145256Sjkoshy#define __PMC_MODE(M,N) #M , 131145256Sjkoshy __PMC_MODES() 132145256Sjkoshy}; 133145256Sjkoshy 134145256Sjkoshystatic const char * pmc_state_names[] = { 135145256Sjkoshy#undef __PMC_STATE 136145256Sjkoshy#define __PMC_STATE(S) #S , 137145256Sjkoshy __PMC_STATES() 138145256Sjkoshy}; 139145256Sjkoshy 140145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 141145256Sjkoshy 142147219Sjkoshystatic struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */ 143145256Sjkoshy 144147219Sjkoshy 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 157147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 158145256Sjkoshystatic int 159145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 160145256Sjkoshy{ 161145256Sjkoshy const struct pmc_masks *pm; 162145256Sjkoshy char *q, *r; 163145256Sjkoshy int c; 164145256Sjkoshy 165145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 166145256Sjkoshy return -1; 167145256Sjkoshy q = strchr(p, '='); /* skip '=' */ 168145256Sjkoshy if (*++q == '\0') /* no more data */ 169145256Sjkoshy return -1; 170145256Sjkoshy c = 0; /* count of mask keywords seen */ 171145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 172145256Sjkoshy for (pm = pmask; pm->pm_name && strcmp(r, pm->pm_name); pm++) 173145256Sjkoshy ; 174145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 175145256Sjkoshy return -1; 176145256Sjkoshy *evmask |= pm->pm_value; 177145256Sjkoshy c++; 178145256Sjkoshy } 179145256Sjkoshy return c; 180145256Sjkoshy} 181145340Smarcel#endif 182145256Sjkoshy 183145256Sjkoshy#define KWMATCH(p,kw) (strcasecmp((p), (kw)) == 0) 184145256Sjkoshy#define KWPREFIXMATCH(p,kw) (strncasecmp((p), (kw), sizeof((kw)) - 1) == 0) 185145256Sjkoshy#define EV_ALIAS(N,S) { .pm_alias = N, .pm_spec = S } 186145256Sjkoshy 187145340Smarcel#if defined(__i386__) 188145256Sjkoshy 189145256Sjkoshy/* 190145256Sjkoshy * AMD K7 (Athlon) CPUs. 191145256Sjkoshy */ 192145256Sjkoshy 193145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 194145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 195145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 196145351Sjkoshy EV_ALIAS("cycles", "tsc"), 197145351Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses,mask=moesi"), 198145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 199145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 200145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 201145351Sjkoshy EV_ALIAS(NULL, NULL) 202145256Sjkoshy}; 203145256Sjkoshy 204145256Sjkoshy#define K7_KW_COUNT "count" 205145256Sjkoshy#define K7_KW_EDGE "edge" 206145256Sjkoshy#define K7_KW_INV "inv" 207145256Sjkoshy#define K7_KW_OS "os" 208145256Sjkoshy#define K7_KW_UNITMASK "unitmask" 209145256Sjkoshy#define K7_KW_USR "usr" 210145256Sjkoshy 211145256Sjkoshystatic int 212145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec, 213145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 214145256Sjkoshy{ 215145256Sjkoshy char *e, *p, *q; 216145256Sjkoshy int c, has_unitmask; 217145256Sjkoshy uint32_t count, unitmask; 218145256Sjkoshy 219147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 220145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 221145256Sjkoshy 222145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 223145256Sjkoshy /* TSC events must be unqualified. */ 224145256Sjkoshy if (ctrspec && *ctrspec != '\0') 225145256Sjkoshy return -1; 226145256Sjkoshy return 0; 227145256Sjkoshy } 228145256Sjkoshy 229145256Sjkoshy if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || 230145256Sjkoshy pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || 231145256Sjkoshy pe == PMC_EV_K7_DC_WRITEBACKS) { 232145256Sjkoshy has_unitmask = 1; 233147191Sjkoshy unitmask = AMD_PMC_UNITMASK_MOESI; 234145256Sjkoshy } else 235145256Sjkoshy unitmask = has_unitmask = 0; 236145256Sjkoshy 237145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 238145256Sjkoshy 239145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 240145256Sjkoshy if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { 241145256Sjkoshy q = strchr(p, '='); 242145256Sjkoshy if (*++q == '\0') /* skip '=' */ 243145256Sjkoshy return -1; 244145256Sjkoshy 245145256Sjkoshy count = strtol(q, &e, 0); 246145256Sjkoshy if (e == q || *e != '\0') 247145256Sjkoshy return -1; 248145256Sjkoshy 249145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 250147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 251147191Sjkoshy AMD_PMC_TO_COUNTER(count); 252145256Sjkoshy 253145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 254145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 255145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 256145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 257145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 258145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 259145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 260145256Sjkoshy if (has_unitmask == 0) 261145256Sjkoshy return -1; 262145256Sjkoshy unitmask = 0; 263145256Sjkoshy q = strchr(p, '='); 264145256Sjkoshy if (*++q == '\0') /* skip '=' */ 265145256Sjkoshy return -1; 266145256Sjkoshy 267145256Sjkoshy while ((c = tolower(*q++)) != 0) 268145256Sjkoshy if (c == 'm') 269147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 270145256Sjkoshy else if (c == 'o') 271147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 272145256Sjkoshy else if (c == 'e') 273147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 274145256Sjkoshy else if (c == 's') 275147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 276145256Sjkoshy else if (c == 'i') 277147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 278145256Sjkoshy else if (c == '+') 279145256Sjkoshy continue; 280145256Sjkoshy else 281145256Sjkoshy return -1; 282145256Sjkoshy 283145256Sjkoshy if (unitmask == 0) 284145256Sjkoshy return -1; 285145256Sjkoshy 286145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 287145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 288145256Sjkoshy } else 289145256Sjkoshy return -1; 290145256Sjkoshy } 291145256Sjkoshy 292145256Sjkoshy if (has_unitmask) { 293145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 294147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 295147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 296145256Sjkoshy } 297145256Sjkoshy 298145256Sjkoshy return 0; 299145256Sjkoshy 300145256Sjkoshy} 301145256Sjkoshy 302147191Sjkoshy#endif 303147191Sjkoshy 304147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 305147191Sjkoshy 306145256Sjkoshy/* 307147191Sjkoshy * AMD K8 PMCs. 308147191Sjkoshy * 309147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 310147191Sjkoshy * events. 311147191Sjkoshy */ 312147191Sjkoshy 313147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 314147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 315147191Sjkoshy EV_ALIAS("branch-mispredicts", 316147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 317147191Sjkoshy EV_ALIAS("cycles", "tsc"), 318147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 319147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 320147191Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 321147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 322155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 323147191Sjkoshy EV_ALIAS(NULL, NULL) 324147191Sjkoshy}; 325147191Sjkoshy 326147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 327147191Sjkoshy 328147191Sjkoshy/* 329147191Sjkoshy * Parsing tables 330147191Sjkoshy */ 331147191Sjkoshy 332147191Sjkoshy/* fp dispatched fpu ops */ 333147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 334147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 335147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 336147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 337147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 338147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 339147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 340147191Sjkoshy NULLMASK 341147191Sjkoshy}; 342147191Sjkoshy 343147191Sjkoshy/* ls segment register loads */ 344147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 345147191Sjkoshy __K8MASK(es, 0), 346147191Sjkoshy __K8MASK(cs, 1), 347147191Sjkoshy __K8MASK(ss, 2), 348147191Sjkoshy __K8MASK(ds, 3), 349147191Sjkoshy __K8MASK(fs, 4), 350147191Sjkoshy __K8MASK(gs, 5), 351147191Sjkoshy __K8MASK(hs, 6), 352147191Sjkoshy NULLMASK 353147191Sjkoshy}; 354147191Sjkoshy 355147191Sjkoshy/* ls locked operation */ 356147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 357147191Sjkoshy __K8MASK(locked-instructions, 0), 358147191Sjkoshy __K8MASK(cycles-in-request, 1), 359147191Sjkoshy __K8MASK(cycles-to-complete, 2), 360147191Sjkoshy NULLMASK 361147191Sjkoshy}; 362147191Sjkoshy 363147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 364147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 365147191Sjkoshy __K8MASK(invalid, 0), 366147191Sjkoshy __K8MASK(shared, 1), 367147191Sjkoshy __K8MASK(exclusive, 2), 368147191Sjkoshy __K8MASK(owner, 3), 369147191Sjkoshy __K8MASK(modified, 4), 370147191Sjkoshy NULLMASK 371147191Sjkoshy}; 372147191Sjkoshy 373147191Sjkoshy/* dc one bit ecc error */ 374147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 375147191Sjkoshy __K8MASK(scrubber, 0), 376147191Sjkoshy __K8MASK(piggyback, 1), 377147191Sjkoshy NULLMASK 378147191Sjkoshy}; 379147191Sjkoshy 380147191Sjkoshy/* dc dispatched prefetch instructions */ 381147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 382147191Sjkoshy __K8MASK(load, 0), 383147191Sjkoshy __K8MASK(store, 1), 384147191Sjkoshy __K8MASK(nta, 2), 385147191Sjkoshy NULLMASK 386147191Sjkoshy}; 387147191Sjkoshy 388147191Sjkoshy/* dc dcache accesses by locks */ 389147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 390147191Sjkoshy __K8MASK(accesses, 0), 391147191Sjkoshy __K8MASK(misses, 1), 392147191Sjkoshy NULLMASK 393147191Sjkoshy}; 394147191Sjkoshy 395147191Sjkoshy/* bu internal l2 request */ 396147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 397147191Sjkoshy __K8MASK(ic-fill, 0), 398147191Sjkoshy __K8MASK(dc-fill, 1), 399147191Sjkoshy __K8MASK(tlb-reload, 2), 400147191Sjkoshy __K8MASK(tag-snoop, 3), 401147191Sjkoshy __K8MASK(cancelled, 4), 402147191Sjkoshy NULLMASK 403147191Sjkoshy}; 404147191Sjkoshy 405147191Sjkoshy/* bu fill request l2 miss */ 406147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 407147191Sjkoshy __K8MASK(ic-fill, 0), 408147191Sjkoshy __K8MASK(dc-fill, 1), 409147191Sjkoshy __K8MASK(tlb-reload, 2), 410147191Sjkoshy NULLMASK 411147191Sjkoshy}; 412147191Sjkoshy 413147191Sjkoshy/* bu fill into l2 */ 414147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 415147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 416147191Sjkoshy __K8MASK(victim-from-l2, 1), 417147191Sjkoshy NULLMASK 418147191Sjkoshy}; 419147191Sjkoshy 420147191Sjkoshy/* fr retired fpu instructions */ 421147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 422147191Sjkoshy __K8MASK(x87, 0), 423147191Sjkoshy __K8MASK(mmx-3dnow, 1), 424147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 425147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 426147191Sjkoshy NULLMASK 427147191Sjkoshy}; 428147191Sjkoshy 429147191Sjkoshy/* fr retired fastpath double op instructions */ 430147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 431147191Sjkoshy __K8MASK(low-op-pos-0, 0), 432147191Sjkoshy __K8MASK(low-op-pos-1, 1), 433147191Sjkoshy __K8MASK(low-op-pos-2, 2), 434147191Sjkoshy NULLMASK 435147191Sjkoshy}; 436147191Sjkoshy 437147191Sjkoshy/* fr fpu exceptions */ 438147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 439147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 440147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 441147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 442147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 443147191Sjkoshy NULLMASK 444147191Sjkoshy}; 445147191Sjkoshy 446147191Sjkoshy/* nb memory controller page access event */ 447147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 448147191Sjkoshy __K8MASK(page-hit, 0), 449147191Sjkoshy __K8MASK(page-miss, 1), 450147191Sjkoshy __K8MASK(page-conflict, 2), 451147191Sjkoshy NULLMASK 452147191Sjkoshy}; 453147191Sjkoshy 454147191Sjkoshy/* nb memory controller turnaround */ 455147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 456147191Sjkoshy __K8MASK(dimm-turnaround, 0), 457147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 458147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 459147191Sjkoshy NULLMASK 460147191Sjkoshy}; 461147191Sjkoshy 462147191Sjkoshy/* nb memory controller bypass saturation */ 463147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 464147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 465147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 466147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 467147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 468147191Sjkoshy NULLMASK 469147191Sjkoshy}; 470147191Sjkoshy 471147191Sjkoshy/* nb sized commands */ 472147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 473147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 474147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 475147191Sjkoshy __K8MASK(postwrszbyte, 2), 476147191Sjkoshy __K8MASK(postwrszdword, 3), 477147191Sjkoshy __K8MASK(rdszbyte, 4), 478147191Sjkoshy __K8MASK(rdszdword, 5), 479147191Sjkoshy __K8MASK(rdmodwr, 6), 480147191Sjkoshy NULLMASK 481147191Sjkoshy}; 482147191Sjkoshy 483147191Sjkoshy/* nb probe result */ 484147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 485147191Sjkoshy __K8MASK(probe-miss, 0), 486147191Sjkoshy __K8MASK(probe-hit, 1), 487147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 488147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 489147191Sjkoshy NULLMASK 490147191Sjkoshy}; 491147191Sjkoshy 492147191Sjkoshy/* nb hypertransport bus bandwidth */ 493147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 494147191Sjkoshy __K8MASK(command, 0), 495147191Sjkoshy __K8MASK(data, 1), 496147191Sjkoshy __K8MASK(buffer-release, 2), 497147191Sjkoshy __K8MASK(nop, 3), 498147191Sjkoshy NULLMASK 499147191Sjkoshy}; 500147191Sjkoshy 501147191Sjkoshy#undef __K8MASK 502147191Sjkoshy 503147191Sjkoshy#define K8_KW_COUNT "count" 504147191Sjkoshy#define K8_KW_EDGE "edge" 505147191Sjkoshy#define K8_KW_INV "inv" 506147191Sjkoshy#define K8_KW_MASK "mask" 507147191Sjkoshy#define K8_KW_OS "os" 508147191Sjkoshy#define K8_KW_USR "usr" 509147191Sjkoshy 510147191Sjkoshystatic int 511147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 512147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 513147191Sjkoshy{ 514147191Sjkoshy char *e, *p, *q; 515147191Sjkoshy int n; 516147191Sjkoshy uint32_t count, evmask; 517147191Sjkoshy const struct pmc_masks *pm, *pmask; 518147191Sjkoshy 519147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 520147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 521147191Sjkoshy 522147191Sjkoshy if (pe == PMC_EV_TSC_TSC) { 523147191Sjkoshy /* TSC events must be unqualified. */ 524147191Sjkoshy if (ctrspec && *ctrspec != '\0') 525147191Sjkoshy return -1; 526147191Sjkoshy return 0; 527147191Sjkoshy } 528147191Sjkoshy 529147191Sjkoshy pmask = NULL; 530147191Sjkoshy evmask = 0; 531147191Sjkoshy 532147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 533147191Sjkoshy 534147191Sjkoshy /* setup parsing tables */ 535147191Sjkoshy switch (pe) { 536147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 537147191Sjkoshy __K8SETMASK(fdfo); 538147191Sjkoshy break; 539147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 540147191Sjkoshy __K8SETMASK(lsrl); 541147191Sjkoshy break; 542147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 543147191Sjkoshy __K8SETMASK(llo); 544147191Sjkoshy break; 545147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 546147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 547147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 548147191Sjkoshy __K8SETMASK(dc); 549147191Sjkoshy break; 550147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 551147191Sjkoshy __K8SETMASK(dobee); 552147191Sjkoshy break; 553147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 554147191Sjkoshy __K8SETMASK(ddpi); 555147191Sjkoshy break; 556147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 557147191Sjkoshy __K8SETMASK(dabl); 558147191Sjkoshy break; 559147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 560147191Sjkoshy __K8SETMASK(bilr); 561147191Sjkoshy break; 562147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 563147191Sjkoshy __K8SETMASK(bfrlm); 564147191Sjkoshy break; 565147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 566147191Sjkoshy __K8SETMASK(bfil); 567147191Sjkoshy break; 568147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 569147191Sjkoshy __K8SETMASK(frfi); 570147191Sjkoshy break; 571147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 572147191Sjkoshy __K8SETMASK(frfdoi); 573147191Sjkoshy break; 574147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 575147191Sjkoshy __K8SETMASK(ffe); 576147191Sjkoshy break; 577147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 578147191Sjkoshy __K8SETMASK(nmcpae); 579147191Sjkoshy break; 580147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 581147191Sjkoshy __K8SETMASK(nmct); 582147191Sjkoshy break; 583147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 584147191Sjkoshy __K8SETMASK(nmcbs); 585147191Sjkoshy break; 586147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 587147191Sjkoshy __K8SETMASK(nsc); 588147191Sjkoshy break; 589147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 590147191Sjkoshy __K8SETMASK(npr); 591147191Sjkoshy break; 592147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 593147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 594147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 595147191Sjkoshy __K8SETMASK(nhbb); 596147191Sjkoshy break; 597147191Sjkoshy 598147191Sjkoshy default: 599147191Sjkoshy break; /* no options defined */ 600147191Sjkoshy } 601147191Sjkoshy 602147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 603147191Sjkoshy 604147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 605147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 606147191Sjkoshy q = strchr(p, '='); 607147191Sjkoshy if (*++q == '\0') /* skip '=' */ 608147191Sjkoshy return -1; 609147191Sjkoshy 610147191Sjkoshy count = strtol(q, &e, 0); 611147191Sjkoshy if (e == q || *e != '\0') 612147191Sjkoshy return -1; 613147191Sjkoshy 614147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 615147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 616147191Sjkoshy AMD_PMC_TO_COUNTER(count); 617147191Sjkoshy 618147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 619147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 620147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 621147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 622147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 623147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 624147191Sjkoshy return -1; 625147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 626147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 627147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 628147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 629147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 630147191Sjkoshy } else 631147191Sjkoshy return -1; 632147191Sjkoshy } 633147191Sjkoshy 634147191Sjkoshy /* other post processing */ 635147191Sjkoshy 636147191Sjkoshy switch (pe) { 637147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 638147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 639147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 640147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 641147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 642147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 643147191Sjkoshy /* XXX only available in rev B and later */ 644147191Sjkoshy break; 645147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 646147191Sjkoshy /* XXX only available in rev C and later */ 647147191Sjkoshy break; 648147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 649147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 650147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 651147191Sjkoshy return -1; 652147191Sjkoshy if (evmask == 0) { 653147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 654147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 655147191Sjkoshy } 656147191Sjkoshy break; 657147191Sjkoshy default: 658147191Sjkoshy if (evmask == 0 && pmask != NULL) { 659147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 660147191Sjkoshy evmask |= pm->pm_value; 661147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 662147191Sjkoshy } 663147191Sjkoshy } 664147191Sjkoshy 665147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 666147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 667147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 668147191Sjkoshy 669147191Sjkoshy return 0; 670147191Sjkoshy} 671147191Sjkoshy 672147191Sjkoshy#endif 673147191Sjkoshy 674147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 675147191Sjkoshy 676147191Sjkoshy/* 677145256Sjkoshy * Intel P4 PMCs 678145256Sjkoshy */ 679145256Sjkoshy 680145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 681145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 682145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 683145351Sjkoshy EV_ALIAS("cycles", "tsc"), 684145351Sjkoshy EV_ALIAS("instructions", 685145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 686155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 687145256Sjkoshy EV_ALIAS(NULL, NULL) 688145256Sjkoshy}; 689145256Sjkoshy 690145256Sjkoshy#define P4_KW_ACTIVE "active" 691145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 692145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 693145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 694145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 695145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 696145256Sjkoshy#define P4_KW_CASCADE "cascade" 697145256Sjkoshy#define P4_KW_EDGE "edge" 698145256Sjkoshy#define P4_KW_INV "complement" 699145256Sjkoshy#define P4_KW_OS "os" 700145256Sjkoshy#define P4_KW_MASK "mask" 701145256Sjkoshy#define P4_KW_PRECISE "precise" 702145256Sjkoshy#define P4_KW_TAG "tag" 703145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 704145256Sjkoshy#define P4_KW_USR "usr" 705145256Sjkoshy 706145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 707145256Sjkoshy 708145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 709145256Sjkoshy __P4MASK(dd, 0), 710145256Sjkoshy __P4MASK(db, 1), 711145256Sjkoshy __P4MASK(di, 2), 712145256Sjkoshy __P4MASK(bd, 3), 713145256Sjkoshy __P4MASK(bb, 4), 714145256Sjkoshy __P4MASK(bi, 5), 715145256Sjkoshy __P4MASK(id, 6), 716145256Sjkoshy __P4MASK(ib, 7), 717145256Sjkoshy NULLMASK 718145256Sjkoshy}; 719145256Sjkoshy 720145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 721145256Sjkoshy __P4MASK(tcmiss, 0), 722145256Sjkoshy NULLMASK, 723145256Sjkoshy}; 724145256Sjkoshy 725145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 726145256Sjkoshy __P4MASK(hit, 0), 727145256Sjkoshy __P4MASK(miss, 1), 728145256Sjkoshy __P4MASK(hit-uc, 2), 729145256Sjkoshy NULLMASK 730145256Sjkoshy}; 731145256Sjkoshy 732145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 733145256Sjkoshy __P4MASK(st-rb-full, 2), 734145256Sjkoshy __P4MASK(64k-conf, 3), 735145256Sjkoshy NULLMASK 736145256Sjkoshy}; 737145256Sjkoshy 738145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 739145256Sjkoshy __P4MASK(lsc, 0), 740145256Sjkoshy __P4MASK(ssc, 1), 741145256Sjkoshy NULLMASK 742145256Sjkoshy}; 743145256Sjkoshy 744145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 745145256Sjkoshy __P4MASK(split-ld, 1), 746145256Sjkoshy NULLMASK 747145256Sjkoshy}; 748145256Sjkoshy 749145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 750145256Sjkoshy __P4MASK(split-st, 1), 751145256Sjkoshy NULLMASK 752145256Sjkoshy}; 753145256Sjkoshy 754145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 755145256Sjkoshy __P4MASK(no-sta, 1), 756145256Sjkoshy __P4MASK(no-std, 3), 757145256Sjkoshy __P4MASK(partial-data, 4), 758145256Sjkoshy __P4MASK(unalgn-addr, 5), 759145256Sjkoshy NULLMASK 760145256Sjkoshy}; 761145256Sjkoshy 762145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 763145256Sjkoshy __P4MASK(dtmiss, 0), 764145256Sjkoshy __P4MASK(itmiss, 1), 765145256Sjkoshy NULLMASK 766145256Sjkoshy}; 767145256Sjkoshy 768145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 769145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 770145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 771145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 772145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 773145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 774145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 775145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 776145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 777145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 778145256Sjkoshy NULLMASK 779145256Sjkoshy}; 780145256Sjkoshy 781145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 782145256Sjkoshy __P4MASK(all-read, 5), 783145256Sjkoshy __P4MASK(all-write, 6), 784145256Sjkoshy __P4MASK(mem-uc, 7), 785145256Sjkoshy __P4MASK(mem-wc, 8), 786145256Sjkoshy __P4MASK(mem-wt, 9), 787145256Sjkoshy __P4MASK(mem-wp, 10), 788145256Sjkoshy __P4MASK(mem-wb, 11), 789145256Sjkoshy __P4MASK(own, 13), 790145256Sjkoshy __P4MASK(other, 14), 791145256Sjkoshy __P4MASK(prefetch, 15), 792145256Sjkoshy NULLMASK 793145256Sjkoshy}; 794145256Sjkoshy 795145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 796145256Sjkoshy __P4MASK(all-read, 5), 797145256Sjkoshy __P4MASK(all-write, 6), 798145256Sjkoshy __P4MASK(mem-uc, 7), 799145256Sjkoshy __P4MASK(mem-wc, 8), 800145256Sjkoshy __P4MASK(mem-wt, 9), 801145256Sjkoshy __P4MASK(mem-wp, 10), 802145256Sjkoshy __P4MASK(mem-wb, 11), 803145256Sjkoshy __P4MASK(own, 13), 804145256Sjkoshy __P4MASK(other, 14), 805145256Sjkoshy __P4MASK(prefetch, 15), 806145256Sjkoshy NULLMASK 807145256Sjkoshy}; 808145256Sjkoshy 809145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 810145256Sjkoshy __P4MASK(drdy-drv, 0), 811145256Sjkoshy __P4MASK(drdy-own, 1), 812145256Sjkoshy __P4MASK(drdy-other, 2), 813145256Sjkoshy __P4MASK(dbsy-drv, 3), 814145256Sjkoshy __P4MASK(dbsy-own, 4), 815145256Sjkoshy __P4MASK(dbsy-other, 5), 816145256Sjkoshy NULLMASK 817145256Sjkoshy}; 818145256Sjkoshy 819145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 820145256Sjkoshy __P4MASK(req-type0, 0), 821145256Sjkoshy __P4MASK(req-type1, 1), 822145256Sjkoshy __P4MASK(req-len0, 2), 823145256Sjkoshy __P4MASK(req-len1, 3), 824145256Sjkoshy __P4MASK(req-io-type, 5), 825145256Sjkoshy __P4MASK(req-lock-type, 6), 826145256Sjkoshy __P4MASK(req-cache-type, 7), 827145256Sjkoshy __P4MASK(req-split-type, 8), 828145256Sjkoshy __P4MASK(req-dem-type, 9), 829145256Sjkoshy __P4MASK(req-ord-type, 10), 830145256Sjkoshy __P4MASK(mem-type0, 11), 831145256Sjkoshy __P4MASK(mem-type1, 12), 832145256Sjkoshy __P4MASK(mem-type2, 13), 833145256Sjkoshy NULLMASK 834145256Sjkoshy}; 835145256Sjkoshy 836145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 837145256Sjkoshy __P4MASK(all, 15), 838145256Sjkoshy NULLMASK 839145256Sjkoshy}; 840145256Sjkoshy 841145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 842145256Sjkoshy __P4MASK(all, 15), 843145256Sjkoshy NULLMASK 844145256Sjkoshy}; 845145256Sjkoshy 846145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 847145256Sjkoshy __P4MASK(all, 15), 848145256Sjkoshy NULLMASK 849145256Sjkoshy}; 850145256Sjkoshy 851145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 852145256Sjkoshy __P4MASK(all, 15), 853145256Sjkoshy NULLMASK 854145256Sjkoshy}; 855145256Sjkoshy 856145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 857145256Sjkoshy __P4MASK(all, 15), 858145256Sjkoshy NULLMASK 859145256Sjkoshy}; 860145256Sjkoshy 861145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 862145256Sjkoshy __P4MASK(all, 15), 863145256Sjkoshy NULLMASK 864145256Sjkoshy}; 865145256Sjkoshy 866145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 867145256Sjkoshy __P4MASK(all, 15), 868145256Sjkoshy NULLMASK 869145256Sjkoshy}; 870145256Sjkoshy 871145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 872145256Sjkoshy __P4MASK(all, 15), 873145256Sjkoshy NULLMASK 874145256Sjkoshy}; 875145256Sjkoshy 876145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 877145256Sjkoshy __P4MASK(allp0, 3), 878145256Sjkoshy __P4MASK(allp2, 4), 879145256Sjkoshy NULLMASK 880145256Sjkoshy}; 881145256Sjkoshy 882145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 883145256Sjkoshy __P4MASK(running, 0), 884145256Sjkoshy NULLMASK 885145256Sjkoshy}; 886145256Sjkoshy 887145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 888145256Sjkoshy __P4MASK(cisc, 0), 889145256Sjkoshy NULLMASK 890145256Sjkoshy}; 891145256Sjkoshy 892145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 893145256Sjkoshy __P4MASK(from-tc-build, 0), 894145256Sjkoshy __P4MASK(from-tc-deliver, 1), 895145256Sjkoshy __P4MASK(from-rom, 2), 896145256Sjkoshy NULLMASK 897145256Sjkoshy}; 898145256Sjkoshy 899145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 900145351Sjkoshy /* retired mispred branch type */ 901145256Sjkoshy __P4MASK(conditional, 1), 902145256Sjkoshy __P4MASK(call, 2), 903145256Sjkoshy __P4MASK(return, 3), 904145256Sjkoshy __P4MASK(indirect, 4), 905145256Sjkoshy NULLMASK 906145256Sjkoshy}; 907145256Sjkoshy 908145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 909145256Sjkoshy __P4MASK(conditional, 1), 910145256Sjkoshy __P4MASK(call, 2), 911145256Sjkoshy __P4MASK(retired, 3), 912145256Sjkoshy __P4MASK(indirect, 4), 913145256Sjkoshy NULLMASK 914145256Sjkoshy}; 915145256Sjkoshy 916145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 917145256Sjkoshy __P4MASK(sbfull, 5), 918145256Sjkoshy NULLMASK 919145256Sjkoshy}; 920145256Sjkoshy 921145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 922145256Sjkoshy __P4MASK(wcb-evicts, 0), 923145256Sjkoshy __P4MASK(wcb-full-evict, 1), 924145256Sjkoshy NULLMASK 925145256Sjkoshy}; 926145256Sjkoshy 927145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 928145256Sjkoshy __P4MASK(nbogus, 0), 929145256Sjkoshy __P4MASK(bogus, 1), 930145256Sjkoshy NULLMASK 931145256Sjkoshy}; 932145256Sjkoshy 933145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 934145256Sjkoshy __P4MASK(nbogus0, 0), 935145256Sjkoshy __P4MASK(nbogus1, 1), 936145256Sjkoshy __P4MASK(nbogus2, 2), 937145256Sjkoshy __P4MASK(nbogus3, 3), 938145256Sjkoshy __P4MASK(bogus0, 4), 939145256Sjkoshy __P4MASK(bogus1, 5), 940145256Sjkoshy __P4MASK(bogus2, 6), 941145256Sjkoshy __P4MASK(bogus3, 7), 942145256Sjkoshy NULLMASK 943145256Sjkoshy}; 944145256Sjkoshy 945145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 946145256Sjkoshy __P4MASK(nbogus, 0), 947145256Sjkoshy __P4MASK(bogus, 1), 948145256Sjkoshy NULLMASK 949145256Sjkoshy}; 950145256Sjkoshy 951145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 952145256Sjkoshy __P4MASK(nbogusntag, 0), 953145256Sjkoshy __P4MASK(nbogustag, 1), 954145256Sjkoshy __P4MASK(bogusntag, 2), 955145256Sjkoshy __P4MASK(bogustag, 3), 956145256Sjkoshy NULLMASK 957145256Sjkoshy}; 958145256Sjkoshy 959145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 960145256Sjkoshy __P4MASK(nbogus, 0), 961145256Sjkoshy __P4MASK(bogus, 1), 962145256Sjkoshy NULLMASK 963145256Sjkoshy}; 964145256Sjkoshy 965145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 966145256Sjkoshy __P4MASK(tagloads, 1), 967145256Sjkoshy __P4MASK(tagstores, 2), 968145256Sjkoshy NULLMASK 969145256Sjkoshy}; 970145256Sjkoshy 971145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 972145256Sjkoshy __P4MASK(mmnp, 0), 973145256Sjkoshy __P4MASK(mmnm, 1), 974145256Sjkoshy __P4MASK(mmtp, 2), 975145256Sjkoshy __P4MASK(mmtm, 3), 976145256Sjkoshy NULLMASK 977145256Sjkoshy}; 978145256Sjkoshy 979145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 980145256Sjkoshy __P4MASK(nbogus, 0), 981145256Sjkoshy NULLMASK 982145256Sjkoshy}; 983145256Sjkoshy 984145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 985145256Sjkoshy __P4MASK(fpsu, 0), 986145256Sjkoshy __P4MASK(fpso, 1), 987145256Sjkoshy __P4MASK(poao, 2), 988145256Sjkoshy __P4MASK(poau, 3), 989145256Sjkoshy __P4MASK(prea, 4), 990145256Sjkoshy NULLMASK 991145256Sjkoshy}; 992145256Sjkoshy 993145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 994145256Sjkoshy __P4MASK(clear, 0), 995145256Sjkoshy __P4MASK(moclear, 2), 996145256Sjkoshy __P4MASK(smclear, 3), 997145256Sjkoshy NULLMASK 998145256Sjkoshy}; 999145256Sjkoshy 1000145256Sjkoshy/* P4 event parser */ 1001145256Sjkoshystatic int 1002145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1003145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1004145256Sjkoshy{ 1005145256Sjkoshy 1006145256Sjkoshy char *e, *p, *q; 1007145256Sjkoshy int count, has_tag, has_busreqtype, n; 1008145256Sjkoshy uint32_t evmask, cccractivemask; 1009145256Sjkoshy const struct pmc_masks *pm, *pmask; 1010145256Sjkoshy 1011145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1012147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1013147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1014145256Sjkoshy 1015145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1016145256Sjkoshy /* TSC must not be further qualified */ 1017145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1018145256Sjkoshy return -1; 1019145256Sjkoshy return 0; 1020145256Sjkoshy } 1021145256Sjkoshy 1022145256Sjkoshy pmask = NULL; 1023145256Sjkoshy evmask = 0; 1024145256Sjkoshy cccractivemask = 0x3; 1025145256Sjkoshy has_tag = has_busreqtype = 0; 1026145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1027145256Sjkoshy 1028145256Sjkoshy#define __P4SETMASK(M) do { \ 1029145256Sjkoshy pmask = p4_mask_##M; \ 1030145256Sjkoshy} while (0) 1031145256Sjkoshy 1032145256Sjkoshy switch (pe) { 1033145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1034145256Sjkoshy __P4SETMASK(tcdm); 1035145256Sjkoshy break; 1036145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1037145256Sjkoshy __P4SETMASK(bfr); 1038145256Sjkoshy break; 1039145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1040145256Sjkoshy __P4SETMASK(ir); 1041145256Sjkoshy break; 1042145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1043145256Sjkoshy __P4SETMASK(memcan); 1044145256Sjkoshy break; 1045145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1046145256Sjkoshy __P4SETMASK(memcomp); 1047145256Sjkoshy break; 1048145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1049145256Sjkoshy __P4SETMASK(lpr); 1050145256Sjkoshy break; 1051145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1052145256Sjkoshy __P4SETMASK(spr); 1053145256Sjkoshy break; 1054145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1055145256Sjkoshy __P4SETMASK(mlr); 1056145256Sjkoshy break; 1057145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1058145256Sjkoshy __P4SETMASK(pwt); 1059145256Sjkoshy break; 1060145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1061145256Sjkoshy __P4SETMASK(bcr); 1062145256Sjkoshy break; 1063145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1064145256Sjkoshy __P4SETMASK(ia); 1065145256Sjkoshy has_busreqtype = 1; 1066145256Sjkoshy break; 1067145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1068145256Sjkoshy __P4SETMASK(iae); 1069145256Sjkoshy has_busreqtype = 1; 1070145256Sjkoshy break; 1071145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1072145256Sjkoshy __P4SETMASK(fda); 1073145256Sjkoshy break; 1074145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1075145256Sjkoshy __P4SETMASK(ba); 1076145256Sjkoshy break; 1077145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1078145256Sjkoshy __P4SETMASK(sia); 1079145256Sjkoshy break; 1080145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1081145256Sjkoshy __P4SETMASK(psu); 1082145256Sjkoshy break; 1083145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1084145256Sjkoshy __P4SETMASK(pdu); 1085145256Sjkoshy break; 1086145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1087145256Sjkoshy __P4SETMASK(ssu); 1088145256Sjkoshy break; 1089145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1090145256Sjkoshy __P4SETMASK(sdu); 1091145256Sjkoshy break; 1092145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1093145256Sjkoshy __P4SETMASK(64bmu); 1094145256Sjkoshy break; 1095145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1096145256Sjkoshy __P4SETMASK(128bmu); 1097145256Sjkoshy break; 1098145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1099145256Sjkoshy __P4SETMASK(xfu); 1100145256Sjkoshy break; 1101145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1102145256Sjkoshy __P4SETMASK(xsmu); 1103145256Sjkoshy break; 1104145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1105145256Sjkoshy __P4SETMASK(gpe); 1106145256Sjkoshy break; 1107145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1108145256Sjkoshy __P4SETMASK(tmx); 1109145256Sjkoshy break; 1110145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1111145256Sjkoshy __P4SETMASK(uqw); 1112145256Sjkoshy break; 1113145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1114145256Sjkoshy __P4SETMASK(rmbt); 1115145256Sjkoshy break; 1116145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1117145256Sjkoshy __P4SETMASK(rbt); 1118145256Sjkoshy break; 1119145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1120145256Sjkoshy __P4SETMASK(rs); 1121145256Sjkoshy break; 1122145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1123145256Sjkoshy __P4SETMASK(wb); 1124145256Sjkoshy break; 1125145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1126145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1127145256Sjkoshy case PMC_EV_P4_BNR: 1128145256Sjkoshy case PMC_EV_P4_SNOOP: 1129145256Sjkoshy case PMC_EV_P4_RESPONSE: 1130145256Sjkoshy break; 1131145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1132145256Sjkoshy __P4SETMASK(fee); 1133145256Sjkoshy break; 1134145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1135145256Sjkoshy __P4SETMASK(ee); 1136145256Sjkoshy break; 1137145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1138145256Sjkoshy __P4SETMASK(re); 1139145256Sjkoshy break; 1140145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1141145256Sjkoshy __P4SETMASK(insret); 1142145256Sjkoshy break; 1143145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1144145256Sjkoshy __P4SETMASK(ur); 1145145256Sjkoshy break; 1146145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1147145256Sjkoshy __P4SETMASK(ut); 1148145256Sjkoshy break; 1149145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1150145256Sjkoshy __P4SETMASK(br); 1151145256Sjkoshy break; 1152145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1153145256Sjkoshy __P4SETMASK(mbr); 1154145256Sjkoshy break; 1155145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1156145256Sjkoshy __P4SETMASK(xa); 1157145256Sjkoshy break; 1158145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1159145256Sjkoshy __P4SETMASK(machclr); 1160145256Sjkoshy break; 1161145256Sjkoshy default: 1162145256Sjkoshy return -1; 1163145256Sjkoshy } 1164145256Sjkoshy 1165145256Sjkoshy /* process additional flags */ 1166145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1167145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1168145256Sjkoshy q = strchr(p, '='); 1169145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1170145256Sjkoshy return -1; 1171145256Sjkoshy 1172145256Sjkoshy if (strcmp(q, P4_KW_ACTIVE_NONE) == 0) 1173145256Sjkoshy cccractivemask = 0x0; 1174145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1175145256Sjkoshy cccractivemask = 0x1; 1176145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_BOTH) == 0) 1177145256Sjkoshy cccractivemask = 0x2; 1178145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_ANY) == 0) 1179145256Sjkoshy cccractivemask = 0x3; 1180145256Sjkoshy else 1181145256Sjkoshy return -1; 1182145256Sjkoshy 1183145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1184145256Sjkoshy if (has_busreqtype == 0) 1185145256Sjkoshy return -1; 1186145256Sjkoshy 1187145256Sjkoshy q = strchr(p, '='); 1188145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1189145256Sjkoshy return -1; 1190145256Sjkoshy 1191145256Sjkoshy count = strtol(q, &e, 0); 1192145256Sjkoshy if (e == q || *e != '\0') 1193145256Sjkoshy return -1; 1194145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1195145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1196145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1197145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1198145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1199145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1200145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1201145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1202145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1203145256Sjkoshy return -1; 1204145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1205145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1206145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1207145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1208145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1209145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1210145256Sjkoshy if (has_tag == 0) 1211145256Sjkoshy return -1; 1212145256Sjkoshy 1213145256Sjkoshy q = strchr(p, '='); 1214145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1215145256Sjkoshy return -1; 1216145256Sjkoshy 1217145256Sjkoshy count = strtol(q, &e, 0); 1218145256Sjkoshy if (e == q || *e != '\0') 1219145256Sjkoshy return -1; 1220145256Sjkoshy 1221145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1222147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1223145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1224145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1225145256Sjkoshy q = strchr(p, '='); 1226145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1227145256Sjkoshy return -1; 1228145256Sjkoshy 1229145256Sjkoshy count = strtol(q, &e, 0); 1230145256Sjkoshy if (e == q || *e != '\0') 1231145256Sjkoshy return -1; 1232145256Sjkoshy 1233145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1234147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1235147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1236147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1237147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1238145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1239145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1240145256Sjkoshy else 1241145256Sjkoshy return -1; 1242145256Sjkoshy } 1243145256Sjkoshy 1244145256Sjkoshy /* other post processing */ 1245145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1246145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1247145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1248145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1249145256Sjkoshy 1250145256Sjkoshy /* fill in thread activity mask */ 1251147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1252145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1253145256Sjkoshy 1254145256Sjkoshy if (evmask) 1255145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1256145256Sjkoshy 1257145256Sjkoshy switch (pe) { 1258145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1259145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1260145256Sjkoshy (evmask & 0x18) == 0x18) 1261145256Sjkoshy return -1; /* can't have own+other bits together */ 1262145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1263145256Sjkoshy evmask = 0x1D; 1264145256Sjkoshy break; 1265145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1266145256Sjkoshy /* only one bit is allowed to be set */ 1267145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1268145256Sjkoshy return -1; 1269145256Sjkoshy if (evmask == 0) { 1270145256Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1271145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1272145256Sjkoshy } 1273145256Sjkoshy break; 1274145256Sjkoshy default: 1275145256Sjkoshy if (evmask == 0 && pmask) { 1276145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1277145256Sjkoshy evmask |= pm->pm_value; 1278145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1279145256Sjkoshy } 1280145256Sjkoshy } 1281145256Sjkoshy 1282147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1283147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1284145256Sjkoshy 1285145256Sjkoshy return 0; 1286145256Sjkoshy} 1287145256Sjkoshy 1288147759Sjkoshy#endif 1289147759Sjkoshy 1290147759Sjkoshy#if defined(__i386__) 1291147759Sjkoshy 1292145256Sjkoshy/* 1293147191Sjkoshy * Pentium style PMCs 1294147191Sjkoshy */ 1295147191Sjkoshy 1296147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1297147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1298147191Sjkoshy EV_ALIAS(NULL, NULL) 1299147191Sjkoshy}; 1300147191Sjkoshy 1301147191Sjkoshystatic int 1302147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1303147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1304147191Sjkoshy{ 1305147191Sjkoshy return -1 || pe || ctrspec || pmc_config; /* shut up gcc */ 1306147191Sjkoshy} 1307147191Sjkoshy 1308147191Sjkoshy/* 1309145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1310145256Sjkoshy * and Pentium M CPUs. 1311145256Sjkoshy */ 1312145256Sjkoshy 1313145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1314145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1315145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1316145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1317145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1318145351Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-ifetch-miss"), 1319145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1320145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1321155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1322145351Sjkoshy EV_ALIAS(NULL, NULL) 1323145256Sjkoshy}; 1324145256Sjkoshy 1325145256Sjkoshy#define P6_KW_CMASK "cmask" 1326145256Sjkoshy#define P6_KW_EDGE "edge" 1327145256Sjkoshy#define P6_KW_INV "inv" 1328145256Sjkoshy#define P6_KW_OS "os" 1329145256Sjkoshy#define P6_KW_UMASK "umask" 1330145256Sjkoshy#define P6_KW_USR "usr" 1331145256Sjkoshy 1332145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1333145256Sjkoshy PMCMASK(m, 0x01), 1334145256Sjkoshy PMCMASK(e, 0x02), 1335145256Sjkoshy PMCMASK(s, 0x04), 1336145256Sjkoshy PMCMASK(i, 0x08), 1337145256Sjkoshy NULLMASK 1338145256Sjkoshy}; 1339145256Sjkoshy 1340145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1341145256Sjkoshy PMCMASK(m, 0x01), 1342145256Sjkoshy PMCMASK(e, 0x02), 1343145256Sjkoshy PMCMASK(s, 0x04), 1344145256Sjkoshy PMCMASK(i, 0x08), 1345145256Sjkoshy PMCMASK(nonhw, 0x00), 1346145256Sjkoshy PMCMASK(hw, 0x10), 1347145256Sjkoshy PMCMASK(both, 0x30), 1348145256Sjkoshy NULLMASK 1349145256Sjkoshy}; 1350145256Sjkoshy 1351145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1352145256Sjkoshy PMCMASK(nonhw, 0x00), 1353145256Sjkoshy PMCMASK(hw, 0x10), 1354145256Sjkoshy PMCMASK(both, 0x30), 1355145256Sjkoshy NULLMASK 1356145256Sjkoshy}; 1357145256Sjkoshy 1358145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1359145256Sjkoshy PMCMASK(self, 0x00), 1360145256Sjkoshy PMCMASK(any, 0x20), 1361145256Sjkoshy NULLMASK 1362145256Sjkoshy}; 1363145256Sjkoshy 1364145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1365145256Sjkoshy PMCMASK(nta, 0x00), 1366145256Sjkoshy PMCMASK(t1, 0x01), 1367145256Sjkoshy PMCMASK(t2, 0x02), 1368145256Sjkoshy PMCMASK(wos, 0x03), 1369145256Sjkoshy NULLMASK 1370145256Sjkoshy}; 1371145256Sjkoshy 1372145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1373145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1374145256Sjkoshy PMCMASK(scalar, 0x01), 1375145256Sjkoshy NULLMASK 1376145256Sjkoshy}; 1377145256Sjkoshy 1378145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1379145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1380145256Sjkoshy PMCMASK(packed-shift, 0x02), 1381145256Sjkoshy PMCMASK(pack, 0x04), 1382145256Sjkoshy PMCMASK(unpack, 0x08), 1383145256Sjkoshy PMCMASK(packed-logical, 0x10), 1384145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1385145256Sjkoshy NULLMASK 1386145256Sjkoshy}; 1387145256Sjkoshy 1388145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1389145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1390145256Sjkoshy PMCMASK(fptommx, 0x01), 1391145256Sjkoshy NULLMASK 1392145256Sjkoshy}; 1393145256Sjkoshy 1394145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1395145256Sjkoshy PMCMASK(es, 0x01), 1396145256Sjkoshy PMCMASK(ds, 0x02), 1397145256Sjkoshy PMCMASK(fs, 0x04), 1398145256Sjkoshy PMCMASK(gs, 0x08), 1399145256Sjkoshy NULLMASK 1400145256Sjkoshy}; 1401145256Sjkoshy 1402145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1403145256Sjkoshy PMCMASK(all, 0x00), 1404145256Sjkoshy PMCMASK(freq, 0x02), 1405145256Sjkoshy NULLMASK 1406145256Sjkoshy}; 1407145256Sjkoshy 1408145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1409145256Sjkoshy PMCMASK(all, 0x00), 1410145256Sjkoshy PMCMASK(loadop, 0x01), 1411145256Sjkoshy PMCMASK(stdsta, 0x02), 1412145256Sjkoshy NULLMASK 1413145256Sjkoshy}; 1414145256Sjkoshy 1415145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1416145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1417145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1418145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1419145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1420145256Sjkoshy NULLMASK 1421145256Sjkoshy}; 1422145256Sjkoshy 1423145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1424145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1425145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1426145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1427145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1428145256Sjkoshy NULLMASK 1429145256Sjkoshy}; 1430145256Sjkoshy 1431145256Sjkoshy/* P6 event parser */ 1432145256Sjkoshystatic int 1433145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1434145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1435145256Sjkoshy{ 1436145256Sjkoshy char *e, *p, *q; 1437145256Sjkoshy uint32_t evmask; 1438145256Sjkoshy int count, n; 1439145256Sjkoshy const struct pmc_masks *pm, *pmask; 1440145256Sjkoshy 1441145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1442147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1443145256Sjkoshy 1444145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1445145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1446145256Sjkoshy return -1; 1447145256Sjkoshy return 0; 1448145256Sjkoshy } 1449145256Sjkoshy 1450145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1451145256Sjkoshy evmask = 0; 1452145256Sjkoshy 1453145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1454145256Sjkoshy 1455145256Sjkoshy switch(pe) { 1456145256Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1457145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1458145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1459145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1460145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1461145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1462145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1463145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1464145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1465145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1466145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1467145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1468145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1469145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1470145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1471145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1472145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1473145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1474145256Sjkoshy P6MASKSET(any); break; 1475145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1476145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1477145256Sjkoshy P6MASKSET(ekp); break; 1478145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1479145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1480145256Sjkoshy P6MASKSET(pps); break; 1481145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 1482145256Sjkoshy P6MASKSET(mite); break; 1483145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1484145256Sjkoshy P6MASKSET(fmt); break; 1485145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 1486145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 1487145256Sjkoshy P6MASKSET(sr); break; 1488145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1489145256Sjkoshy P6MASKSET(eet); break; 1490145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1491145256Sjkoshy P6MASKSET(efur); break; 1492145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1493145256Sjkoshy P6MASKSET(essir); break; 1494145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1495145256Sjkoshy P6MASKSET(esscir); break; 1496145256Sjkoshy default: 1497145256Sjkoshy pmask = NULL; 1498145256Sjkoshy break; 1499145256Sjkoshy } 1500145256Sjkoshy 1501145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 1502145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 1503145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 1504145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 1505145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 1506145256Sjkoshy P6MASKSET(mesihw); 1507145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 1508145256Sjkoshy P6MASKSET(hw); 1509145256Sjkoshy } 1510145256Sjkoshy 1511145256Sjkoshy /* Parse additional modifiers if present */ 1512145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1513145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 1514145256Sjkoshy q = strchr(p, '='); 1515145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1516145256Sjkoshy return -1; 1517145256Sjkoshy count = strtol(q, &e, 0); 1518145256Sjkoshy if (e == q || *e != '\0') 1519145256Sjkoshy return -1; 1520145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1521147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1522147191Sjkoshy P6_EVSEL_TO_CMASK(count); 1523145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 1524145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1525145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 1526145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1527145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 1528145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1529145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 1530145256Sjkoshy evmask = 0; 1531145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1532145256Sjkoshy return -1; 1533145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 1534145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 1535145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 1536145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 1537145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 1538145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 1539145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 1540145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 1541145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 1542145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 1543145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 1544145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 1545145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 1546145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 1547145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 1548145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 1549145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 1550145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 1551145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 1552145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 1553145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 1554145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 1555145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 1556145256Sjkoshy && (n > 1)) 1557145256Sjkoshy return -1; /* only one mask keyword allowed */ 1558145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1559145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 1560145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1561145256Sjkoshy } else 1562145256Sjkoshy return -1; 1563145256Sjkoshy } 1564145256Sjkoshy 1565145256Sjkoshy /* post processing */ 1566145256Sjkoshy switch (pe) { 1567145256Sjkoshy 1568145256Sjkoshy /* 1569145256Sjkoshy * The following events default to an evmask of 0 1570145256Sjkoshy */ 1571145256Sjkoshy 1572145256Sjkoshy /* default => 'self' */ 1573145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1574145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1575145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1576145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1577145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1578145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1579145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1580145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1581145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1582145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1583145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1584145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1585145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1586145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1587145256Sjkoshy 1588145256Sjkoshy /* default => 'nta' */ 1589145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1590145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1591145256Sjkoshy 1592145256Sjkoshy /* default => 'packed and scalar' */ 1593145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1594145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1595145256Sjkoshy 1596145256Sjkoshy /* default => 'mmx to fp transitions' */ 1597145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1598145256Sjkoshy 1599145256Sjkoshy /* default => 'SSE Packed Single' */ 1600145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1601145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1602145256Sjkoshy 1603145256Sjkoshy /* default => 'all fused micro-ops' */ 1604145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1605145256Sjkoshy 1606145256Sjkoshy /* default => 'all transitions' */ 1607145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1608145256Sjkoshy break; 1609145256Sjkoshy 1610145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 1611145256Sjkoshy evmask = 0x0F; /* only value allowed */ 1612145256Sjkoshy break; 1613145256Sjkoshy 1614145256Sjkoshy default: 1615145256Sjkoshy 1616145256Sjkoshy /* 1617145256Sjkoshy * For all other events, set the default event mask 1618145256Sjkoshy * to a logical OR of all the allowed event mask bits. 1619145256Sjkoshy */ 1620145256Sjkoshy 1621145256Sjkoshy if (evmask == 0 && pmask) { 1622145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1623145256Sjkoshy evmask |= pm->pm_value; 1624145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1625145256Sjkoshy } 1626145256Sjkoshy 1627145256Sjkoshy break; 1628145256Sjkoshy } 1629145256Sjkoshy 1630145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1631147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1632147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 1633145256Sjkoshy 1634145256Sjkoshy return 0; 1635145256Sjkoshy} 1636145256Sjkoshy 1637147191Sjkoshy#endif 1638147191Sjkoshy 1639145256Sjkoshy/* 1640147191Sjkoshy * API entry points 1641145256Sjkoshy */ 1642145256Sjkoshy 1643145256Sjkoshy 1644147191Sjkoshyint 1645147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 1646147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 1647145256Sjkoshy{ 1648147191Sjkoshy int retval; 1649147191Sjkoshy enum pmc_event pe; 1650147191Sjkoshy char *r, *spec_copy; 1651147191Sjkoshy const char *ctrname; 1652147191Sjkoshy const struct pmc_event_alias *p; 1653147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 1654145256Sjkoshy 1655147191Sjkoshy spec_copy = NULL; 1656147191Sjkoshy retval = -1; 1657145256Sjkoshy 1658147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 1659147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 1660147191Sjkoshy errno = EINVAL; 1661147191Sjkoshy goto out; 1662147191Sjkoshy } 1663145256Sjkoshy 1664147191Sjkoshy /* replace an event alias with the canonical event specifier */ 1665147191Sjkoshy if (pmc_mdep_event_aliases) 1666147191Sjkoshy for (p = pmc_mdep_event_aliases; p->pm_alias; p++) 1667147191Sjkoshy if (!strcmp(ctrspec, p->pm_alias)) { 1668147191Sjkoshy spec_copy = strdup(p->pm_spec); 1669147191Sjkoshy break; 1670147191Sjkoshy } 1671145256Sjkoshy 1672147191Sjkoshy if (spec_copy == NULL) 1673147191Sjkoshy spec_copy = strdup(ctrspec); 1674145256Sjkoshy 1675147191Sjkoshy r = spec_copy; 1676147191Sjkoshy ctrname = strsep(&r, ","); 1677145256Sjkoshy 1678147191Sjkoshy /* look for the given counter name */ 1679145256Sjkoshy 1680147191Sjkoshy for (pe = PMC_EVENT_FIRST; pe < (PMC_EVENT_LAST+1); pe++) 1681147191Sjkoshy if (!strcmp(ctrname, pmc_event_table[pe].pm_ev_name)) 1682147191Sjkoshy break; 1683145256Sjkoshy 1684147191Sjkoshy if (pe > PMC_EVENT_LAST) { 1685147191Sjkoshy errno = EINVAL; 1686147191Sjkoshy goto out; 1687147191Sjkoshy } 1688145256Sjkoshy 1689147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 1690147191Sjkoshy pmc_config.pm_ev = pmc_event_table[pe].pm_ev_code; 1691147191Sjkoshy pmc_config.pm_class = pmc_event_table[pe].pm_ev_class; 1692147191Sjkoshy pmc_config.pm_cpu = cpu; 1693147191Sjkoshy pmc_config.pm_mode = mode; 1694147191Sjkoshy pmc_config.pm_flags = flags; 1695145256Sjkoshy 1696147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 1697147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 1698145256Sjkoshy 1699147191Sjkoshy if (pmc_mdep_allocate_pmc(pe, r, &pmc_config) < 0) { 1700147191Sjkoshy errno = EINVAL; 1701147191Sjkoshy goto out; 1702147191Sjkoshy } 1703145256Sjkoshy 1704147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 1705147191Sjkoshy goto out; 1706145256Sjkoshy 1707147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 1708145256Sjkoshy 1709147191Sjkoshy retval = 0; 1710145256Sjkoshy 1711147191Sjkoshy out: 1712147191Sjkoshy if (spec_copy) 1713147191Sjkoshy free(spec_copy); 1714145256Sjkoshy 1715147191Sjkoshy return retval; 1716147191Sjkoshy} 1717145256Sjkoshy 1718147191Sjkoshyint 1719147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 1720147191Sjkoshy{ 1721147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 1722145256Sjkoshy 1723147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 1724147191Sjkoshy pmc_attach_args.pm_pid = pid; 1725145256Sjkoshy 1726147191Sjkoshy return PMC_CALL(PMCATTACH, &pmc_attach_args); 1727147191Sjkoshy} 1728145256Sjkoshy 1729147191Sjkoshyint 1730147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 1731147191Sjkoshy{ 1732147191Sjkoshy unsigned int i; 1733147191Sjkoshy enum pmc_class cl; 1734145256Sjkoshy 1735147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 1736147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 1737147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 1738147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 1739147191Sjkoshy return 0; 1740147191Sjkoshy } 1741147191Sjkoshy return EINVAL; 1742147191Sjkoshy} 1743145256Sjkoshy 1744147191Sjkoshyint 1745147191Sjkoshypmc_configure_logfile(int fd) 1746147191Sjkoshy{ 1747147191Sjkoshy struct pmc_op_configurelog cla; 1748145256Sjkoshy 1749147191Sjkoshy cla.pm_logfd = fd; 1750147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 1751147191Sjkoshy return -1; 1752147191Sjkoshy return 0; 1753147191Sjkoshy} 1754145256Sjkoshy 1755147191Sjkoshyint 1756147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 1757147191Sjkoshy{ 1758147191Sjkoshy if (pmc_syscall == -1) { 1759147191Sjkoshy errno = ENXIO; 1760147191Sjkoshy return -1; 1761147191Sjkoshy } 1762145256Sjkoshy 1763147219Sjkoshy *pci = &cpu_info; 1764147191Sjkoshy return 0; 1765147191Sjkoshy} 1766145256Sjkoshy 1767147191Sjkoshyint 1768147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 1769147191Sjkoshy{ 1770147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 1771145256Sjkoshy 1772147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 1773147191Sjkoshy pmc_detach_args.pm_pid = pid; 1774147191Sjkoshy 1775147191Sjkoshy return PMC_CALL(PMCDETACH, &pmc_detach_args); 1776147191Sjkoshy} 1777147191Sjkoshy 1778147191Sjkoshyint 1779147191Sjkoshypmc_disable(int cpu, int pmc) 1780145256Sjkoshy{ 1781147191Sjkoshy struct pmc_op_pmcadmin ssa; 1782145256Sjkoshy 1783147191Sjkoshy ssa.pm_cpu = cpu; 1784147191Sjkoshy ssa.pm_pmc = pmc; 1785147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 1786147191Sjkoshy return PMC_CALL(PMCADMIN, &ssa); 1787147191Sjkoshy} 1788145256Sjkoshy 1789147191Sjkoshyint 1790147191Sjkoshypmc_enable(int cpu, int pmc) 1791147191Sjkoshy{ 1792147191Sjkoshy struct pmc_op_pmcadmin ssa; 1793145256Sjkoshy 1794147191Sjkoshy ssa.pm_cpu = cpu; 1795147191Sjkoshy ssa.pm_pmc = pmc; 1796147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 1797147191Sjkoshy return PMC_CALL(PMCADMIN, &ssa); 1798147191Sjkoshy} 1799145256Sjkoshy 1800147191Sjkoshy/* 1801147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 1802147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 1803147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 1804147191Sjkoshy * the number of event name pointers returned. 1805147191Sjkoshy * 1806147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 1807147191Sjkoshy * is responsible for freeing this space when done. 1808147191Sjkoshy */ 1809145256Sjkoshy 1810147191Sjkoshyint 1811147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 1812147191Sjkoshy int *nevents) 1813147191Sjkoshy{ 1814147191Sjkoshy int count; 1815147191Sjkoshy const char **names; 1816147191Sjkoshy const struct pmc_event_descr *ev; 1817147191Sjkoshy 1818147191Sjkoshy switch (cl) 1819147191Sjkoshy { 1820147191Sjkoshy case PMC_CLASS_TSC: 1821147191Sjkoshy ev = &pmc_event_table[PMC_EV_TSC_TSC]; 1822147191Sjkoshy count = 1; 1823145256Sjkoshy break; 1824147191Sjkoshy case PMC_CLASS_K7: 1825147191Sjkoshy ev = &pmc_event_table[PMC_EV_K7_FIRST]; 1826147191Sjkoshy count = PMC_EV_K7_LAST - PMC_EV_K7_FIRST + 1; 1827145256Sjkoshy break; 1828147191Sjkoshy case PMC_CLASS_K8: 1829147191Sjkoshy ev = &pmc_event_table[PMC_EV_K8_FIRST]; 1830147191Sjkoshy count = PMC_EV_K8_LAST - PMC_EV_K8_FIRST + 1; 1831145256Sjkoshy break; 1832147191Sjkoshy case PMC_CLASS_P5: 1833147191Sjkoshy ev = &pmc_event_table[PMC_EV_P5_FIRST]; 1834147191Sjkoshy count = PMC_EV_P5_LAST - PMC_EV_P5_FIRST + 1; 1835145256Sjkoshy break; 1836147191Sjkoshy case PMC_CLASS_P6: 1837147191Sjkoshy ev = &pmc_event_table[PMC_EV_P6_FIRST]; 1838147191Sjkoshy count = PMC_EV_P6_LAST - PMC_EV_P6_FIRST + 1; 1839145256Sjkoshy break; 1840147191Sjkoshy case PMC_CLASS_P4: 1841147191Sjkoshy ev = &pmc_event_table[PMC_EV_P4_FIRST]; 1842147191Sjkoshy count = PMC_EV_P4_LAST - PMC_EV_P4_FIRST + 1; 1843145256Sjkoshy break; 1844145256Sjkoshy default: 1845147191Sjkoshy errno = EINVAL; 1846147191Sjkoshy return -1; 1847145256Sjkoshy } 1848145256Sjkoshy 1849147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 1850147191Sjkoshy return -1; 1851145256Sjkoshy 1852147191Sjkoshy *eventnames = names; 1853147191Sjkoshy *nevents = count; 1854145256Sjkoshy 1855147191Sjkoshy for (;count--; ev++, names++) 1856147191Sjkoshy *names = ev->pm_ev_name; 1857147191Sjkoshy return 0; 1858147191Sjkoshy} 1859145256Sjkoshy 1860147191Sjkoshyint 1861147191Sjkoshypmc_flush_logfile(void) 1862147191Sjkoshy{ 1863147191Sjkoshy return PMC_CALL(FLUSHLOG,0); 1864147191Sjkoshy} 1865145256Sjkoshy 1866147191Sjkoshyint 1867147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 1868147191Sjkoshy{ 1869147191Sjkoshy struct pmc_op_getdriverstats gms; 1870145256Sjkoshy 1871147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 1872147191Sjkoshy return -1; 1873145256Sjkoshy 1874147191Sjkoshy /* copy out fields in the current userland<->library interface */ 1875147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 1876147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 1877147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 1878147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 1879147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 1880147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 1881147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 1882147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 1883145256Sjkoshy 1884147191Sjkoshy return 0; 1885147191Sjkoshy} 1886145256Sjkoshy 1887147191Sjkoshyint 1888147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 1889147191Sjkoshy{ 1890147191Sjkoshy struct pmc_op_getmsr gm; 1891147191Sjkoshy 1892147191Sjkoshy gm.pm_pmcid = pmc; 1893147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 1894147191Sjkoshy return -1; 1895147191Sjkoshy *msr = gm.pm_msr; 1896145256Sjkoshy return 0; 1897145256Sjkoshy} 1898145256Sjkoshy 1899145256Sjkoshyint 1900145256Sjkoshypmc_init(void) 1901145256Sjkoshy{ 1902145256Sjkoshy int error, pmc_mod_id; 1903147219Sjkoshy unsigned int n; 1904145256Sjkoshy uint32_t abi_version; 1905145256Sjkoshy struct module_stat pmc_modstat; 1906147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 1907145256Sjkoshy 1908145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 1909145256Sjkoshy return 0; 1910145256Sjkoshy 1911145256Sjkoshy /* retrieve the system call number from the KLD */ 1912145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 1913145256Sjkoshy return -1; 1914145256Sjkoshy 1915145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 1916145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 1917145256Sjkoshy return -1; 1918145256Sjkoshy 1919145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 1920145256Sjkoshy 1921147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 1922147191Sjkoshy abi_version = PMC_VERSION; 1923145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 1924145256Sjkoshy return (pmc_syscall = -1); 1925145256Sjkoshy 1926147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 1927147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 1928145256Sjkoshy errno = EPROGMISMATCH; 1929145256Sjkoshy return (pmc_syscall = -1); 1930145256Sjkoshy } 1931145256Sjkoshy 1932147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 1933145256Sjkoshy return (pmc_syscall = -1); 1934145256Sjkoshy 1935147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 1936147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 1937147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 1938147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 1939147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 1940147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 1941147219Sjkoshy 1942145256Sjkoshy /* set parser pointer */ 1943145256Sjkoshy switch (cpu_info.pm_cputype) { 1944145340Smarcel#if defined(__i386__) 1945145256Sjkoshy case PMC_CPU_AMD_K7: 1946145256Sjkoshy pmc_mdep_event_aliases = k7_aliases; 1947145256Sjkoshy pmc_mdep_allocate_pmc = k7_allocate_pmc; 1948145256Sjkoshy break; 1949145256Sjkoshy case PMC_CPU_INTEL_P5: 1950145256Sjkoshy pmc_mdep_event_aliases = p5_aliases; 1951145256Sjkoshy pmc_mdep_allocate_pmc = p5_allocate_pmc; 1952145256Sjkoshy break; 1953145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 1954145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 1955145256Sjkoshy case PMC_CPU_INTEL_PIII: 1956145256Sjkoshy case PMC_CPU_INTEL_PM: 1957145256Sjkoshy pmc_mdep_event_aliases = p6_aliases; 1958145256Sjkoshy pmc_mdep_allocate_pmc = p6_allocate_pmc; 1959145256Sjkoshy break; 1960147759Sjkoshy#endif 1961147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1962145256Sjkoshy case PMC_CPU_INTEL_PIV: 1963145256Sjkoshy pmc_mdep_event_aliases = p4_aliases; 1964145256Sjkoshy pmc_mdep_allocate_pmc = p4_allocate_pmc; 1965145256Sjkoshy break; 1966145256Sjkoshy case PMC_CPU_AMD_K8: 1967145256Sjkoshy pmc_mdep_event_aliases = k8_aliases; 1968145256Sjkoshy pmc_mdep_allocate_pmc = k8_allocate_pmc; 1969145256Sjkoshy break; 1970145256Sjkoshy#endif 1971145256Sjkoshy 1972145256Sjkoshy default: 1973145256Sjkoshy /* 1974145256Sjkoshy * Some kind of CPU this version of the library knows nothing 1975145256Sjkoshy * about. This shouldn't happen since the abi version check 1976145256Sjkoshy * should have caught this. 1977145256Sjkoshy */ 1978145256Sjkoshy errno = ENXIO; 1979145256Sjkoshy return (pmc_syscall = -1); 1980145256Sjkoshy } 1981145256Sjkoshy 1982145256Sjkoshy return 0; 1983145256Sjkoshy} 1984145256Sjkoshy 1985147191Sjkoshyconst char * 1986147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 1987145256Sjkoshy{ 1988147191Sjkoshy int i; 1989145256Sjkoshy 1990147191Sjkoshy /* 1991147191Sjkoshy * 'cap' should have a single bit set and should be in 1992147191Sjkoshy * range. 1993147191Sjkoshy */ 1994145256Sjkoshy 1995147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 1996147191Sjkoshy cap > PMC_CAP_LAST) { 1997145256Sjkoshy errno = EINVAL; 1998147191Sjkoshy return NULL; 1999145256Sjkoshy } 2000145256Sjkoshy 2001147191Sjkoshy i = ffs(cap); 2002145256Sjkoshy 2003147191Sjkoshy return pmc_capability_names[i - 1]; 2004147191Sjkoshy} 2005145256Sjkoshy 2006147191Sjkoshyconst char * 2007147191Sjkoshypmc_name_of_class(enum pmc_class pc) 2008147191Sjkoshy{ 2009147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 2010147191Sjkoshy pc <= PMC_CLASS_LAST) 2011147191Sjkoshy return pmc_class_names[pc]; 2012145256Sjkoshy 2013147191Sjkoshy errno = EINVAL; 2014147191Sjkoshy return NULL; 2015147191Sjkoshy} 2016145256Sjkoshy 2017147191Sjkoshyconst char * 2018147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2019147191Sjkoshy{ 2020147191Sjkoshy if ((int) cp >= PMC_CPU_FIRST && 2021147191Sjkoshy cp <= PMC_CPU_LAST) 2022147191Sjkoshy return pmc_cputype_names[cp]; 2023147191Sjkoshy errno = EINVAL; 2024147191Sjkoshy return NULL; 2025147191Sjkoshy} 2026145256Sjkoshy 2027147191Sjkoshyconst char * 2028147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2029147191Sjkoshy{ 2030147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2031147191Sjkoshy pd <= PMC_DISP_LAST) 2032147191Sjkoshy return pmc_disposition_names[pd]; 2033145256Sjkoshy 2034147191Sjkoshy errno = EINVAL; 2035147191Sjkoshy return NULL; 2036147191Sjkoshy} 2037145256Sjkoshy 2038147191Sjkoshyconst char * 2039147191Sjkoshypmc_name_of_event(enum pmc_event pe) 2040147191Sjkoshy{ 2041147191Sjkoshy if ((int) pe >= PMC_EVENT_FIRST && 2042147191Sjkoshy pe <= PMC_EVENT_LAST) 2043147191Sjkoshy return pmc_event_table[pe].pm_ev_name; 2044145256Sjkoshy 2045147191Sjkoshy errno = EINVAL; 2046147191Sjkoshy return NULL; 2047147191Sjkoshy} 2048145256Sjkoshy 2049147191Sjkoshyconst char * 2050147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 2051147191Sjkoshy{ 2052147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 2053147191Sjkoshy pm <= PMC_MODE_LAST) 2054147191Sjkoshy return pmc_mode_names[pm]; 2055145256Sjkoshy 2056147191Sjkoshy errno = EINVAL; 2057147191Sjkoshy return NULL; 2058147191Sjkoshy} 2059145256Sjkoshy 2060147191Sjkoshyconst char * 2061147191Sjkoshypmc_name_of_state(enum pmc_state ps) 2062147191Sjkoshy{ 2063147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 2064147191Sjkoshy ps <= PMC_STATE_LAST) 2065147191Sjkoshy return pmc_state_names[ps]; 2066145256Sjkoshy 2067147191Sjkoshy errno = EINVAL; 2068147191Sjkoshy return NULL; 2069145256Sjkoshy} 2070145256Sjkoshy 2071145256Sjkoshyint 2072147191Sjkoshypmc_ncpu(void) 2073145256Sjkoshy{ 2074147191Sjkoshy if (pmc_syscall == -1) { 2075147191Sjkoshy errno = ENXIO; 2076147191Sjkoshy return -1; 2077147191Sjkoshy } 2078145256Sjkoshy 2079147191Sjkoshy return cpu_info.pm_ncpu; 2080145256Sjkoshy} 2081145256Sjkoshy 2082145256Sjkoshyint 2083147191Sjkoshypmc_npmc(int cpu) 2084145256Sjkoshy{ 2085147191Sjkoshy if (pmc_syscall == -1) { 2086147191Sjkoshy errno = ENXIO; 2087147191Sjkoshy return -1; 2088147191Sjkoshy } 2089145256Sjkoshy 2090147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 2091147191Sjkoshy errno = EINVAL; 2092147191Sjkoshy return -1; 2093147191Sjkoshy } 2094145256Sjkoshy 2095147191Sjkoshy return cpu_info.pm_npmc; 2096145256Sjkoshy} 2097145256Sjkoshy 2098145256Sjkoshyint 2099147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 2100145256Sjkoshy{ 2101147191Sjkoshy int nbytes, npmc; 2102147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 2103145256Sjkoshy 2104147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 2105147191Sjkoshy return -1; 2106145256Sjkoshy 2107147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 2108147191Sjkoshy npmc * sizeof(struct pmc_info); 2109145256Sjkoshy 2110147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 2111147191Sjkoshy return -1; 2112145256Sjkoshy 2113147191Sjkoshy pmci->pm_cpu = cpu; 2114145256Sjkoshy 2115147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 2116147191Sjkoshy free(pmci); 2117147191Sjkoshy return -1; 2118147191Sjkoshy } 2119145256Sjkoshy 2120147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 2121147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 2122147191Sjkoshy 2123147191Sjkoshy return 0; 2124145256Sjkoshy} 2125145256Sjkoshy 2126145256Sjkoshyint 2127145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 2128145256Sjkoshy{ 2129145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 2130145256Sjkoshy 2131145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 2132145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 2133145256Sjkoshy pmc_read_op.pm_value = -1; 2134145256Sjkoshy 2135145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 2136145256Sjkoshy return -1; 2137145256Sjkoshy 2138145256Sjkoshy *value = pmc_read_op.pm_value; 2139145256Sjkoshy 2140145256Sjkoshy return 0; 2141145256Sjkoshy} 2142145256Sjkoshy 2143145256Sjkoshyint 2144147191Sjkoshypmc_release(pmc_id_t pmc) 2145145256Sjkoshy{ 2146147191Sjkoshy struct pmc_op_simple pmc_release_args; 2147145256Sjkoshy 2148147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 2149145256Sjkoshy 2150147191Sjkoshy return PMC_CALL(PMCRELEASE, &pmc_release_args); 2151145256Sjkoshy} 2152145256Sjkoshy 2153145256Sjkoshyint 2154145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 2155145256Sjkoshy{ 2156145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 2157145256Sjkoshy 2158145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 2159145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 2160145256Sjkoshy pmc_rw_op.pm_value = newvalue; 2161145256Sjkoshy 2162145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 2163145256Sjkoshy return -1; 2164145256Sjkoshy 2165145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 2166145256Sjkoshy 2167145256Sjkoshy return 0; 2168145256Sjkoshy} 2169145256Sjkoshy 2170145256Sjkoshyint 2171145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 2172145256Sjkoshy{ 2173145256Sjkoshy struct pmc_op_pmcsetcount sc; 2174145256Sjkoshy 2175145256Sjkoshy sc.pm_pmcid = pmc; 2176145256Sjkoshy sc.pm_count = value; 2177145256Sjkoshy 2178145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 2179145256Sjkoshy return -1; 2180145256Sjkoshy 2181145256Sjkoshy return 0; 2182145256Sjkoshy 2183145256Sjkoshy} 2184145256Sjkoshy 2185145256Sjkoshyint 2186147191Sjkoshypmc_start(pmc_id_t pmc) 2187145256Sjkoshy{ 2188147191Sjkoshy struct pmc_op_simple pmc_start_args; 2189145256Sjkoshy 2190147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 2191147191Sjkoshy return PMC_CALL(PMCSTART, &pmc_start_args); 2192145256Sjkoshy} 2193145256Sjkoshy 2194145256Sjkoshyint 2195147191Sjkoshypmc_stop(pmc_id_t pmc) 2196145256Sjkoshy{ 2197147191Sjkoshy struct pmc_op_simple pmc_stop_args; 2198145256Sjkoshy 2199147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 2200147191Sjkoshy return PMC_CALL(PMCSTOP, &pmc_stop_args); 2201145256Sjkoshy} 2202145256Sjkoshy 2203145256Sjkoshyint 2204145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 2205145774Sjkoshy{ 2206145774Sjkoshy unsigned int i; 2207145774Sjkoshy enum pmc_class cl; 2208145774Sjkoshy 2209145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2210145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2211145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2212145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 2213145774Sjkoshy return 0; 2214145774Sjkoshy } 2215145774Sjkoshy return EINVAL; 2216145774Sjkoshy} 2217145774Sjkoshy 2218145774Sjkoshyint 2219147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 2220145774Sjkoshy{ 2221147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 2222145774Sjkoshy 2223147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 2224147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 2225147191Sjkoshy pmc_write_op.pm_value = value; 2226145774Sjkoshy 2227147191Sjkoshy return PMC_CALL(PMCRW, &pmc_write_op); 2228145256Sjkoshy} 2229145256Sjkoshy 2230145256Sjkoshyint 2231147191Sjkoshypmc_writelog(uint32_t userdata) 2232145256Sjkoshy{ 2233147191Sjkoshy struct pmc_op_writelog wl; 2234145256Sjkoshy 2235147191Sjkoshy wl.pm_userdata = userdata; 2236147191Sjkoshy return PMC_CALL(WRITELOG, &wl); 2237145256Sjkoshy} 2238