libpmc.c revision 177107
1145256Sjkoshy/*- 2177107Sjkoshy * Copyright (c) 2003-2008 Joseph Koshy 3145256Sjkoshy * All rights reserved. 4145256Sjkoshy * 5145256Sjkoshy * Redistribution and use in source and binary forms, with or without 6145256Sjkoshy * modification, are permitted provided that the following conditions 7145256Sjkoshy * are met: 8145256Sjkoshy * 1. Redistributions of source code must retain the above copyright 9145256Sjkoshy * notice, this list of conditions and the following disclaimer. 10145256Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11145256Sjkoshy * notice, this list of conditions and the following disclaimer in the 12145256Sjkoshy * documentation and/or other materials provided with the distribution. 13145256Sjkoshy * 14145256Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15145256Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16145256Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17145256Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18145256Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19145256Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20145256Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21145256Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22145256Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23145256Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24145256Sjkoshy * SUCH DAMAGE. 25145256Sjkoshy */ 26145256Sjkoshy 27145256Sjkoshy#include <sys/cdefs.h> 28145256Sjkoshy__FBSDID("$FreeBSD: head/lib/libpmc/libpmc.c 177107 2008-03-12 15:51:32Z 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 */ 72145256Sjkoshystruct pmc_event_alias { 73145256Sjkoshy const char *pm_alias; 74145256Sjkoshy const char *pm_spec; 75145256Sjkoshy}; 76145256Sjkoshy 77145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases; 78145256Sjkoshy 79145256Sjkoshy/* 80145256Sjkoshy * The pmc_event_descr table maps symbolic names known to the user 81145256Sjkoshy * to integer codes used by the PMC KLD. 82145256Sjkoshy */ 83145256Sjkoshystruct pmc_event_descr { 84145256Sjkoshy const char *pm_ev_name; 85145256Sjkoshy enum pmc_event pm_ev_code; 86145256Sjkoshy enum pmc_class pm_ev_class; 87145256Sjkoshy}; 88145256Sjkoshy 89145256Sjkoshystatic const struct pmc_event_descr 90145256Sjkoshypmc_event_table[] = 91145256Sjkoshy{ 92145256Sjkoshy#undef __PMC_EV 93145256Sjkoshy#define __PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C }, 94145256Sjkoshy __PMC_EVENTS() 95145256Sjkoshy}; 96145256Sjkoshy 97145256Sjkoshy/* 98145256Sjkoshy * Mapping tables, mapping enumeration values to human readable 99145256Sjkoshy * strings. 100145256Sjkoshy */ 101145256Sjkoshy 102145256Sjkoshystatic const char * pmc_capability_names[] = { 103145256Sjkoshy#undef __PMC_CAP 104145256Sjkoshy#define __PMC_CAP(N,V,D) #N , 105145256Sjkoshy __PMC_CAPS() 106145256Sjkoshy}; 107145256Sjkoshy 108145256Sjkoshystatic const char * pmc_class_names[] = { 109145256Sjkoshy#undef __PMC_CLASS 110145256Sjkoshy#define __PMC_CLASS(C) #C , 111145256Sjkoshy __PMC_CLASSES() 112145256Sjkoshy}; 113145256Sjkoshy 114145256Sjkoshystatic const char * pmc_cputype_names[] = { 115145256Sjkoshy#undef __PMC_CPU 116145256Sjkoshy#define __PMC_CPU(S, D) #S , 117145256Sjkoshy __PMC_CPUS() 118145256Sjkoshy}; 119145256Sjkoshy 120145256Sjkoshystatic const char * pmc_disposition_names[] = { 121145256Sjkoshy#undef __PMC_DISP 122145256Sjkoshy#define __PMC_DISP(D) #D , 123145256Sjkoshy __PMC_DISPOSITIONS() 124145256Sjkoshy}; 125145256Sjkoshy 126145256Sjkoshystatic const char * pmc_mode_names[] = { 127145256Sjkoshy#undef __PMC_MODE 128145256Sjkoshy#define __PMC_MODE(M,N) #M , 129145256Sjkoshy __PMC_MODES() 130145256Sjkoshy}; 131145256Sjkoshy 132145256Sjkoshystatic const char * pmc_state_names[] = { 133145256Sjkoshy#undef __PMC_STATE 134145256Sjkoshy#define __PMC_STATE(S) #S , 135145256Sjkoshy __PMC_STATES() 136145256Sjkoshy}; 137145256Sjkoshy 138145256Sjkoshystatic int pmc_syscall = -1; /* filled in by pmc_init() */ 139145256Sjkoshy 140147219Sjkoshystatic struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */ 141145256Sjkoshy 142147219Sjkoshy 143145256Sjkoshy/* Architecture dependent event parsing */ 144145256Sjkoshystatic int (*pmc_mdep_allocate_pmc)(enum pmc_event _pe, char *_ctrspec, 145145256Sjkoshy struct pmc_op_pmcallocate *_pmc_config); 146145256Sjkoshy 147145256Sjkoshy/* Event masks for events */ 148145256Sjkoshystruct pmc_masks { 149145256Sjkoshy const char *pm_name; 150145256Sjkoshy const uint32_t pm_value; 151145256Sjkoshy}; 152145256Sjkoshy#define PMCMASK(N,V) { .pm_name = #N, .pm_value = (V) } 153145256Sjkoshy#define NULLMASK PMCMASK(NULL,0) 154145256Sjkoshy 155147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 156145256Sjkoshystatic int 157145256Sjkoshypmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask) 158145256Sjkoshy{ 159145256Sjkoshy const struct pmc_masks *pm; 160145256Sjkoshy char *q, *r; 161145256Sjkoshy int c; 162145256Sjkoshy 163145256Sjkoshy if (pmask == NULL) /* no mask keywords */ 164174406Sjkoshy return (-1); 165145256Sjkoshy q = strchr(p, '='); /* skip '=' */ 166145256Sjkoshy if (*++q == '\0') /* no more data */ 167174406Sjkoshy return (-1); 168145256Sjkoshy c = 0; /* count of mask keywords seen */ 169145256Sjkoshy while ((r = strsep(&q, "+")) != NULL) { 170145256Sjkoshy for (pm = pmask; pm->pm_name && strcmp(r, pm->pm_name); pm++) 171145256Sjkoshy ; 172145256Sjkoshy if (pm->pm_name == NULL) /* not found */ 173174406Sjkoshy return (-1); 174145256Sjkoshy *evmask |= pm->pm_value; 175145256Sjkoshy c++; 176145256Sjkoshy } 177174406Sjkoshy return (c); 178145256Sjkoshy} 179145340Smarcel#endif 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 185145340Smarcel#if defined(__i386__) 186145256Sjkoshy 187145256Sjkoshy/* 188145256Sjkoshy * AMD K7 (Athlon) CPUs. 189145256Sjkoshy */ 190145256Sjkoshy 191145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = { 192145351Sjkoshy EV_ALIAS("branches", "k7-retired-branches"), 193145351Sjkoshy EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), 194145351Sjkoshy EV_ALIAS("cycles", "tsc"), 195145351Sjkoshy EV_ALIAS("dc-misses", "k7-dc-misses,mask=moesi"), 196145351Sjkoshy EV_ALIAS("ic-misses", "k7-ic-misses"), 197145351Sjkoshy EV_ALIAS("instructions", "k7-retired-instructions"), 198145351Sjkoshy EV_ALIAS("interrupts", "k7-hardware-interrupts"), 199145351Sjkoshy EV_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 217147191Sjkoshy pmc_config->pm_md.pm_amd.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') 223174406Sjkoshy return (-1); 224174406Sjkoshy 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; 231147191Sjkoshy unitmask = AMD_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 '=' */ 241174406Sjkoshy return (-1); 242145256Sjkoshy 243145256Sjkoshy count = strtol(q, &e, 0); 244145256Sjkoshy if (e == q || *e != '\0') 245174406Sjkoshy return (-1); 246145256Sjkoshy 247145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 248147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 249147191Sjkoshy AMD_PMC_TO_COUNTER(count); 250145256Sjkoshy 251145256Sjkoshy } else if (KWMATCH(p, K7_KW_EDGE)) { 252145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 253145256Sjkoshy } else if (KWMATCH(p, K7_KW_INV)) { 254145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 255145256Sjkoshy } else if (KWMATCH(p, K7_KW_OS)) { 256145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 257145256Sjkoshy } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { 258145256Sjkoshy if (has_unitmask == 0) 259174406Sjkoshy return (-1); 260145256Sjkoshy unitmask = 0; 261145256Sjkoshy q = strchr(p, '='); 262145256Sjkoshy if (*++q == '\0') /* skip '=' */ 263174406Sjkoshy return (-1); 264145256Sjkoshy 265145256Sjkoshy while ((c = tolower(*q++)) != 0) 266145256Sjkoshy if (c == 'm') 267147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_M; 268145256Sjkoshy else if (c == 'o') 269147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_O; 270145256Sjkoshy else if (c == 'e') 271147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_E; 272145256Sjkoshy else if (c == 's') 273147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_S; 274145256Sjkoshy else if (c == 'i') 275147191Sjkoshy unitmask |= AMD_PMC_UNITMASK_I; 276145256Sjkoshy else if (c == '+') 277145256Sjkoshy continue; 278145256Sjkoshy else 279174406Sjkoshy return (-1); 280145256Sjkoshy 281145256Sjkoshy if (unitmask == 0) 282174406Sjkoshy return (-1); 283145256Sjkoshy 284145256Sjkoshy } else if (KWMATCH(p, K7_KW_USR)) { 285145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 286145256Sjkoshy } else 287174406Sjkoshy return (-1); 288145256Sjkoshy } 289145256Sjkoshy 290145256Sjkoshy if (has_unitmask) { 291145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 292147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 293147191Sjkoshy AMD_PMC_TO_UNITMASK(unitmask); 294145256Sjkoshy } 295145256Sjkoshy 296174406Sjkoshy return (0); 297145256Sjkoshy 298145256Sjkoshy} 299145256Sjkoshy 300147191Sjkoshy#endif 301147191Sjkoshy 302147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 303147191Sjkoshy 304145256Sjkoshy/* 305147191Sjkoshy * AMD K8 PMCs. 306147191Sjkoshy * 307147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of 308147191Sjkoshy * events. 309147191Sjkoshy */ 310147191Sjkoshy 311147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = { 312147191Sjkoshy EV_ALIAS("branches", "k8-fr-retired-taken-branches"), 313147191Sjkoshy EV_ALIAS("branch-mispredicts", 314147191Sjkoshy "k8-fr-retired-taken-branches-mispredicted"), 315147191Sjkoshy EV_ALIAS("cycles", "tsc"), 316147191Sjkoshy EV_ALIAS("dc-misses", "k8-dc-miss"), 317147191Sjkoshy EV_ALIAS("ic-misses", "k8-ic-miss"), 318147191Sjkoshy EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), 319147191Sjkoshy EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), 320155998Sjkoshy EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), 321147191Sjkoshy EV_ALIAS(NULL, NULL) 322147191Sjkoshy}; 323147191Sjkoshy 324147191Sjkoshy#define __K8MASK(N,V) PMCMASK(N,(1 << (V))) 325147191Sjkoshy 326147191Sjkoshy/* 327147191Sjkoshy * Parsing tables 328147191Sjkoshy */ 329147191Sjkoshy 330147191Sjkoshy/* fp dispatched fpu ops */ 331147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = { 332147191Sjkoshy __K8MASK(add-pipe-excluding-junk-ops, 0), 333147191Sjkoshy __K8MASK(multiply-pipe-excluding-junk-ops, 1), 334147191Sjkoshy __K8MASK(store-pipe-excluding-junk-ops, 2), 335147191Sjkoshy __K8MASK(add-pipe-junk-ops, 3), 336147191Sjkoshy __K8MASK(multiply-pipe-junk-ops, 4), 337147191Sjkoshy __K8MASK(store-pipe-junk-ops, 5), 338147191Sjkoshy NULLMASK 339147191Sjkoshy}; 340147191Sjkoshy 341147191Sjkoshy/* ls segment register loads */ 342147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = { 343147191Sjkoshy __K8MASK(es, 0), 344147191Sjkoshy __K8MASK(cs, 1), 345147191Sjkoshy __K8MASK(ss, 2), 346147191Sjkoshy __K8MASK(ds, 3), 347147191Sjkoshy __K8MASK(fs, 4), 348147191Sjkoshy __K8MASK(gs, 5), 349147191Sjkoshy __K8MASK(hs, 6), 350147191Sjkoshy NULLMASK 351147191Sjkoshy}; 352147191Sjkoshy 353147191Sjkoshy/* ls locked operation */ 354147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = { 355147191Sjkoshy __K8MASK(locked-instructions, 0), 356147191Sjkoshy __K8MASK(cycles-in-request, 1), 357147191Sjkoshy __K8MASK(cycles-to-complete, 2), 358147191Sjkoshy NULLMASK 359147191Sjkoshy}; 360147191Sjkoshy 361147191Sjkoshy/* dc refill from {l2,system} and dc copyback */ 362147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = { 363147191Sjkoshy __K8MASK(invalid, 0), 364147191Sjkoshy __K8MASK(shared, 1), 365147191Sjkoshy __K8MASK(exclusive, 2), 366147191Sjkoshy __K8MASK(owner, 3), 367147191Sjkoshy __K8MASK(modified, 4), 368147191Sjkoshy NULLMASK 369147191Sjkoshy}; 370147191Sjkoshy 371147191Sjkoshy/* dc one bit ecc error */ 372147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = { 373147191Sjkoshy __K8MASK(scrubber, 0), 374147191Sjkoshy __K8MASK(piggyback, 1), 375147191Sjkoshy NULLMASK 376147191Sjkoshy}; 377147191Sjkoshy 378147191Sjkoshy/* dc dispatched prefetch instructions */ 379147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = { 380147191Sjkoshy __K8MASK(load, 0), 381147191Sjkoshy __K8MASK(store, 1), 382147191Sjkoshy __K8MASK(nta, 2), 383147191Sjkoshy NULLMASK 384147191Sjkoshy}; 385147191Sjkoshy 386147191Sjkoshy/* dc dcache accesses by locks */ 387147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = { 388147191Sjkoshy __K8MASK(accesses, 0), 389147191Sjkoshy __K8MASK(misses, 1), 390147191Sjkoshy NULLMASK 391147191Sjkoshy}; 392147191Sjkoshy 393147191Sjkoshy/* bu internal l2 request */ 394147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = { 395147191Sjkoshy __K8MASK(ic-fill, 0), 396147191Sjkoshy __K8MASK(dc-fill, 1), 397147191Sjkoshy __K8MASK(tlb-reload, 2), 398147191Sjkoshy __K8MASK(tag-snoop, 3), 399147191Sjkoshy __K8MASK(cancelled, 4), 400147191Sjkoshy NULLMASK 401147191Sjkoshy}; 402147191Sjkoshy 403147191Sjkoshy/* bu fill request l2 miss */ 404147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = { 405147191Sjkoshy __K8MASK(ic-fill, 0), 406147191Sjkoshy __K8MASK(dc-fill, 1), 407147191Sjkoshy __K8MASK(tlb-reload, 2), 408147191Sjkoshy NULLMASK 409147191Sjkoshy}; 410147191Sjkoshy 411147191Sjkoshy/* bu fill into l2 */ 412147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = { 413147191Sjkoshy __K8MASK(dirty-l2-victim, 0), 414147191Sjkoshy __K8MASK(victim-from-l2, 1), 415147191Sjkoshy NULLMASK 416147191Sjkoshy}; 417147191Sjkoshy 418147191Sjkoshy/* fr retired fpu instructions */ 419147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = { 420147191Sjkoshy __K8MASK(x87, 0), 421147191Sjkoshy __K8MASK(mmx-3dnow, 1), 422147191Sjkoshy __K8MASK(packed-sse-sse2, 2), 423147191Sjkoshy __K8MASK(scalar-sse-sse2, 3), 424147191Sjkoshy NULLMASK 425147191Sjkoshy}; 426147191Sjkoshy 427147191Sjkoshy/* fr retired fastpath double op instructions */ 428147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = { 429147191Sjkoshy __K8MASK(low-op-pos-0, 0), 430147191Sjkoshy __K8MASK(low-op-pos-1, 1), 431147191Sjkoshy __K8MASK(low-op-pos-2, 2), 432147191Sjkoshy NULLMASK 433147191Sjkoshy}; 434147191Sjkoshy 435147191Sjkoshy/* fr fpu exceptions */ 436147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = { 437147191Sjkoshy __K8MASK(x87-reclass-microfaults, 0), 438147191Sjkoshy __K8MASK(sse-retype-microfaults, 1), 439147191Sjkoshy __K8MASK(sse-reclass-microfaults, 2), 440147191Sjkoshy __K8MASK(sse-and-x87-microtraps, 3), 441147191Sjkoshy NULLMASK 442147191Sjkoshy}; 443147191Sjkoshy 444147191Sjkoshy/* nb memory controller page access event */ 445147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = { 446147191Sjkoshy __K8MASK(page-hit, 0), 447147191Sjkoshy __K8MASK(page-miss, 1), 448147191Sjkoshy __K8MASK(page-conflict, 2), 449147191Sjkoshy NULLMASK 450147191Sjkoshy}; 451147191Sjkoshy 452147191Sjkoshy/* nb memory controller turnaround */ 453147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = { 454147191Sjkoshy __K8MASK(dimm-turnaround, 0), 455147191Sjkoshy __K8MASK(read-to-write-turnaround, 1), 456147191Sjkoshy __K8MASK(write-to-read-turnaround, 2), 457147191Sjkoshy NULLMASK 458147191Sjkoshy}; 459147191Sjkoshy 460147191Sjkoshy/* nb memory controller bypass saturation */ 461147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = { 462147191Sjkoshy __K8MASK(memory-controller-hi-pri-bypass, 0), 463147191Sjkoshy __K8MASK(memory-controller-lo-pri-bypass, 1), 464147191Sjkoshy __K8MASK(dram-controller-interface-bypass, 2), 465147191Sjkoshy __K8MASK(dram-controller-queue-bypass, 3), 466147191Sjkoshy NULLMASK 467147191Sjkoshy}; 468147191Sjkoshy 469147191Sjkoshy/* nb sized commands */ 470147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = { 471147191Sjkoshy __K8MASK(nonpostwrszbyte, 0), 472147191Sjkoshy __K8MASK(nonpostwrszdword, 1), 473147191Sjkoshy __K8MASK(postwrszbyte, 2), 474147191Sjkoshy __K8MASK(postwrszdword, 3), 475147191Sjkoshy __K8MASK(rdszbyte, 4), 476147191Sjkoshy __K8MASK(rdszdword, 5), 477147191Sjkoshy __K8MASK(rdmodwr, 6), 478147191Sjkoshy NULLMASK 479147191Sjkoshy}; 480147191Sjkoshy 481147191Sjkoshy/* nb probe result */ 482147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = { 483147191Sjkoshy __K8MASK(probe-miss, 0), 484147191Sjkoshy __K8MASK(probe-hit, 1), 485147191Sjkoshy __K8MASK(probe-hit-dirty-no-memory-cancel, 2), 486147191Sjkoshy __K8MASK(probe-hit-dirty-with-memory-cancel, 3), 487147191Sjkoshy NULLMASK 488147191Sjkoshy}; 489147191Sjkoshy 490147191Sjkoshy/* nb hypertransport bus bandwidth */ 491147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ 492147191Sjkoshy __K8MASK(command, 0), 493147191Sjkoshy __K8MASK(data, 1), 494147191Sjkoshy __K8MASK(buffer-release, 2), 495147191Sjkoshy __K8MASK(nop, 3), 496147191Sjkoshy NULLMASK 497147191Sjkoshy}; 498147191Sjkoshy 499147191Sjkoshy#undef __K8MASK 500147191Sjkoshy 501147191Sjkoshy#define K8_KW_COUNT "count" 502147191Sjkoshy#define K8_KW_EDGE "edge" 503147191Sjkoshy#define K8_KW_INV "inv" 504147191Sjkoshy#define K8_KW_MASK "mask" 505147191Sjkoshy#define K8_KW_OS "os" 506147191Sjkoshy#define K8_KW_USR "usr" 507147191Sjkoshy 508147191Sjkoshystatic int 509147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec, 510147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 511147191Sjkoshy{ 512147191Sjkoshy char *e, *p, *q; 513147191Sjkoshy int n; 514147191Sjkoshy uint32_t count, evmask; 515147191Sjkoshy const struct pmc_masks *pm, *pmask; 516147191Sjkoshy 517147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 518147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 0; 519147191Sjkoshy 520147191Sjkoshy if (pe == PMC_EV_TSC_TSC) { 521147191Sjkoshy /* TSC events must be unqualified. */ 522147191Sjkoshy if (ctrspec && *ctrspec != '\0') 523174406Sjkoshy return (-1); 524174406Sjkoshy return (0); 525147191Sjkoshy } 526147191Sjkoshy 527147191Sjkoshy pmask = NULL; 528147191Sjkoshy evmask = 0; 529147191Sjkoshy 530147191Sjkoshy#define __K8SETMASK(M) pmask = k8_mask_##M 531147191Sjkoshy 532147191Sjkoshy /* setup parsing tables */ 533147191Sjkoshy switch (pe) { 534147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 535147191Sjkoshy __K8SETMASK(fdfo); 536147191Sjkoshy break; 537147191Sjkoshy case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD: 538147191Sjkoshy __K8SETMASK(lsrl); 539147191Sjkoshy break; 540147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 541147191Sjkoshy __K8SETMASK(llo); 542147191Sjkoshy break; 543147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_L2: 544147191Sjkoshy case PMC_EV_K8_DC_REFILL_FROM_SYSTEM: 545147191Sjkoshy case PMC_EV_K8_DC_COPYBACK: 546147191Sjkoshy __K8SETMASK(dc); 547147191Sjkoshy break; 548147191Sjkoshy case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR: 549147191Sjkoshy __K8SETMASK(dobee); 550147191Sjkoshy break; 551147191Sjkoshy case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS: 552147191Sjkoshy __K8SETMASK(ddpi); 553147191Sjkoshy break; 554147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 555147191Sjkoshy __K8SETMASK(dabl); 556147191Sjkoshy break; 557147191Sjkoshy case PMC_EV_K8_BU_INTERNAL_L2_REQUEST: 558147191Sjkoshy __K8SETMASK(bilr); 559147191Sjkoshy break; 560147191Sjkoshy case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS: 561147191Sjkoshy __K8SETMASK(bfrlm); 562147191Sjkoshy break; 563147191Sjkoshy case PMC_EV_K8_BU_FILL_INTO_L2: 564147191Sjkoshy __K8SETMASK(bfil); 565147191Sjkoshy break; 566147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 567147191Sjkoshy __K8SETMASK(frfi); 568147191Sjkoshy break; 569147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 570147191Sjkoshy __K8SETMASK(frfdoi); 571147191Sjkoshy break; 572147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 573147191Sjkoshy __K8SETMASK(ffe); 574147191Sjkoshy break; 575147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT: 576147191Sjkoshy __K8SETMASK(nmcpae); 577147191Sjkoshy break; 578147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND: 579147191Sjkoshy __K8SETMASK(nmct); 580147191Sjkoshy break; 581147191Sjkoshy case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION: 582147191Sjkoshy __K8SETMASK(nmcbs); 583147191Sjkoshy break; 584147191Sjkoshy case PMC_EV_K8_NB_SIZED_COMMANDS: 585147191Sjkoshy __K8SETMASK(nsc); 586147191Sjkoshy break; 587147191Sjkoshy case PMC_EV_K8_NB_PROBE_RESULT: 588147191Sjkoshy __K8SETMASK(npr); 589147191Sjkoshy break; 590147191Sjkoshy case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH: 591147191Sjkoshy case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH: 592147191Sjkoshy case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH: 593147191Sjkoshy __K8SETMASK(nhbb); 594147191Sjkoshy break; 595147191Sjkoshy 596147191Sjkoshy default: 597147191Sjkoshy break; /* no options defined */ 598147191Sjkoshy } 599147191Sjkoshy 600147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 601147191Sjkoshy 602147191Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 603147191Sjkoshy if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { 604147191Sjkoshy q = strchr(p, '='); 605147191Sjkoshy if (*++q == '\0') /* skip '=' */ 606174406Sjkoshy return (-1); 607147191Sjkoshy 608147191Sjkoshy count = strtol(q, &e, 0); 609147191Sjkoshy if (e == q || *e != '\0') 610174406Sjkoshy return (-1); 611147191Sjkoshy 612147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 613147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config |= 614147191Sjkoshy AMD_PMC_TO_COUNTER(count); 615147191Sjkoshy 616147191Sjkoshy } else if (KWMATCH(p, K8_KW_EDGE)) { 617147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 618147191Sjkoshy } else if (KWMATCH(p, K8_KW_INV)) { 619147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 620147191Sjkoshy } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { 621147191Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 622174406Sjkoshy return (-1); 623147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 624147191Sjkoshy } else if (KWMATCH(p, K8_KW_OS)) { 625147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 626147191Sjkoshy } else if (KWMATCH(p, K8_KW_USR)) { 627147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 628147191Sjkoshy } else 629174406Sjkoshy return (-1); 630147191Sjkoshy } 631147191Sjkoshy 632147191Sjkoshy /* other post processing */ 633147191Sjkoshy switch (pe) { 634147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: 635147191Sjkoshy case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: 636147191Sjkoshy case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS: 637147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS: 638147191Sjkoshy case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS: 639147191Sjkoshy case PMC_EV_K8_FR_FPU_EXCEPTIONS: 640147191Sjkoshy /* XXX only available in rev B and later */ 641147191Sjkoshy break; 642147191Sjkoshy case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS: 643147191Sjkoshy /* XXX only available in rev C and later */ 644147191Sjkoshy break; 645147191Sjkoshy case PMC_EV_K8_LS_LOCKED_OPERATION: 646147191Sjkoshy /* XXX CPU Rev A,B evmask is to be zero */ 647147191Sjkoshy if (evmask & (evmask - 1)) /* > 1 bit set */ 648174406Sjkoshy return (-1); 649147191Sjkoshy if (evmask == 0) { 650147191Sjkoshy evmask = 0x01; /* Rev C and later: #instrs */ 651147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 652147191Sjkoshy } 653147191Sjkoshy break; 654147191Sjkoshy default: 655147191Sjkoshy if (evmask == 0 && pmask != NULL) { 656147191Sjkoshy for (pm = pmask; pm->pm_name; pm++) 657147191Sjkoshy evmask |= pm->pm_value; 658147191Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 659147191Sjkoshy } 660147191Sjkoshy } 661147191Sjkoshy 662147191Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 663147191Sjkoshy pmc_config->pm_md.pm_amd.pm_amd_config = 664147191Sjkoshy AMD_PMC_TO_UNITMASK(evmask); 665147191Sjkoshy 666174406Sjkoshy return (0); 667147191Sjkoshy} 668147191Sjkoshy 669147191Sjkoshy#endif 670147191Sjkoshy 671147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 672147191Sjkoshy 673147191Sjkoshy/* 674145256Sjkoshy * Intel P4 PMCs 675145256Sjkoshy */ 676145256Sjkoshy 677145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = { 678145351Sjkoshy EV_ALIAS("branches", "p4-branch-retired,mask=mmtp+mmtm"), 679145351Sjkoshy EV_ALIAS("branch-mispredicts", "p4-mispred-branch-retired"), 680145351Sjkoshy EV_ALIAS("cycles", "tsc"), 681145351Sjkoshy EV_ALIAS("instructions", 682145351Sjkoshy "p4-instr-retired,mask=nbogusntag+nbogustag"), 683155998Sjkoshy EV_ALIAS("unhalted-cycles", "p4-global-power-events"), 684145256Sjkoshy EV_ALIAS(NULL, NULL) 685145256Sjkoshy}; 686145256Sjkoshy 687145256Sjkoshy#define P4_KW_ACTIVE "active" 688145256Sjkoshy#define P4_KW_ACTIVE_ANY "any" 689145256Sjkoshy#define P4_KW_ACTIVE_BOTH "both" 690145256Sjkoshy#define P4_KW_ACTIVE_NONE "none" 691145256Sjkoshy#define P4_KW_ACTIVE_SINGLE "single" 692145256Sjkoshy#define P4_KW_BUSREQTYPE "busreqtype" 693145256Sjkoshy#define P4_KW_CASCADE "cascade" 694145256Sjkoshy#define P4_KW_EDGE "edge" 695145256Sjkoshy#define P4_KW_INV "complement" 696145256Sjkoshy#define P4_KW_OS "os" 697145256Sjkoshy#define P4_KW_MASK "mask" 698145256Sjkoshy#define P4_KW_PRECISE "precise" 699145256Sjkoshy#define P4_KW_TAG "tag" 700145256Sjkoshy#define P4_KW_THRESHOLD "threshold" 701145256Sjkoshy#define P4_KW_USR "usr" 702145256Sjkoshy 703145256Sjkoshy#define __P4MASK(N,V) PMCMASK(N, (1 << (V))) 704145256Sjkoshy 705145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */ 706145256Sjkoshy __P4MASK(dd, 0), 707145256Sjkoshy __P4MASK(db, 1), 708145256Sjkoshy __P4MASK(di, 2), 709145256Sjkoshy __P4MASK(bd, 3), 710145256Sjkoshy __P4MASK(bb, 4), 711145256Sjkoshy __P4MASK(bi, 5), 712145256Sjkoshy __P4MASK(id, 6), 713145256Sjkoshy __P4MASK(ib, 7), 714145256Sjkoshy NULLMASK 715145256Sjkoshy}; 716145256Sjkoshy 717145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */ 718145256Sjkoshy __P4MASK(tcmiss, 0), 719145256Sjkoshy NULLMASK, 720145256Sjkoshy}; 721145256Sjkoshy 722145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */ 723145256Sjkoshy __P4MASK(hit, 0), 724145256Sjkoshy __P4MASK(miss, 1), 725145256Sjkoshy __P4MASK(hit-uc, 2), 726145256Sjkoshy NULLMASK 727145256Sjkoshy}; 728145256Sjkoshy 729145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */ 730145256Sjkoshy __P4MASK(st-rb-full, 2), 731145256Sjkoshy __P4MASK(64k-conf, 3), 732145256Sjkoshy NULLMASK 733145256Sjkoshy}; 734145256Sjkoshy 735145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */ 736145256Sjkoshy __P4MASK(lsc, 0), 737145256Sjkoshy __P4MASK(ssc, 1), 738145256Sjkoshy NULLMASK 739145256Sjkoshy}; 740145256Sjkoshy 741145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */ 742145256Sjkoshy __P4MASK(split-ld, 1), 743145256Sjkoshy NULLMASK 744145256Sjkoshy}; 745145256Sjkoshy 746145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */ 747145256Sjkoshy __P4MASK(split-st, 1), 748145256Sjkoshy NULLMASK 749145256Sjkoshy}; 750145256Sjkoshy 751145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */ 752145256Sjkoshy __P4MASK(no-sta, 1), 753145256Sjkoshy __P4MASK(no-std, 3), 754145256Sjkoshy __P4MASK(partial-data, 4), 755145256Sjkoshy __P4MASK(unalgn-addr, 5), 756145256Sjkoshy NULLMASK 757145256Sjkoshy}; 758145256Sjkoshy 759145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */ 760145256Sjkoshy __P4MASK(dtmiss, 0), 761145256Sjkoshy __P4MASK(itmiss, 1), 762145256Sjkoshy NULLMASK 763145256Sjkoshy}; 764145256Sjkoshy 765145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */ 766145256Sjkoshy __P4MASK(rd-2ndl-hits, 0), 767145256Sjkoshy __P4MASK(rd-2ndl-hite, 1), 768145256Sjkoshy __P4MASK(rd-2ndl-hitm, 2), 769145256Sjkoshy __P4MASK(rd-3rdl-hits, 3), 770145256Sjkoshy __P4MASK(rd-3rdl-hite, 4), 771145256Sjkoshy __P4MASK(rd-3rdl-hitm, 5), 772145256Sjkoshy __P4MASK(rd-2ndl-miss, 8), 773145256Sjkoshy __P4MASK(rd-3rdl-miss, 9), 774145256Sjkoshy __P4MASK(wr-2ndl-miss, 10), 775145256Sjkoshy NULLMASK 776145256Sjkoshy}; 777145256Sjkoshy 778145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */ 779145256Sjkoshy __P4MASK(all-read, 5), 780145256Sjkoshy __P4MASK(all-write, 6), 781145256Sjkoshy __P4MASK(mem-uc, 7), 782145256Sjkoshy __P4MASK(mem-wc, 8), 783145256Sjkoshy __P4MASK(mem-wt, 9), 784145256Sjkoshy __P4MASK(mem-wp, 10), 785145256Sjkoshy __P4MASK(mem-wb, 11), 786145256Sjkoshy __P4MASK(own, 13), 787145256Sjkoshy __P4MASK(other, 14), 788145256Sjkoshy __P4MASK(prefetch, 15), 789145256Sjkoshy NULLMASK 790145256Sjkoshy}; 791145256Sjkoshy 792145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */ 793145256Sjkoshy __P4MASK(all-read, 5), 794145256Sjkoshy __P4MASK(all-write, 6), 795145256Sjkoshy __P4MASK(mem-uc, 7), 796145256Sjkoshy __P4MASK(mem-wc, 8), 797145256Sjkoshy __P4MASK(mem-wt, 9), 798145256Sjkoshy __P4MASK(mem-wp, 10), 799145256Sjkoshy __P4MASK(mem-wb, 11), 800145256Sjkoshy __P4MASK(own, 13), 801145256Sjkoshy __P4MASK(other, 14), 802145256Sjkoshy __P4MASK(prefetch, 15), 803145256Sjkoshy NULLMASK 804145256Sjkoshy}; 805145256Sjkoshy 806145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */ 807145256Sjkoshy __P4MASK(drdy-drv, 0), 808145256Sjkoshy __P4MASK(drdy-own, 1), 809145256Sjkoshy __P4MASK(drdy-other, 2), 810145256Sjkoshy __P4MASK(dbsy-drv, 3), 811145256Sjkoshy __P4MASK(dbsy-own, 4), 812145256Sjkoshy __P4MASK(dbsy-other, 5), 813145256Sjkoshy NULLMASK 814145256Sjkoshy}; 815145256Sjkoshy 816145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */ 817145256Sjkoshy __P4MASK(req-type0, 0), 818145256Sjkoshy __P4MASK(req-type1, 1), 819145256Sjkoshy __P4MASK(req-len0, 2), 820145256Sjkoshy __P4MASK(req-len1, 3), 821145256Sjkoshy __P4MASK(req-io-type, 5), 822145256Sjkoshy __P4MASK(req-lock-type, 6), 823145256Sjkoshy __P4MASK(req-cache-type, 7), 824145256Sjkoshy __P4MASK(req-split-type, 8), 825145256Sjkoshy __P4MASK(req-dem-type, 9), 826145256Sjkoshy __P4MASK(req-ord-type, 10), 827145256Sjkoshy __P4MASK(mem-type0, 11), 828145256Sjkoshy __P4MASK(mem-type1, 12), 829145256Sjkoshy __P4MASK(mem-type2, 13), 830145256Sjkoshy NULLMASK 831145256Sjkoshy}; 832145256Sjkoshy 833145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */ 834145256Sjkoshy __P4MASK(all, 15), 835145256Sjkoshy NULLMASK 836145256Sjkoshy}; 837145256Sjkoshy 838145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */ 839145256Sjkoshy __P4MASK(all, 15), 840145256Sjkoshy NULLMASK 841145256Sjkoshy}; 842145256Sjkoshy 843145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */ 844145256Sjkoshy __P4MASK(all, 15), 845145256Sjkoshy NULLMASK 846145256Sjkoshy}; 847145256Sjkoshy 848145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */ 849145256Sjkoshy __P4MASK(all, 15), 850145256Sjkoshy NULLMASK 851145256Sjkoshy}; 852145256Sjkoshy 853145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */ 854145256Sjkoshy __P4MASK(all, 15), 855145256Sjkoshy NULLMASK 856145256Sjkoshy}; 857145256Sjkoshy 858145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */ 859145256Sjkoshy __P4MASK(all, 15), 860145256Sjkoshy NULLMASK 861145256Sjkoshy}; 862145256Sjkoshy 863145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */ 864145256Sjkoshy __P4MASK(all, 15), 865145256Sjkoshy NULLMASK 866145256Sjkoshy}; 867145256Sjkoshy 868145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */ 869145256Sjkoshy __P4MASK(all, 15), 870145256Sjkoshy NULLMASK 871145256Sjkoshy}; 872145256Sjkoshy 873145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */ 874145256Sjkoshy __P4MASK(allp0, 3), 875145256Sjkoshy __P4MASK(allp2, 4), 876145256Sjkoshy NULLMASK 877145256Sjkoshy}; 878145256Sjkoshy 879145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */ 880145256Sjkoshy __P4MASK(running, 0), 881145256Sjkoshy NULLMASK 882145256Sjkoshy}; 883145256Sjkoshy 884145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */ 885145256Sjkoshy __P4MASK(cisc, 0), 886145256Sjkoshy NULLMASK 887145256Sjkoshy}; 888145256Sjkoshy 889145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */ 890145256Sjkoshy __P4MASK(from-tc-build, 0), 891145256Sjkoshy __P4MASK(from-tc-deliver, 1), 892145256Sjkoshy __P4MASK(from-rom, 2), 893145256Sjkoshy NULLMASK 894145256Sjkoshy}; 895145256Sjkoshy 896145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = { 897145351Sjkoshy /* retired mispred branch type */ 898145256Sjkoshy __P4MASK(conditional, 1), 899145256Sjkoshy __P4MASK(call, 2), 900145256Sjkoshy __P4MASK(return, 3), 901145256Sjkoshy __P4MASK(indirect, 4), 902145256Sjkoshy NULLMASK 903145256Sjkoshy}; 904145256Sjkoshy 905145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */ 906145256Sjkoshy __P4MASK(conditional, 1), 907145256Sjkoshy __P4MASK(call, 2), 908145256Sjkoshy __P4MASK(retired, 3), 909145256Sjkoshy __P4MASK(indirect, 4), 910145256Sjkoshy NULLMASK 911145256Sjkoshy}; 912145256Sjkoshy 913145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */ 914145256Sjkoshy __P4MASK(sbfull, 5), 915145256Sjkoshy NULLMASK 916145256Sjkoshy}; 917145256Sjkoshy 918145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */ 919145256Sjkoshy __P4MASK(wcb-evicts, 0), 920145256Sjkoshy __P4MASK(wcb-full-evict, 1), 921145256Sjkoshy NULLMASK 922145256Sjkoshy}; 923145256Sjkoshy 924145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */ 925145256Sjkoshy __P4MASK(nbogus, 0), 926145256Sjkoshy __P4MASK(bogus, 1), 927145256Sjkoshy NULLMASK 928145256Sjkoshy}; 929145256Sjkoshy 930145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */ 931145256Sjkoshy __P4MASK(nbogus0, 0), 932145256Sjkoshy __P4MASK(nbogus1, 1), 933145256Sjkoshy __P4MASK(nbogus2, 2), 934145256Sjkoshy __P4MASK(nbogus3, 3), 935145256Sjkoshy __P4MASK(bogus0, 4), 936145256Sjkoshy __P4MASK(bogus1, 5), 937145256Sjkoshy __P4MASK(bogus2, 6), 938145256Sjkoshy __P4MASK(bogus3, 7), 939145256Sjkoshy NULLMASK 940145256Sjkoshy}; 941145256Sjkoshy 942145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */ 943145256Sjkoshy __P4MASK(nbogus, 0), 944145256Sjkoshy __P4MASK(bogus, 1), 945145256Sjkoshy NULLMASK 946145256Sjkoshy}; 947145256Sjkoshy 948145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */ 949145256Sjkoshy __P4MASK(nbogusntag, 0), 950145256Sjkoshy __P4MASK(nbogustag, 1), 951145256Sjkoshy __P4MASK(bogusntag, 2), 952145256Sjkoshy __P4MASK(bogustag, 3), 953145256Sjkoshy NULLMASK 954145256Sjkoshy}; 955145256Sjkoshy 956145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */ 957145256Sjkoshy __P4MASK(nbogus, 0), 958145256Sjkoshy __P4MASK(bogus, 1), 959145256Sjkoshy NULLMASK 960145256Sjkoshy}; 961145256Sjkoshy 962145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */ 963145256Sjkoshy __P4MASK(tagloads, 1), 964145256Sjkoshy __P4MASK(tagstores, 2), 965145256Sjkoshy NULLMASK 966145256Sjkoshy}; 967145256Sjkoshy 968145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */ 969145256Sjkoshy __P4MASK(mmnp, 0), 970145256Sjkoshy __P4MASK(mmnm, 1), 971145256Sjkoshy __P4MASK(mmtp, 2), 972145256Sjkoshy __P4MASK(mmtm, 3), 973145256Sjkoshy NULLMASK 974145256Sjkoshy}; 975145256Sjkoshy 976145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */ 977145256Sjkoshy __P4MASK(nbogus, 0), 978145256Sjkoshy NULLMASK 979145256Sjkoshy}; 980145256Sjkoshy 981145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */ 982145256Sjkoshy __P4MASK(fpsu, 0), 983145256Sjkoshy __P4MASK(fpso, 1), 984145256Sjkoshy __P4MASK(poao, 2), 985145256Sjkoshy __P4MASK(poau, 3), 986145256Sjkoshy __P4MASK(prea, 4), 987145256Sjkoshy NULLMASK 988145256Sjkoshy}; 989145256Sjkoshy 990145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */ 991145256Sjkoshy __P4MASK(clear, 0), 992145256Sjkoshy __P4MASK(moclear, 2), 993145256Sjkoshy __P4MASK(smclear, 3), 994145256Sjkoshy NULLMASK 995145256Sjkoshy}; 996145256Sjkoshy 997145256Sjkoshy/* P4 event parser */ 998145256Sjkoshystatic int 999145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec, 1000145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1001145256Sjkoshy{ 1002145256Sjkoshy 1003145256Sjkoshy char *e, *p, *q; 1004145256Sjkoshy int count, has_tag, has_busreqtype, n; 1005145256Sjkoshy uint32_t evmask, cccractivemask; 1006145256Sjkoshy const struct pmc_masks *pm, *pmask; 1007145256Sjkoshy 1008145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1009147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = 1010147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; 1011145256Sjkoshy 1012145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1013145256Sjkoshy /* TSC must not be further qualified */ 1014145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1015174406Sjkoshy return (-1); 1016174406Sjkoshy return (0); 1017145256Sjkoshy } 1018145256Sjkoshy 1019145256Sjkoshy pmask = NULL; 1020145256Sjkoshy evmask = 0; 1021145256Sjkoshy cccractivemask = 0x3; 1022145256Sjkoshy has_tag = has_busreqtype = 0; 1023145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1024145256Sjkoshy 1025145256Sjkoshy#define __P4SETMASK(M) do { \ 1026145256Sjkoshy pmask = p4_mask_##M; \ 1027145256Sjkoshy} while (0) 1028145256Sjkoshy 1029145256Sjkoshy switch (pe) { 1030145256Sjkoshy case PMC_EV_P4_TC_DELIVER_MODE: 1031145256Sjkoshy __P4SETMASK(tcdm); 1032145256Sjkoshy break; 1033145256Sjkoshy case PMC_EV_P4_BPU_FETCH_REQUEST: 1034145256Sjkoshy __P4SETMASK(bfr); 1035145256Sjkoshy break; 1036145256Sjkoshy case PMC_EV_P4_ITLB_REFERENCE: 1037145256Sjkoshy __P4SETMASK(ir); 1038145256Sjkoshy break; 1039145256Sjkoshy case PMC_EV_P4_MEMORY_CANCEL: 1040145256Sjkoshy __P4SETMASK(memcan); 1041145256Sjkoshy break; 1042145256Sjkoshy case PMC_EV_P4_MEMORY_COMPLETE: 1043145256Sjkoshy __P4SETMASK(memcomp); 1044145256Sjkoshy break; 1045145256Sjkoshy case PMC_EV_P4_LOAD_PORT_REPLAY: 1046145256Sjkoshy __P4SETMASK(lpr); 1047145256Sjkoshy break; 1048145256Sjkoshy case PMC_EV_P4_STORE_PORT_REPLAY: 1049145256Sjkoshy __P4SETMASK(spr); 1050145256Sjkoshy break; 1051145256Sjkoshy case PMC_EV_P4_MOB_LOAD_REPLAY: 1052145256Sjkoshy __P4SETMASK(mlr); 1053145256Sjkoshy break; 1054145256Sjkoshy case PMC_EV_P4_PAGE_WALK_TYPE: 1055145256Sjkoshy __P4SETMASK(pwt); 1056145256Sjkoshy break; 1057145256Sjkoshy case PMC_EV_P4_BSQ_CACHE_REFERENCE: 1058145256Sjkoshy __P4SETMASK(bcr); 1059145256Sjkoshy break; 1060145256Sjkoshy case PMC_EV_P4_IOQ_ALLOCATION: 1061145256Sjkoshy __P4SETMASK(ia); 1062145256Sjkoshy has_busreqtype = 1; 1063145256Sjkoshy break; 1064145256Sjkoshy case PMC_EV_P4_IOQ_ACTIVE_ENTRIES: 1065145256Sjkoshy __P4SETMASK(iae); 1066145256Sjkoshy has_busreqtype = 1; 1067145256Sjkoshy break; 1068145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1069145256Sjkoshy __P4SETMASK(fda); 1070145256Sjkoshy break; 1071145256Sjkoshy case PMC_EV_P4_BSQ_ALLOCATION: 1072145256Sjkoshy __P4SETMASK(ba); 1073145256Sjkoshy break; 1074145256Sjkoshy case PMC_EV_P4_SSE_INPUT_ASSIST: 1075145256Sjkoshy __P4SETMASK(sia); 1076145256Sjkoshy break; 1077145256Sjkoshy case PMC_EV_P4_PACKED_SP_UOP: 1078145256Sjkoshy __P4SETMASK(psu); 1079145256Sjkoshy break; 1080145256Sjkoshy case PMC_EV_P4_PACKED_DP_UOP: 1081145256Sjkoshy __P4SETMASK(pdu); 1082145256Sjkoshy break; 1083145256Sjkoshy case PMC_EV_P4_SCALAR_SP_UOP: 1084145256Sjkoshy __P4SETMASK(ssu); 1085145256Sjkoshy break; 1086145256Sjkoshy case PMC_EV_P4_SCALAR_DP_UOP: 1087145256Sjkoshy __P4SETMASK(sdu); 1088145256Sjkoshy break; 1089145256Sjkoshy case PMC_EV_P4_64BIT_MMX_UOP: 1090145256Sjkoshy __P4SETMASK(64bmu); 1091145256Sjkoshy break; 1092145256Sjkoshy case PMC_EV_P4_128BIT_MMX_UOP: 1093145256Sjkoshy __P4SETMASK(128bmu); 1094145256Sjkoshy break; 1095145256Sjkoshy case PMC_EV_P4_X87_FP_UOP: 1096145256Sjkoshy __P4SETMASK(xfu); 1097145256Sjkoshy break; 1098145256Sjkoshy case PMC_EV_P4_X87_SIMD_MOVES_UOP: 1099145256Sjkoshy __P4SETMASK(xsmu); 1100145256Sjkoshy break; 1101145256Sjkoshy case PMC_EV_P4_GLOBAL_POWER_EVENTS: 1102145256Sjkoshy __P4SETMASK(gpe); 1103145256Sjkoshy break; 1104145256Sjkoshy case PMC_EV_P4_TC_MS_XFER: 1105145256Sjkoshy __P4SETMASK(tmx); 1106145256Sjkoshy break; 1107145256Sjkoshy case PMC_EV_P4_UOP_QUEUE_WRITES: 1108145256Sjkoshy __P4SETMASK(uqw); 1109145256Sjkoshy break; 1110145256Sjkoshy case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE: 1111145256Sjkoshy __P4SETMASK(rmbt); 1112145256Sjkoshy break; 1113145256Sjkoshy case PMC_EV_P4_RETIRED_BRANCH_TYPE: 1114145256Sjkoshy __P4SETMASK(rbt); 1115145256Sjkoshy break; 1116145256Sjkoshy case PMC_EV_P4_RESOURCE_STALL: 1117145256Sjkoshy __P4SETMASK(rs); 1118145256Sjkoshy break; 1119145256Sjkoshy case PMC_EV_P4_WC_BUFFER: 1120145256Sjkoshy __P4SETMASK(wb); 1121145256Sjkoshy break; 1122145256Sjkoshy case PMC_EV_P4_BSQ_ACTIVE_ENTRIES: 1123145256Sjkoshy case PMC_EV_P4_B2B_CYCLES: 1124145256Sjkoshy case PMC_EV_P4_BNR: 1125145256Sjkoshy case PMC_EV_P4_SNOOP: 1126145256Sjkoshy case PMC_EV_P4_RESPONSE: 1127145256Sjkoshy break; 1128145256Sjkoshy case PMC_EV_P4_FRONT_END_EVENT: 1129145256Sjkoshy __P4SETMASK(fee); 1130145256Sjkoshy break; 1131145256Sjkoshy case PMC_EV_P4_EXECUTION_EVENT: 1132145256Sjkoshy __P4SETMASK(ee); 1133145256Sjkoshy break; 1134145256Sjkoshy case PMC_EV_P4_REPLAY_EVENT: 1135145256Sjkoshy __P4SETMASK(re); 1136145256Sjkoshy break; 1137145256Sjkoshy case PMC_EV_P4_INSTR_RETIRED: 1138145256Sjkoshy __P4SETMASK(insret); 1139145256Sjkoshy break; 1140145256Sjkoshy case PMC_EV_P4_UOPS_RETIRED: 1141145256Sjkoshy __P4SETMASK(ur); 1142145256Sjkoshy break; 1143145256Sjkoshy case PMC_EV_P4_UOP_TYPE: 1144145256Sjkoshy __P4SETMASK(ut); 1145145256Sjkoshy break; 1146145256Sjkoshy case PMC_EV_P4_BRANCH_RETIRED: 1147145256Sjkoshy __P4SETMASK(br); 1148145256Sjkoshy break; 1149145256Sjkoshy case PMC_EV_P4_MISPRED_BRANCH_RETIRED: 1150145256Sjkoshy __P4SETMASK(mbr); 1151145256Sjkoshy break; 1152145256Sjkoshy case PMC_EV_P4_X87_ASSIST: 1153145256Sjkoshy __P4SETMASK(xa); 1154145256Sjkoshy break; 1155145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1156145256Sjkoshy __P4SETMASK(machclr); 1157145256Sjkoshy break; 1158145256Sjkoshy default: 1159174406Sjkoshy return (-1); 1160145256Sjkoshy } 1161145256Sjkoshy 1162145256Sjkoshy /* process additional flags */ 1163145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1164145256Sjkoshy if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { 1165145256Sjkoshy q = strchr(p, '='); 1166145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1167174406Sjkoshy return (-1); 1168145256Sjkoshy 1169145256Sjkoshy if (strcmp(q, P4_KW_ACTIVE_NONE) == 0) 1170145256Sjkoshy cccractivemask = 0x0; 1171145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_SINGLE) == 0) 1172145256Sjkoshy cccractivemask = 0x1; 1173145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_BOTH) == 0) 1174145256Sjkoshy cccractivemask = 0x2; 1175145256Sjkoshy else if (strcmp(q, P4_KW_ACTIVE_ANY) == 0) 1176145256Sjkoshy cccractivemask = 0x3; 1177145256Sjkoshy else 1178174406Sjkoshy return (-1); 1179145256Sjkoshy 1180145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { 1181145256Sjkoshy if (has_busreqtype == 0) 1182174406Sjkoshy return (-1); 1183145256Sjkoshy 1184145256Sjkoshy q = strchr(p, '='); 1185145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1186174406Sjkoshy return (-1); 1187145256Sjkoshy 1188145256Sjkoshy count = strtol(q, &e, 0); 1189145256Sjkoshy if (e == q || *e != '\0') 1190174406Sjkoshy return (-1); 1191145256Sjkoshy evmask = (evmask & ~0x1F) | (count & 0x1F); 1192145256Sjkoshy } else if (KWMATCH(p, P4_KW_CASCADE)) 1193145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_CASCADE; 1194145256Sjkoshy else if (KWMATCH(p, P4_KW_EDGE)) 1195145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1196145256Sjkoshy else if (KWMATCH(p, P4_KW_INV)) 1197145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1198145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { 1199145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1200174406Sjkoshy return (-1); 1201145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1202145256Sjkoshy } else if (KWMATCH(p, P4_KW_OS)) 1203145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1204145256Sjkoshy else if (KWMATCH(p, P4_KW_PRECISE)) 1205145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_PRECISE; 1206145256Sjkoshy else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { 1207145256Sjkoshy if (has_tag == 0) 1208174406Sjkoshy return (-1); 1209145256Sjkoshy 1210145256Sjkoshy q = strchr(p, '='); 1211145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1212174406Sjkoshy return (-1); 1213145256Sjkoshy 1214145256Sjkoshy count = strtol(q, &e, 0); 1215145256Sjkoshy if (e == q || *e != '\0') 1216174406Sjkoshy return (-1); 1217145256Sjkoshy 1218145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_TAGGING; 1219147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= 1220145256Sjkoshy P4_ESCR_TO_TAG_VALUE(count); 1221145256Sjkoshy } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { 1222145256Sjkoshy q = strchr(p, '='); 1223145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1224174406Sjkoshy return (-1); 1225145256Sjkoshy 1226145256Sjkoshy count = strtol(q, &e, 0); 1227145256Sjkoshy if (e == q || *e != '\0') 1228174406Sjkoshy return (-1); 1229145256Sjkoshy 1230145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1231147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= 1232147191Sjkoshy ~P4_CCCR_THRESHOLD_MASK; 1233147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1234147191Sjkoshy P4_CCCR_TO_THRESHOLD(count); 1235145256Sjkoshy } else if (KWMATCH(p, P4_KW_USR)) 1236145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1237145256Sjkoshy else 1238174406Sjkoshy return (-1); 1239145256Sjkoshy } 1240145256Sjkoshy 1241145256Sjkoshy /* other post processing */ 1242145256Sjkoshy if (pe == PMC_EV_P4_IOQ_ALLOCATION || 1243145256Sjkoshy pe == PMC_EV_P4_FSB_DATA_ACTIVITY || 1244145256Sjkoshy pe == PMC_EV_P4_BSQ_ALLOCATION) 1245145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1246145256Sjkoshy 1247145256Sjkoshy /* fill in thread activity mask */ 1248147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |= 1249145256Sjkoshy P4_CCCR_TO_ACTIVE_THREAD(cccractivemask); 1250145256Sjkoshy 1251145256Sjkoshy if (evmask) 1252145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1253145256Sjkoshy 1254145256Sjkoshy switch (pe) { 1255145256Sjkoshy case PMC_EV_P4_FSB_DATA_ACTIVITY: 1256145256Sjkoshy if ((evmask & 0x06) == 0x06 || 1257145256Sjkoshy (evmask & 0x18) == 0x18) 1258174406Sjkoshy return (-1); /* can't have own+other bits together */ 1259145256Sjkoshy if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ 1260145256Sjkoshy evmask = 0x1D; 1261145256Sjkoshy break; 1262145256Sjkoshy case PMC_EV_P4_MACHINE_CLEAR: 1263145256Sjkoshy /* only one bit is allowed to be set */ 1264145256Sjkoshy if ((evmask & (evmask - 1)) != 0) 1265174406Sjkoshy return (-1); 1266145256Sjkoshy if (evmask == 0) { 1267145256Sjkoshy evmask = 0x1; /* 'CLEAR' */ 1268145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1269145256Sjkoshy } 1270145256Sjkoshy break; 1271145256Sjkoshy default: 1272145256Sjkoshy if (evmask == 0 && pmask) { 1273145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1274145256Sjkoshy evmask |= pm->pm_value; 1275145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1276145256Sjkoshy } 1277145256Sjkoshy } 1278145256Sjkoshy 1279147191Sjkoshy pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 1280147191Sjkoshy P4_ESCR_TO_EVENT_MASK(evmask); 1281145256Sjkoshy 1282174406Sjkoshy return (0); 1283145256Sjkoshy} 1284145256Sjkoshy 1285147759Sjkoshy#endif 1286147759Sjkoshy 1287147759Sjkoshy#if defined(__i386__) 1288147759Sjkoshy 1289145256Sjkoshy/* 1290147191Sjkoshy * Pentium style PMCs 1291147191Sjkoshy */ 1292147191Sjkoshy 1293147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = { 1294147191Sjkoshy EV_ALIAS("cycles", "tsc"), 1295147191Sjkoshy EV_ALIAS(NULL, NULL) 1296147191Sjkoshy}; 1297147191Sjkoshy 1298147191Sjkoshystatic int 1299147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec, 1300147191Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1301147191Sjkoshy{ 1302174406Sjkoshy return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ 1303147191Sjkoshy} 1304147191Sjkoshy 1305147191Sjkoshy/* 1306145256Sjkoshy * Pentium Pro style PMCs. These PMCs are found in Pentium II, Pentium III, 1307145256Sjkoshy * and Pentium M CPUs. 1308145256Sjkoshy */ 1309145256Sjkoshy 1310145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = { 1311145351Sjkoshy EV_ALIAS("branches", "p6-br-inst-retired"), 1312145351Sjkoshy EV_ALIAS("branch-mispredicts", "p6-br-miss-pred-retired"), 1313145351Sjkoshy EV_ALIAS("cycles", "tsc"), 1314145351Sjkoshy EV_ALIAS("dc-misses", "p6-dcu-lines-in"), 1315168612Sjkoshy EV_ALIAS("ic-misses", "p6-ifu-fetch-miss"), 1316145351Sjkoshy EV_ALIAS("instructions", "p6-inst-retired"), 1317145351Sjkoshy EV_ALIAS("interrupts", "p6-hw-int-rx"), 1318155998Sjkoshy EV_ALIAS("unhalted-cycles", "p6-cpu-clk-unhalted"), 1319145351Sjkoshy EV_ALIAS(NULL, NULL) 1320145256Sjkoshy}; 1321145256Sjkoshy 1322145256Sjkoshy#define P6_KW_CMASK "cmask" 1323145256Sjkoshy#define P6_KW_EDGE "edge" 1324145256Sjkoshy#define P6_KW_INV "inv" 1325145256Sjkoshy#define P6_KW_OS "os" 1326145256Sjkoshy#define P6_KW_UMASK "umask" 1327145256Sjkoshy#define P6_KW_USR "usr" 1328145256Sjkoshy 1329145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = { 1330145256Sjkoshy PMCMASK(m, 0x01), 1331145256Sjkoshy PMCMASK(e, 0x02), 1332145256Sjkoshy PMCMASK(s, 0x04), 1333145256Sjkoshy PMCMASK(i, 0x08), 1334145256Sjkoshy NULLMASK 1335145256Sjkoshy}; 1336145256Sjkoshy 1337145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = { 1338145256Sjkoshy PMCMASK(m, 0x01), 1339145256Sjkoshy PMCMASK(e, 0x02), 1340145256Sjkoshy PMCMASK(s, 0x04), 1341145256Sjkoshy PMCMASK(i, 0x08), 1342145256Sjkoshy PMCMASK(nonhw, 0x00), 1343145256Sjkoshy PMCMASK(hw, 0x10), 1344145256Sjkoshy PMCMASK(both, 0x30), 1345145256Sjkoshy NULLMASK 1346145256Sjkoshy}; 1347145256Sjkoshy 1348145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = { 1349145256Sjkoshy PMCMASK(nonhw, 0x00), 1350145256Sjkoshy PMCMASK(hw, 0x10), 1351145256Sjkoshy PMCMASK(both, 0x30), 1352145256Sjkoshy NULLMASK 1353145256Sjkoshy}; 1354145256Sjkoshy 1355145256Sjkoshystatic struct pmc_masks p6_mask_any[] = { 1356145256Sjkoshy PMCMASK(self, 0x00), 1357145256Sjkoshy PMCMASK(any, 0x20), 1358145256Sjkoshy NULLMASK 1359145256Sjkoshy}; 1360145256Sjkoshy 1361145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = { 1362145256Sjkoshy PMCMASK(nta, 0x00), 1363145256Sjkoshy PMCMASK(t1, 0x01), 1364145256Sjkoshy PMCMASK(t2, 0x02), 1365145256Sjkoshy PMCMASK(wos, 0x03), 1366145256Sjkoshy NULLMASK 1367145256Sjkoshy}; 1368145256Sjkoshy 1369145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = { 1370145256Sjkoshy PMCMASK(packed-and-scalar, 0x00), 1371145256Sjkoshy PMCMASK(scalar, 0x01), 1372145256Sjkoshy NULLMASK 1373145256Sjkoshy}; 1374145256Sjkoshy 1375145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = { 1376145256Sjkoshy PMCMASK(packed-multiply, 0x01), 1377145256Sjkoshy PMCMASK(packed-shift, 0x02), 1378145256Sjkoshy PMCMASK(pack, 0x04), 1379145256Sjkoshy PMCMASK(unpack, 0x08), 1380145256Sjkoshy PMCMASK(packed-logical, 0x10), 1381145256Sjkoshy PMCMASK(packed-arithmetic, 0x20), 1382145256Sjkoshy NULLMASK 1383145256Sjkoshy}; 1384145256Sjkoshy 1385145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = { 1386145256Sjkoshy PMCMASK(mmxtofp, 0x00), 1387145256Sjkoshy PMCMASK(fptommx, 0x01), 1388145256Sjkoshy NULLMASK 1389145256Sjkoshy}; 1390145256Sjkoshy 1391145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = { 1392145256Sjkoshy PMCMASK(es, 0x01), 1393145256Sjkoshy PMCMASK(ds, 0x02), 1394145256Sjkoshy PMCMASK(fs, 0x04), 1395145256Sjkoshy PMCMASK(gs, 0x08), 1396145256Sjkoshy NULLMASK 1397145256Sjkoshy}; 1398145256Sjkoshy 1399145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = { 1400145256Sjkoshy PMCMASK(all, 0x00), 1401145256Sjkoshy PMCMASK(freq, 0x02), 1402145256Sjkoshy NULLMASK 1403145256Sjkoshy}; 1404145256Sjkoshy 1405145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = { 1406145256Sjkoshy PMCMASK(all, 0x00), 1407145256Sjkoshy PMCMASK(loadop, 0x01), 1408145256Sjkoshy PMCMASK(stdsta, 0x02), 1409145256Sjkoshy NULLMASK 1410145256Sjkoshy}; 1411145256Sjkoshy 1412145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = { 1413145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1414145256Sjkoshy PMCMASK(sse-packed-single-scalar-single, 0x01), 1415145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1416145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1417145256Sjkoshy NULLMASK 1418145256Sjkoshy}; 1419145256Sjkoshy 1420145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = { 1421145256Sjkoshy PMCMASK(sse-packed-single, 0x00), 1422145256Sjkoshy PMCMASK(sse-scalar-single, 0x01), 1423145256Sjkoshy PMCMASK(sse2-packed-double, 0x02), 1424145256Sjkoshy PMCMASK(sse2-scalar-double, 0x03), 1425145256Sjkoshy NULLMASK 1426145256Sjkoshy}; 1427145256Sjkoshy 1428145256Sjkoshy/* P6 event parser */ 1429145256Sjkoshystatic int 1430145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec, 1431145256Sjkoshy struct pmc_op_pmcallocate *pmc_config) 1432145256Sjkoshy{ 1433145256Sjkoshy char *e, *p, *q; 1434145256Sjkoshy uint32_t evmask; 1435145256Sjkoshy int count, n; 1436145256Sjkoshy const struct pmc_masks *pm, *pmask; 1437145256Sjkoshy 1438145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_READ; 1439147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; 1440145256Sjkoshy 1441145256Sjkoshy if (pe == PMC_EV_TSC_TSC) { 1442145256Sjkoshy if (ctrspec && *ctrspec != '\0') 1443174406Sjkoshy return (-1); 1444174406Sjkoshy return (0); 1445145256Sjkoshy } 1446145256Sjkoshy 1447145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_WRITE; 1448145256Sjkoshy evmask = 0; 1449145256Sjkoshy 1450145256Sjkoshy#define P6MASKSET(M) pmask = p6_mask_ ## M 1451145256Sjkoshy 1452145256Sjkoshy switch(pe) { 1453145256Sjkoshy case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; 1454145256Sjkoshy case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; 1455145256Sjkoshy case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; 1456145256Sjkoshy case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; 1457145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1458145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1459145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1460145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1461145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1462145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1463145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1464145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1465145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1466145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1467145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1468145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1469145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1470145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1471145256Sjkoshy P6MASKSET(any); break; 1472145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1473145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1474145256Sjkoshy P6MASKSET(ekp); break; 1475145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1476145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1477145256Sjkoshy P6MASKSET(pps); break; 1478145256Sjkoshy case PMC_EV_P6_MMX_INSTR_TYPE_EXEC: 1479145256Sjkoshy P6MASKSET(mite); break; 1480145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1481145256Sjkoshy P6MASKSET(fmt); break; 1482145256Sjkoshy case PMC_EV_P6_SEG_RENAME_STALLS: 1483145256Sjkoshy case PMC_EV_P6_SEG_REG_RENAMES: 1484145256Sjkoshy P6MASKSET(sr); break; 1485145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1486145256Sjkoshy P6MASKSET(eet); break; 1487145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1488145256Sjkoshy P6MASKSET(efur); break; 1489145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1490145256Sjkoshy P6MASKSET(essir); break; 1491145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1492145256Sjkoshy P6MASKSET(esscir); break; 1493145256Sjkoshy default: 1494145256Sjkoshy pmask = NULL; 1495145256Sjkoshy break; 1496145256Sjkoshy } 1497145256Sjkoshy 1498145256Sjkoshy /* Pentium M PMCs have a few events with different semantics */ 1499145256Sjkoshy if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) { 1500145256Sjkoshy if (pe == PMC_EV_P6_L2_LD || 1501145256Sjkoshy pe == PMC_EV_P6_L2_LINES_IN || 1502145256Sjkoshy pe == PMC_EV_P6_L2_LINES_OUT) 1503145256Sjkoshy P6MASKSET(mesihw); 1504145256Sjkoshy else if (pe == PMC_EV_P6_L2_M_LINES_OUTM) 1505145256Sjkoshy P6MASKSET(hw); 1506145256Sjkoshy } 1507145256Sjkoshy 1508145256Sjkoshy /* Parse additional modifiers if present */ 1509145256Sjkoshy while ((p = strsep(&ctrspec, ",")) != NULL) { 1510145256Sjkoshy if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { 1511145256Sjkoshy q = strchr(p, '='); 1512145256Sjkoshy if (*++q == '\0') /* skip '=' */ 1513174406Sjkoshy return (-1); 1514145256Sjkoshy count = strtol(q, &e, 0); 1515145256Sjkoshy if (e == q || *e != '\0') 1516174406Sjkoshy return (-1); 1517145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_THRESHOLD; 1518147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1519147191Sjkoshy P6_EVSEL_TO_CMASK(count); 1520145256Sjkoshy } else if (KWMATCH(p, P6_KW_EDGE)) { 1521145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_EDGE; 1522145256Sjkoshy } else if (KWMATCH(p, P6_KW_INV)) { 1523145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_INVERT; 1524145256Sjkoshy } else if (KWMATCH(p, P6_KW_OS)) { 1525145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_SYSTEM; 1526145256Sjkoshy } else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) { 1527145256Sjkoshy evmask = 0; 1528145256Sjkoshy if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) 1529174406Sjkoshy return (-1); 1530145256Sjkoshy if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS || 1531145256Sjkoshy pe == PMC_EV_P6_BUS_LOCK_CLOCKS || 1532145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BRD || 1533145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_RFO || 1534145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_IFETCH || 1535145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_INVAL || 1536145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_PWR || 1537145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_DEF || 1538145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_BURST || 1539145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_ANY || 1540145256Sjkoshy pe == PMC_EV_P6_BUS_TRAN_MEM || 1541145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_IO || 1542145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_P || 1543145256Sjkoshy pe == PMC_EV_P6_BUS_TRANS_WB || 1544145256Sjkoshy pe == PMC_EV_P6_EMON_EST_TRANS || 1545145256Sjkoshy pe == PMC_EV_P6_EMON_FUSED_UOPS_RET || 1546145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET || 1547145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_INST_RETIRED || 1548145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED || 1549145256Sjkoshy pe == PMC_EV_P6_EMON_KNI_PREF_MISS || 1550145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED || 1551145256Sjkoshy pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED || 1552145256Sjkoshy pe == PMC_EV_P6_FP_MMX_TRANS) 1553174406Sjkoshy && (n > 1)) /* Only one mask keyword is allowed. */ 1554174406Sjkoshy return (-1); 1555145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1556145256Sjkoshy } else if (KWMATCH(p, P6_KW_USR)) { 1557145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_USER; 1558145256Sjkoshy } else 1559174406Sjkoshy return (-1); 1560145256Sjkoshy } 1561145256Sjkoshy 1562145256Sjkoshy /* post processing */ 1563145256Sjkoshy switch (pe) { 1564145256Sjkoshy 1565145256Sjkoshy /* 1566145256Sjkoshy * The following events default to an evmask of 0 1567145256Sjkoshy */ 1568145256Sjkoshy 1569145256Sjkoshy /* default => 'self' */ 1570145256Sjkoshy case PMC_EV_P6_BUS_DRDY_CLOCKS: 1571145256Sjkoshy case PMC_EV_P6_BUS_LOCK_CLOCKS: 1572145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BRD: 1573145256Sjkoshy case PMC_EV_P6_BUS_TRAN_RFO: 1574145256Sjkoshy case PMC_EV_P6_BUS_TRANS_WB: 1575145256Sjkoshy case PMC_EV_P6_BUS_TRAN_IFETCH: 1576145256Sjkoshy case PMC_EV_P6_BUS_TRAN_INVAL: 1577145256Sjkoshy case PMC_EV_P6_BUS_TRAN_PWR: 1578145256Sjkoshy case PMC_EV_P6_BUS_TRANS_P: 1579145256Sjkoshy case PMC_EV_P6_BUS_TRANS_IO: 1580145256Sjkoshy case PMC_EV_P6_BUS_TRAN_DEF: 1581145256Sjkoshy case PMC_EV_P6_BUS_TRAN_BURST: 1582145256Sjkoshy case PMC_EV_P6_BUS_TRAN_ANY: 1583145256Sjkoshy case PMC_EV_P6_BUS_TRAN_MEM: 1584145256Sjkoshy 1585145256Sjkoshy /* default => 'nta' */ 1586145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED: 1587145256Sjkoshy case PMC_EV_P6_EMON_KNI_PREF_MISS: 1588145256Sjkoshy 1589145256Sjkoshy /* default => 'packed and scalar' */ 1590145256Sjkoshy case PMC_EV_P6_EMON_KNI_INST_RETIRED: 1591145256Sjkoshy case PMC_EV_P6_EMON_KNI_COMP_INST_RET: 1592145256Sjkoshy 1593145256Sjkoshy /* default => 'mmx to fp transitions' */ 1594145256Sjkoshy case PMC_EV_P6_FP_MMX_TRANS: 1595145256Sjkoshy 1596145256Sjkoshy /* default => 'SSE Packed Single' */ 1597145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED: 1598145256Sjkoshy case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED: 1599145256Sjkoshy 1600145256Sjkoshy /* default => 'all fused micro-ops' */ 1601145256Sjkoshy case PMC_EV_P6_EMON_FUSED_UOPS_RET: 1602145256Sjkoshy 1603145256Sjkoshy /* default => 'all transitions' */ 1604145256Sjkoshy case PMC_EV_P6_EMON_EST_TRANS: 1605145256Sjkoshy break; 1606145256Sjkoshy 1607145256Sjkoshy case PMC_EV_P6_MMX_UOPS_EXEC: 1608145256Sjkoshy evmask = 0x0F; /* only value allowed */ 1609145256Sjkoshy break; 1610145256Sjkoshy 1611145256Sjkoshy default: 1612145256Sjkoshy /* 1613145256Sjkoshy * For all other events, set the default event mask 1614145256Sjkoshy * to a logical OR of all the allowed event mask bits. 1615145256Sjkoshy */ 1616145256Sjkoshy if (evmask == 0 && pmask) { 1617145256Sjkoshy for (pm = pmask; pm->pm_name; pm++) 1618145256Sjkoshy evmask |= pm->pm_value; 1619145256Sjkoshy pmc_config->pm_caps |= PMC_CAP_QUALIFIER; 1620145256Sjkoshy } 1621145256Sjkoshy 1622145256Sjkoshy break; 1623145256Sjkoshy } 1624145256Sjkoshy 1625145256Sjkoshy if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) 1626147191Sjkoshy pmc_config->pm_md.pm_ppro.pm_ppro_config |= 1627147191Sjkoshy P6_EVSEL_TO_UMASK(evmask); 1628145256Sjkoshy 1629174406Sjkoshy return (0); 1630145256Sjkoshy} 1631145256Sjkoshy 1632147191Sjkoshy#endif 1633147191Sjkoshy 1634145256Sjkoshy/* 1635147191Sjkoshy * API entry points 1636145256Sjkoshy */ 1637145256Sjkoshy 1638147191Sjkoshyint 1639147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode, 1640147191Sjkoshy uint32_t flags, int cpu, pmc_id_t *pmcid) 1641145256Sjkoshy{ 1642147191Sjkoshy int retval; 1643147191Sjkoshy enum pmc_event pe; 1644147191Sjkoshy char *r, *spec_copy; 1645147191Sjkoshy const char *ctrname; 1646147191Sjkoshy const struct pmc_event_alias *p; 1647147191Sjkoshy struct pmc_op_pmcallocate pmc_config; 1648145256Sjkoshy 1649147191Sjkoshy spec_copy = NULL; 1650147191Sjkoshy retval = -1; 1651145256Sjkoshy 1652147191Sjkoshy if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && 1653147191Sjkoshy mode != PMC_MODE_SC && mode != PMC_MODE_TC) { 1654147191Sjkoshy errno = EINVAL; 1655147191Sjkoshy goto out; 1656147191Sjkoshy } 1657145256Sjkoshy 1658147191Sjkoshy /* replace an event alias with the canonical event specifier */ 1659147191Sjkoshy if (pmc_mdep_event_aliases) 1660147191Sjkoshy for (p = pmc_mdep_event_aliases; p->pm_alias; p++) 1661147191Sjkoshy if (!strcmp(ctrspec, p->pm_alias)) { 1662147191Sjkoshy spec_copy = strdup(p->pm_spec); 1663147191Sjkoshy break; 1664147191Sjkoshy } 1665145256Sjkoshy 1666147191Sjkoshy if (spec_copy == NULL) 1667147191Sjkoshy spec_copy = strdup(ctrspec); 1668145256Sjkoshy 1669147191Sjkoshy r = spec_copy; 1670147191Sjkoshy ctrname = strsep(&r, ","); 1671145256Sjkoshy 1672147191Sjkoshy /* look for the given counter name */ 1673147191Sjkoshy for (pe = PMC_EVENT_FIRST; pe < (PMC_EVENT_LAST+1); pe++) 1674147191Sjkoshy if (!strcmp(ctrname, pmc_event_table[pe].pm_ev_name)) 1675147191Sjkoshy break; 1676145256Sjkoshy 1677147191Sjkoshy if (pe > PMC_EVENT_LAST) { 1678147191Sjkoshy errno = EINVAL; 1679147191Sjkoshy goto out; 1680147191Sjkoshy } 1681145256Sjkoshy 1682147191Sjkoshy bzero(&pmc_config, sizeof(pmc_config)); 1683147191Sjkoshy pmc_config.pm_ev = pmc_event_table[pe].pm_ev_code; 1684147191Sjkoshy pmc_config.pm_class = pmc_event_table[pe].pm_ev_class; 1685147191Sjkoshy pmc_config.pm_cpu = cpu; 1686147191Sjkoshy pmc_config.pm_mode = mode; 1687147191Sjkoshy pmc_config.pm_flags = flags; 1688145256Sjkoshy 1689147191Sjkoshy if (PMC_IS_SAMPLING_MODE(mode)) 1690147191Sjkoshy pmc_config.pm_caps |= PMC_CAP_INTERRUPT; 1691145256Sjkoshy 1692147191Sjkoshy if (pmc_mdep_allocate_pmc(pe, r, &pmc_config) < 0) { 1693147191Sjkoshy errno = EINVAL; 1694147191Sjkoshy goto out; 1695147191Sjkoshy } 1696145256Sjkoshy 1697147191Sjkoshy if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0) 1698147191Sjkoshy goto out; 1699145256Sjkoshy 1700147191Sjkoshy *pmcid = pmc_config.pm_pmcid; 1701145256Sjkoshy 1702147191Sjkoshy retval = 0; 1703145256Sjkoshy 1704147191Sjkoshy out: 1705147191Sjkoshy if (spec_copy) 1706147191Sjkoshy free(spec_copy); 1707145256Sjkoshy 1708174406Sjkoshy return (retval); 1709147191Sjkoshy} 1710145256Sjkoshy 1711147191Sjkoshyint 1712147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid) 1713147191Sjkoshy{ 1714147191Sjkoshy struct pmc_op_pmcattach pmc_attach_args; 1715145256Sjkoshy 1716147191Sjkoshy pmc_attach_args.pm_pmc = pmc; 1717147191Sjkoshy pmc_attach_args.pm_pid = pid; 1718145256Sjkoshy 1719174406Sjkoshy return (PMC_CALL(PMCATTACH, &pmc_attach_args)); 1720147191Sjkoshy} 1721145256Sjkoshy 1722147191Sjkoshyint 1723147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps) 1724147191Sjkoshy{ 1725147191Sjkoshy unsigned int i; 1726147191Sjkoshy enum pmc_class cl; 1727145256Sjkoshy 1728147191Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 1729147191Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 1730147191Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 1731147191Sjkoshy *caps = cpu_info.pm_classes[i].pm_caps; 1732174406Sjkoshy return (0); 1733147191Sjkoshy } 1734177107Sjkoshy errno = EINVAL; 1735177107Sjkoshy return (-1); 1736147191Sjkoshy} 1737145256Sjkoshy 1738147191Sjkoshyint 1739147191Sjkoshypmc_configure_logfile(int fd) 1740147191Sjkoshy{ 1741147191Sjkoshy struct pmc_op_configurelog cla; 1742145256Sjkoshy 1743147191Sjkoshy cla.pm_logfd = fd; 1744147191Sjkoshy if (PMC_CALL(CONFIGURELOG, &cla) < 0) 1745174406Sjkoshy return (-1); 1746174406Sjkoshy return (0); 1747147191Sjkoshy} 1748145256Sjkoshy 1749147191Sjkoshyint 1750147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci) 1751147191Sjkoshy{ 1752147191Sjkoshy if (pmc_syscall == -1) { 1753147191Sjkoshy errno = ENXIO; 1754174406Sjkoshy return (-1); 1755147191Sjkoshy } 1756145256Sjkoshy 1757147219Sjkoshy *pci = &cpu_info; 1758174406Sjkoshy return (0); 1759147191Sjkoshy} 1760145256Sjkoshy 1761147191Sjkoshyint 1762147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid) 1763147191Sjkoshy{ 1764147191Sjkoshy struct pmc_op_pmcattach pmc_detach_args; 1765145256Sjkoshy 1766147191Sjkoshy pmc_detach_args.pm_pmc = pmc; 1767147191Sjkoshy pmc_detach_args.pm_pid = pid; 1768174406Sjkoshy return (PMC_CALL(PMCDETACH, &pmc_detach_args)); 1769147191Sjkoshy} 1770147191Sjkoshy 1771147191Sjkoshyint 1772147191Sjkoshypmc_disable(int cpu, int pmc) 1773145256Sjkoshy{ 1774147191Sjkoshy struct pmc_op_pmcadmin ssa; 1775145256Sjkoshy 1776147191Sjkoshy ssa.pm_cpu = cpu; 1777147191Sjkoshy ssa.pm_pmc = pmc; 1778147191Sjkoshy ssa.pm_state = PMC_STATE_DISABLED; 1779174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 1780147191Sjkoshy} 1781145256Sjkoshy 1782147191Sjkoshyint 1783147191Sjkoshypmc_enable(int cpu, int pmc) 1784147191Sjkoshy{ 1785147191Sjkoshy struct pmc_op_pmcadmin ssa; 1786145256Sjkoshy 1787147191Sjkoshy ssa.pm_cpu = cpu; 1788147191Sjkoshy ssa.pm_pmc = pmc; 1789147191Sjkoshy ssa.pm_state = PMC_STATE_FREE; 1790174406Sjkoshy return (PMC_CALL(PMCADMIN, &ssa)); 1791147191Sjkoshy} 1792145256Sjkoshy 1793147191Sjkoshy/* 1794147191Sjkoshy * Return a list of events known to a given PMC class. 'cl' is the 1795147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const 1796147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is 1797147191Sjkoshy * the number of event name pointers returned. 1798147191Sjkoshy * 1799147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3). The caller 1800147191Sjkoshy * is responsible for freeing this space when done. 1801147191Sjkoshy */ 1802147191Sjkoshyint 1803147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames, 1804147191Sjkoshy int *nevents) 1805147191Sjkoshy{ 1806147191Sjkoshy int count; 1807147191Sjkoshy const char **names; 1808147191Sjkoshy const struct pmc_event_descr *ev; 1809147191Sjkoshy 1810147191Sjkoshy switch (cl) 1811147191Sjkoshy { 1812147191Sjkoshy case PMC_CLASS_TSC: 1813147191Sjkoshy ev = &pmc_event_table[PMC_EV_TSC_TSC]; 1814147191Sjkoshy count = 1; 1815145256Sjkoshy break; 1816147191Sjkoshy case PMC_CLASS_K7: 1817147191Sjkoshy ev = &pmc_event_table[PMC_EV_K7_FIRST]; 1818147191Sjkoshy count = PMC_EV_K7_LAST - PMC_EV_K7_FIRST + 1; 1819145256Sjkoshy break; 1820147191Sjkoshy case PMC_CLASS_K8: 1821147191Sjkoshy ev = &pmc_event_table[PMC_EV_K8_FIRST]; 1822147191Sjkoshy count = PMC_EV_K8_LAST - PMC_EV_K8_FIRST + 1; 1823145256Sjkoshy break; 1824147191Sjkoshy case PMC_CLASS_P5: 1825147191Sjkoshy ev = &pmc_event_table[PMC_EV_P5_FIRST]; 1826147191Sjkoshy count = PMC_EV_P5_LAST - PMC_EV_P5_FIRST + 1; 1827145256Sjkoshy break; 1828147191Sjkoshy case PMC_CLASS_P6: 1829147191Sjkoshy ev = &pmc_event_table[PMC_EV_P6_FIRST]; 1830147191Sjkoshy count = PMC_EV_P6_LAST - PMC_EV_P6_FIRST + 1; 1831145256Sjkoshy break; 1832147191Sjkoshy case PMC_CLASS_P4: 1833147191Sjkoshy ev = &pmc_event_table[PMC_EV_P4_FIRST]; 1834147191Sjkoshy count = PMC_EV_P4_LAST - PMC_EV_P4_FIRST + 1; 1835145256Sjkoshy break; 1836145256Sjkoshy default: 1837147191Sjkoshy errno = EINVAL; 1838174406Sjkoshy return (-1); 1839145256Sjkoshy } 1840145256Sjkoshy 1841147191Sjkoshy if ((names = malloc(count * sizeof(const char *))) == NULL) 1842174406Sjkoshy return (-1); 1843145256Sjkoshy 1844147191Sjkoshy *eventnames = names; 1845147191Sjkoshy *nevents = count; 1846145256Sjkoshy 1847147191Sjkoshy for (;count--; ev++, names++) 1848147191Sjkoshy *names = ev->pm_ev_name; 1849174406Sjkoshy return (0); 1850147191Sjkoshy} 1851145256Sjkoshy 1852147191Sjkoshyint 1853147191Sjkoshypmc_flush_logfile(void) 1854147191Sjkoshy{ 1855174406Sjkoshy return (PMC_CALL(FLUSHLOG,0)); 1856147191Sjkoshy} 1857145256Sjkoshy 1858147191Sjkoshyint 1859147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds) 1860147191Sjkoshy{ 1861147191Sjkoshy struct pmc_op_getdriverstats gms; 1862145256Sjkoshy 1863147191Sjkoshy if (PMC_CALL(GETDRIVERSTATS, &gms) < 0) 1864174406Sjkoshy return (-1); 1865145256Sjkoshy 1866147191Sjkoshy /* copy out fields in the current userland<->library interface */ 1867147191Sjkoshy ds->pm_intr_ignored = gms.pm_intr_ignored; 1868147191Sjkoshy ds->pm_intr_processed = gms.pm_intr_processed; 1869147191Sjkoshy ds->pm_intr_bufferfull = gms.pm_intr_bufferfull; 1870147191Sjkoshy ds->pm_syscalls = gms.pm_syscalls; 1871147191Sjkoshy ds->pm_syscall_errors = gms.pm_syscall_errors; 1872147191Sjkoshy ds->pm_buffer_requests = gms.pm_buffer_requests; 1873147191Sjkoshy ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed; 1874147191Sjkoshy ds->pm_log_sweeps = gms.pm_log_sweeps; 1875174406Sjkoshy return (0); 1876147191Sjkoshy} 1877145256Sjkoshy 1878147191Sjkoshyint 1879147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr) 1880147191Sjkoshy{ 1881147191Sjkoshy struct pmc_op_getmsr gm; 1882147191Sjkoshy 1883147191Sjkoshy gm.pm_pmcid = pmc; 1884147191Sjkoshy if (PMC_CALL(PMCGETMSR, &gm) < 0) 1885174406Sjkoshy return (-1); 1886147191Sjkoshy *msr = gm.pm_msr; 1887174406Sjkoshy return (0); 1888145256Sjkoshy} 1889145256Sjkoshy 1890145256Sjkoshyint 1891145256Sjkoshypmc_init(void) 1892145256Sjkoshy{ 1893145256Sjkoshy int error, pmc_mod_id; 1894147219Sjkoshy unsigned int n; 1895145256Sjkoshy uint32_t abi_version; 1896145256Sjkoshy struct module_stat pmc_modstat; 1897147219Sjkoshy struct pmc_op_getcpuinfo op_cpu_info; 1898145256Sjkoshy 1899145256Sjkoshy if (pmc_syscall != -1) /* already inited */ 1900174406Sjkoshy return (0); 1901145256Sjkoshy 1902145256Sjkoshy /* retrieve the system call number from the KLD */ 1903145256Sjkoshy if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0) 1904174406Sjkoshy return (-1); 1905145256Sjkoshy 1906145256Sjkoshy pmc_modstat.version = sizeof(struct module_stat); 1907145256Sjkoshy if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0) 1908174406Sjkoshy return (-1); 1909145256Sjkoshy 1910145256Sjkoshy pmc_syscall = pmc_modstat.data.intval; 1911145256Sjkoshy 1912147191Sjkoshy /* check the kernel module's ABI against our compiled-in version */ 1913147191Sjkoshy abi_version = PMC_VERSION; 1914145256Sjkoshy if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0) 1915145256Sjkoshy return (pmc_syscall = -1); 1916145256Sjkoshy 1917147191Sjkoshy /* ignore patch & minor numbers for the comparision */ 1918147191Sjkoshy if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) { 1919145256Sjkoshy errno = EPROGMISMATCH; 1920145256Sjkoshy return (pmc_syscall = -1); 1921145256Sjkoshy } 1922145256Sjkoshy 1923147219Sjkoshy if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0) 1924145256Sjkoshy return (pmc_syscall = -1); 1925145256Sjkoshy 1926147219Sjkoshy cpu_info.pm_cputype = op_cpu_info.pm_cputype; 1927147219Sjkoshy cpu_info.pm_ncpu = op_cpu_info.pm_ncpu; 1928147219Sjkoshy cpu_info.pm_npmc = op_cpu_info.pm_npmc; 1929147219Sjkoshy cpu_info.pm_nclass = op_cpu_info.pm_nclass; 1930147219Sjkoshy for (n = 0; n < cpu_info.pm_nclass; n++) 1931147219Sjkoshy cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n]; 1932147219Sjkoshy 1933145256Sjkoshy /* set parser pointer */ 1934145256Sjkoshy switch (cpu_info.pm_cputype) { 1935145340Smarcel#if defined(__i386__) 1936145256Sjkoshy case PMC_CPU_AMD_K7: 1937145256Sjkoshy pmc_mdep_event_aliases = k7_aliases; 1938145256Sjkoshy pmc_mdep_allocate_pmc = k7_allocate_pmc; 1939145256Sjkoshy break; 1940145256Sjkoshy case PMC_CPU_INTEL_P5: 1941145256Sjkoshy pmc_mdep_event_aliases = p5_aliases; 1942145256Sjkoshy pmc_mdep_allocate_pmc = p5_allocate_pmc; 1943145256Sjkoshy break; 1944145256Sjkoshy case PMC_CPU_INTEL_P6: /* P6 ... Pentium M CPUs have */ 1945145256Sjkoshy case PMC_CPU_INTEL_PII: /* similar PMCs. */ 1946145256Sjkoshy case PMC_CPU_INTEL_PIII: 1947145256Sjkoshy case PMC_CPU_INTEL_PM: 1948145256Sjkoshy pmc_mdep_event_aliases = p6_aliases; 1949145256Sjkoshy pmc_mdep_allocate_pmc = p6_allocate_pmc; 1950145256Sjkoshy break; 1951147759Sjkoshy#endif 1952147759Sjkoshy#if defined(__amd64__) || defined(__i386__) 1953145256Sjkoshy case PMC_CPU_INTEL_PIV: 1954145256Sjkoshy pmc_mdep_event_aliases = p4_aliases; 1955145256Sjkoshy pmc_mdep_allocate_pmc = p4_allocate_pmc; 1956145256Sjkoshy break; 1957145256Sjkoshy case PMC_CPU_AMD_K8: 1958145256Sjkoshy pmc_mdep_event_aliases = k8_aliases; 1959145256Sjkoshy pmc_mdep_allocate_pmc = k8_allocate_pmc; 1960145256Sjkoshy break; 1961145256Sjkoshy#endif 1962145256Sjkoshy 1963145256Sjkoshy default: 1964145256Sjkoshy /* 1965145256Sjkoshy * Some kind of CPU this version of the library knows nothing 1966145256Sjkoshy * about. This shouldn't happen since the abi version check 1967145256Sjkoshy * should have caught this. 1968145256Sjkoshy */ 1969145256Sjkoshy errno = ENXIO; 1970145256Sjkoshy return (pmc_syscall = -1); 1971145256Sjkoshy } 1972145256Sjkoshy 1973174406Sjkoshy return (0); 1974145256Sjkoshy} 1975145256Sjkoshy 1976147191Sjkoshyconst char * 1977147191Sjkoshypmc_name_of_capability(enum pmc_caps cap) 1978145256Sjkoshy{ 1979147191Sjkoshy int i; 1980145256Sjkoshy 1981147191Sjkoshy /* 1982147191Sjkoshy * 'cap' should have a single bit set and should be in 1983147191Sjkoshy * range. 1984147191Sjkoshy */ 1985147191Sjkoshy if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST || 1986147191Sjkoshy cap > PMC_CAP_LAST) { 1987145256Sjkoshy errno = EINVAL; 1988174406Sjkoshy return (NULL); 1989145256Sjkoshy } 1990145256Sjkoshy 1991147191Sjkoshy i = ffs(cap); 1992174406Sjkoshy return (pmc_capability_names[i - 1]); 1993147191Sjkoshy} 1994145256Sjkoshy 1995147191Sjkoshyconst char * 1996147191Sjkoshypmc_name_of_class(enum pmc_class pc) 1997147191Sjkoshy{ 1998147191Sjkoshy if ((int) pc >= PMC_CLASS_FIRST && 1999147191Sjkoshy pc <= PMC_CLASS_LAST) 2000174406Sjkoshy return (pmc_class_names[pc]); 2001145256Sjkoshy 2002147191Sjkoshy errno = EINVAL; 2003174406Sjkoshy return (NULL); 2004147191Sjkoshy} 2005145256Sjkoshy 2006147191Sjkoshyconst char * 2007147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp) 2008147191Sjkoshy{ 2009147191Sjkoshy if ((int) cp >= PMC_CPU_FIRST && 2010147191Sjkoshy cp <= PMC_CPU_LAST) 2011174406Sjkoshy return (pmc_cputype_names[cp]); 2012147191Sjkoshy errno = EINVAL; 2013174406Sjkoshy return (NULL); 2014147191Sjkoshy} 2015145256Sjkoshy 2016147191Sjkoshyconst char * 2017147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd) 2018147191Sjkoshy{ 2019147191Sjkoshy if ((int) pd >= PMC_DISP_FIRST && 2020147191Sjkoshy pd <= PMC_DISP_LAST) 2021174406Sjkoshy return (pmc_disposition_names[pd]); 2022145256Sjkoshy 2023147191Sjkoshy errno = EINVAL; 2024174406Sjkoshy return (NULL); 2025147191Sjkoshy} 2026145256Sjkoshy 2027147191Sjkoshyconst char * 2028147191Sjkoshypmc_name_of_event(enum pmc_event pe) 2029147191Sjkoshy{ 2030147191Sjkoshy if ((int) pe >= PMC_EVENT_FIRST && 2031147191Sjkoshy pe <= PMC_EVENT_LAST) 2032174406Sjkoshy return (pmc_event_table[pe].pm_ev_name); 2033145256Sjkoshy 2034147191Sjkoshy errno = EINVAL; 2035174406Sjkoshy return (NULL); 2036147191Sjkoshy} 2037145256Sjkoshy 2038147191Sjkoshyconst char * 2039147191Sjkoshypmc_name_of_mode(enum pmc_mode pm) 2040147191Sjkoshy{ 2041147191Sjkoshy if ((int) pm >= PMC_MODE_FIRST && 2042147191Sjkoshy pm <= PMC_MODE_LAST) 2043174406Sjkoshy return (pmc_mode_names[pm]); 2044145256Sjkoshy 2045147191Sjkoshy errno = EINVAL; 2046174406Sjkoshy return (NULL); 2047147191Sjkoshy} 2048145256Sjkoshy 2049147191Sjkoshyconst char * 2050147191Sjkoshypmc_name_of_state(enum pmc_state ps) 2051147191Sjkoshy{ 2052147191Sjkoshy if ((int) ps >= PMC_STATE_FIRST && 2053147191Sjkoshy ps <= PMC_STATE_LAST) 2054174406Sjkoshy return (pmc_state_names[ps]); 2055145256Sjkoshy 2056147191Sjkoshy errno = EINVAL; 2057174406Sjkoshy return (NULL); 2058145256Sjkoshy} 2059145256Sjkoshy 2060145256Sjkoshyint 2061147191Sjkoshypmc_ncpu(void) 2062145256Sjkoshy{ 2063147191Sjkoshy if (pmc_syscall == -1) { 2064147191Sjkoshy errno = ENXIO; 2065174406Sjkoshy return (-1); 2066147191Sjkoshy } 2067145256Sjkoshy 2068174406Sjkoshy return (cpu_info.pm_ncpu); 2069145256Sjkoshy} 2070145256Sjkoshy 2071145256Sjkoshyint 2072147191Sjkoshypmc_npmc(int cpu) 2073145256Sjkoshy{ 2074147191Sjkoshy if (pmc_syscall == -1) { 2075147191Sjkoshy errno = ENXIO; 2076174406Sjkoshy return (-1); 2077147191Sjkoshy } 2078145256Sjkoshy 2079147191Sjkoshy if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) { 2080147191Sjkoshy errno = EINVAL; 2081174406Sjkoshy return (-1); 2082147191Sjkoshy } 2083145256Sjkoshy 2084174406Sjkoshy return (cpu_info.pm_npmc); 2085145256Sjkoshy} 2086145256Sjkoshy 2087145256Sjkoshyint 2088147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci) 2089145256Sjkoshy{ 2090147191Sjkoshy int nbytes, npmc; 2091147191Sjkoshy struct pmc_op_getpmcinfo *pmci; 2092145256Sjkoshy 2093147191Sjkoshy if ((npmc = pmc_npmc(cpu)) < 0) 2094174406Sjkoshy return (-1); 2095145256Sjkoshy 2096147191Sjkoshy nbytes = sizeof(struct pmc_op_getpmcinfo) + 2097147191Sjkoshy npmc * sizeof(struct pmc_info); 2098145256Sjkoshy 2099147191Sjkoshy if ((pmci = calloc(1, nbytes)) == NULL) 2100174406Sjkoshy return (-1); 2101145256Sjkoshy 2102147191Sjkoshy pmci->pm_cpu = cpu; 2103145256Sjkoshy 2104147191Sjkoshy if (PMC_CALL(GETPMCINFO, pmci) < 0) { 2105147191Sjkoshy free(pmci); 2106174406Sjkoshy return (-1); 2107147191Sjkoshy } 2108145256Sjkoshy 2109147191Sjkoshy /* kernel<->library, library<->userland interfaces are identical */ 2110147191Sjkoshy *ppmci = (struct pmc_pmcinfo *) pmci; 2111174406Sjkoshy return (0); 2112145256Sjkoshy} 2113145256Sjkoshy 2114145256Sjkoshyint 2115145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value) 2116145256Sjkoshy{ 2117145256Sjkoshy struct pmc_op_pmcrw pmc_read_op; 2118145256Sjkoshy 2119145256Sjkoshy pmc_read_op.pm_pmcid = pmc; 2120145256Sjkoshy pmc_read_op.pm_flags = PMC_F_OLDVALUE; 2121145256Sjkoshy pmc_read_op.pm_value = -1; 2122145256Sjkoshy 2123145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_read_op) < 0) 2124174406Sjkoshy return (-1); 2125145256Sjkoshy 2126145256Sjkoshy *value = pmc_read_op.pm_value; 2127174406Sjkoshy return (0); 2128145256Sjkoshy} 2129145256Sjkoshy 2130145256Sjkoshyint 2131147191Sjkoshypmc_release(pmc_id_t pmc) 2132145256Sjkoshy{ 2133147191Sjkoshy struct pmc_op_simple pmc_release_args; 2134145256Sjkoshy 2135147191Sjkoshy pmc_release_args.pm_pmcid = pmc; 2136174406Sjkoshy return (PMC_CALL(PMCRELEASE, &pmc_release_args)); 2137145256Sjkoshy} 2138145256Sjkoshy 2139145256Sjkoshyint 2140145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep) 2141145256Sjkoshy{ 2142145256Sjkoshy struct pmc_op_pmcrw pmc_rw_op; 2143145256Sjkoshy 2144145256Sjkoshy pmc_rw_op.pm_pmcid = pmc; 2145145256Sjkoshy pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE; 2146145256Sjkoshy pmc_rw_op.pm_value = newvalue; 2147145256Sjkoshy 2148145256Sjkoshy if (PMC_CALL(PMCRW, &pmc_rw_op) < 0) 2149174406Sjkoshy return (-1); 2150145256Sjkoshy 2151145256Sjkoshy *oldvaluep = pmc_rw_op.pm_value; 2152174406Sjkoshy return (0); 2153145256Sjkoshy} 2154145256Sjkoshy 2155145256Sjkoshyint 2156145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value) 2157145256Sjkoshy{ 2158145256Sjkoshy struct pmc_op_pmcsetcount sc; 2159145256Sjkoshy 2160145256Sjkoshy sc.pm_pmcid = pmc; 2161145256Sjkoshy sc.pm_count = value; 2162145256Sjkoshy 2163145256Sjkoshy if (PMC_CALL(PMCSETCOUNT, &sc) < 0) 2164174406Sjkoshy return (-1); 2165174406Sjkoshy return (0); 2166145256Sjkoshy} 2167145256Sjkoshy 2168145256Sjkoshyint 2169147191Sjkoshypmc_start(pmc_id_t pmc) 2170145256Sjkoshy{ 2171147191Sjkoshy struct pmc_op_simple pmc_start_args; 2172145256Sjkoshy 2173147191Sjkoshy pmc_start_args.pm_pmcid = pmc; 2174174406Sjkoshy return (PMC_CALL(PMCSTART, &pmc_start_args)); 2175145256Sjkoshy} 2176145256Sjkoshy 2177145256Sjkoshyint 2178147191Sjkoshypmc_stop(pmc_id_t pmc) 2179145256Sjkoshy{ 2180147191Sjkoshy struct pmc_op_simple pmc_stop_args; 2181145256Sjkoshy 2182147191Sjkoshy pmc_stop_args.pm_pmcid = pmc; 2183174406Sjkoshy return (PMC_CALL(PMCSTOP, &pmc_stop_args)); 2184145256Sjkoshy} 2185145256Sjkoshy 2186145256Sjkoshyint 2187145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width) 2188145774Sjkoshy{ 2189145774Sjkoshy unsigned int i; 2190145774Sjkoshy enum pmc_class cl; 2191145774Sjkoshy 2192145774Sjkoshy cl = PMC_ID_TO_CLASS(pmcid); 2193145774Sjkoshy for (i = 0; i < cpu_info.pm_nclass; i++) 2194145774Sjkoshy if (cpu_info.pm_classes[i].pm_class == cl) { 2195145774Sjkoshy *width = cpu_info.pm_classes[i].pm_width; 2196174406Sjkoshy return (0); 2197145774Sjkoshy } 2198177107Sjkoshy errno = EINVAL; 2199177107Sjkoshy return (-1); 2200145774Sjkoshy} 2201145774Sjkoshy 2202145774Sjkoshyint 2203147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value) 2204145774Sjkoshy{ 2205147191Sjkoshy struct pmc_op_pmcrw pmc_write_op; 2206145774Sjkoshy 2207147191Sjkoshy pmc_write_op.pm_pmcid = pmc; 2208147191Sjkoshy pmc_write_op.pm_flags = PMC_F_NEWVALUE; 2209147191Sjkoshy pmc_write_op.pm_value = value; 2210174406Sjkoshy return (PMC_CALL(PMCRW, &pmc_write_op)); 2211145256Sjkoshy} 2212145256Sjkoshy 2213145256Sjkoshyint 2214147191Sjkoshypmc_writelog(uint32_t userdata) 2215145256Sjkoshy{ 2216147191Sjkoshy struct pmc_op_writelog wl; 2217145256Sjkoshy 2218147191Sjkoshy wl.pm_userdata = userdata; 2219174406Sjkoshy return (PMC_CALL(WRITELOG, &wl)); 2220145256Sjkoshy} 2221