|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* pfmlib_intel_nhm.c : Intel Nehalem PMU
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Copyright (c) 2008 Google, Inc
|
|
Packit |
577717 |
* Contributed by Stephane Eranian <eranian@gmail.com>
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
Packit |
577717 |
* of this software and associated documentation files (the "Software"), to deal
|
|
Packit |
577717 |
* in the Software without restriction, including without limitation the rights
|
|
Packit |
577717 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
577717 |
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
Packit |
577717 |
* subject to the following conditions:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* The above copyright notice and this permission notice shall be included in all
|
|
Packit |
577717 |
* copies or substantial portions of the Software.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
Packit |
577717 |
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit |
577717 |
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
Packit |
577717 |
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
Packit |
577717 |
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
Packit |
577717 |
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Nehalem PMU = architectural perfmon v3 + OFFCORE + PEBS v2 + uncore PMU + LBR
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#include <sys/types.h>
|
|
Packit |
577717 |
#include <ctype.h>
|
|
Packit |
577717 |
#include <string.h>
|
|
Packit |
577717 |
#include <stdlib.h>
|
|
Packit |
577717 |
#include <stdio.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* public headers */
|
|
Packit |
577717 |
#include <perfmon/pfmlib_intel_nhm.h>
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* private headers */
|
|
Packit |
577717 |
#include "pfmlib_priv.h"
|
|
Packit |
577717 |
#include "pfmlib_intel_nhm_priv.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel Westmere event tables */
|
|
Packit |
577717 |
#include "intel_wsm_events.h"
|
|
Packit |
577717 |
#include "intel_wsm_unc_events.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* Intel Core i7 event tables */
|
|
Packit |
577717 |
#include "intel_corei7_events.h"
|
|
Packit |
577717 |
#include "intel_corei7_unc_events.h"
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* let's define some handy shortcuts! */
|
|
Packit |
577717 |
#define usel_event unc_perfevtsel.usel_event
|
|
Packit |
577717 |
#define usel_umask unc_perfevtsel.usel_umask
|
|
Packit |
577717 |
#define usel_occ unc_perfevtsel.usel_occ
|
|
Packit |
577717 |
#define usel_edge unc_perfevtsel.usel_edge
|
|
Packit |
577717 |
#define usel_int unc_perfevtsel.usel_int
|
|
Packit |
577717 |
#define usel_en unc_perfevtsel.usel_en
|
|
Packit |
577717 |
#define usel_inv unc_perfevtsel.usel_inv
|
|
Packit |
577717 |
#define usel_cnt_mask unc_perfevtsel.usel_cnt_mask
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define sel_event perfevtsel.sel_event
|
|
Packit |
577717 |
#define sel_umask perfevtsel.sel_umask
|
|
Packit |
577717 |
#define sel_usr perfevtsel.sel_usr
|
|
Packit |
577717 |
#define sel_os perfevtsel.sel_os
|
|
Packit |
577717 |
#define sel_edge perfevtsel.sel_edge
|
|
Packit |
577717 |
#define sel_pc perfevtsel.sel_pc
|
|
Packit |
577717 |
#define sel_int perfevtsel.sel_int
|
|
Packit |
577717 |
#define sel_en perfevtsel.sel_en
|
|
Packit |
577717 |
#define sel_inv perfevtsel.sel_inv
|
|
Packit |
577717 |
#define sel_anythr perfevtsel.sel_anythr
|
|
Packit |
577717 |
#define sel_cnt_mask perfevtsel.sel_cnt_mask
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Description of the PMC registers mappings:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* 0 -> PMC0 -> PERFEVTSEL0
|
|
Packit |
577717 |
* 1 -> PMC1 -> PERFEVTSEL1
|
|
Packit |
577717 |
* 2 -> PMC2 -> PERFEVTSEL2
|
|
Packit |
577717 |
* 3 -> PMC3 -> PERFEVTSEL3
|
|
Packit |
577717 |
* 16 -> PMC16 -> FIXED_CTR_CTRL
|
|
Packit |
577717 |
* 17 -> PMC17 -> PEBS_ENABLED
|
|
Packit |
577717 |
* 18 -> PMC18 -> PEBS_LD_LATENCY_THRESHOLD
|
|
Packit |
577717 |
* 19 -> PMC19 -> OFFCORE_RSP0
|
|
Packit |
577717 |
* 20 -> PMC20 -> UNCORE_FIXED_CTRL
|
|
Packit |
577717 |
* 21 -> PMC21 -> UNCORE_EVNTSEL0
|
|
Packit |
577717 |
* 22 -> PMC22 -> UNCORE_EVNTSEL1
|
|
Packit |
577717 |
* 23 -> PMC23 -> UNCORE_EVNTSEL2
|
|
Packit |
577717 |
* 24 -> PMC24 -> UNCORE_EVNTSEL3
|
|
Packit |
577717 |
* 25 -> PMC25 -> UNCORE_EVNTSEL4
|
|
Packit |
577717 |
* 26 -> PMC26 -> UNCORE_EVNTSEL5
|
|
Packit |
577717 |
* 27 -> PMC27 -> UNCORE_EVNTSEL6
|
|
Packit |
577717 |
* 28 -> PMC28 -> UNCORE_EVNTSEL7
|
|
Packit |
577717 |
* 29 -> PMC31 -> UNCORE_ADDROP_MATCH
|
|
Packit |
577717 |
* 30 -> PMC32 -> LBR_SELECT
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Description of the PMD registers mapping:
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* 0 -> PMD0 -> PMC0
|
|
Packit |
577717 |
* 1 -> PMD1 -> PMC1
|
|
Packit |
577717 |
* 2 -> PMD2 -> PMC2
|
|
Packit |
577717 |
* 3 -> PMD3 -> PMC3
|
|
Packit |
577717 |
* 16 -> PMD16 -> FIXED_CTR0
|
|
Packit |
577717 |
* 17 -> PMD17 -> FIXED_CTR1
|
|
Packit |
577717 |
* 18 -> PMD18 -> FIXED_CTR2
|
|
Packit |
577717 |
* 19 not used
|
|
Packit |
577717 |
* 20 -> PMD20 -> UNCORE_FIXED_CTR0
|
|
Packit |
577717 |
* 21 -> PMD21 -> UNCORE_PMC0
|
|
Packit |
577717 |
* 22 -> PMD22 -> UNCORE_PMC1
|
|
Packit |
577717 |
* 23 -> PMD23 -> UNCORE_PMC2
|
|
Packit |
577717 |
* 24 -> PMD24 -> UNCORE_PMC3
|
|
Packit |
577717 |
* 25 -> PMD25 -> UNCORE_PMC4
|
|
Packit |
577717 |
* 26 -> PMD26 -> UNCORE_PMC5
|
|
Packit |
577717 |
* 27 -> PMD27 -> UNCORE_PMC6
|
|
Packit |
577717 |
* 28 -> PMD28 -> UNCORE_PMC7
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* 31 -> PMD31 -> LBR_TOS
|
|
Packit |
577717 |
* 32-63 -> PMD32-PMD63 -> LBR_FROM_0/LBR_TO_0 - LBR_FROM15/LBR_TO_15
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#define NHM_SEL_BASE 0x186
|
|
Packit |
577717 |
#define NHM_CTR_BASE 0xc1
|
|
Packit |
577717 |
#define NHM_FIXED_CTR_BASE 0x309
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define UNC_NHM_SEL_BASE 0x3c0
|
|
Packit |
577717 |
#define UNC_NHM_CTR_BASE 0x3b0
|
|
Packit |
577717 |
#define UNC_NHM_FIXED_CTR_BASE 0x394
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define MAX_COUNTERS 28 /* highest implemented counter */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define PFMLIB_NHM_ALL_FLAGS \
|
|
Packit |
577717 |
(PFM_NHM_SEL_INV|PFM_NHM_SEL_EDGE|PFM_NHM_SEL_ANYTHR)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#define NHM_NUM_GEN_COUNTERS 4
|
|
Packit |
577717 |
#define NHM_NUM_FIXED_COUNTERS 3
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_pmu_support_t intel_nhm_support;
|
|
Packit |
577717 |
pfm_pmu_support_t intel_wsm_support;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static pfmlib_regmask_t nhm_impl_pmcs, nhm_impl_pmds;
|
|
Packit |
577717 |
static pfmlib_regmask_t nhm_impl_unc_pmcs, nhm_impl_unc_pmds;
|
|
Packit |
577717 |
static pme_nhm_entry_t *pe, *unc_pe;
|
|
Packit |
577717 |
static unsigned int num_pe, num_unc_pe;
|
|
Packit |
577717 |
static int cpu_model, aaj80;
|
|
Packit |
577717 |
static int pme_cycles, pme_instr;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
#ifdef __i386__
|
|
Packit |
577717 |
static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
|
|
Packit |
577717 |
unsigned int *ecx, unsigned int *edx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* because ebx is used in Pic mode, we need to save/restore because
|
|
Packit |
577717 |
* cpuid clobbers it. I could not figure out a way to get ebx out in
|
|
Packit |
577717 |
* one cpuid instruction. To extract ebx, we need to move it to another
|
|
Packit |
577717 |
* register (here eax)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
__asm__("pushl %%ebx;cpuid; popl %%ebx"
|
|
Packit |
577717 |
:"=a" (*eax)
|
|
Packit |
577717 |
: "a" (op)
|
|
Packit |
577717 |
: "ecx", "edx");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__asm__("pushl %%ebx;cpuid; movl %%ebx, %%eax;popl %%ebx"
|
|
Packit |
577717 |
:"=a" (*ebx)
|
|
Packit |
577717 |
: "a" (op)
|
|
Packit |
577717 |
: "ecx", "edx");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#else
|
|
Packit |
577717 |
static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
|
|
Packit |
577717 |
unsigned int *ecx, unsigned int *edx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
__asm__("cpuid"
|
|
Packit |
577717 |
: "=a" (*eax),
|
|
Packit |
577717 |
"=b" (*ebx),
|
|
Packit |
577717 |
"=c" (*ecx),
|
|
Packit |
577717 |
"=d" (*edx)
|
|
Packit |
577717 |
: "0" (op), "c"(0));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
#endif
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline pme_nhm_entry_t *
|
|
Packit |
577717 |
get_nhm_entry(unsigned int i)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return i < num_pe ? pe+i : unc_pe+(i-num_pe);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_midx2uidx(unsigned int ev, unsigned int midx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i, num = 0;
|
|
Packit |
577717 |
pme_nhm_entry_t *ne;
|
|
Packit |
577717 |
int model;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(ev);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (i=0; i < ne->pme_numasks; i++) {
|
|
Packit |
577717 |
model = ne->pme_umasks[i].pme_umodel;
|
|
Packit |
577717 |
if (!model || model == cpu_model) {
|
|
Packit |
577717 |
if (midx == num)
|
|
Packit |
577717 |
return i;
|
|
Packit |
577717 |
num++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
DPRINT("cannot find umask %d for event %s\n", midx, ne->pme_name);
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_detect_common(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
int family;
|
|
Packit |
577717 |
char buffer[128];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("vendor_id", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (strcmp(buffer, "GenuineIntel"))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("cpu family", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
family = atoi(buffer);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = __pfm_getcpuinfo_attr("model", buffer, sizeof(buffer));
|
|
Packit |
577717 |
if (ret == -1)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
cpu_model = atoi(buffer);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (family != 6)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_detect(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#define INTEL_ARCH_MISP_BR_RETIRED (1 << 6)
|
|
Packit |
577717 |
unsigned int eax, ebx, ecx, edx;
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ret = pfm_nhm_detect_common();
|
|
Packit |
577717 |
if (ret != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
switch(cpu_model) {
|
|
Packit |
577717 |
case 26: /* Nehalem */
|
|
Packit |
577717 |
case 30:
|
|
Packit |
577717 |
case 31:
|
|
Packit |
577717 |
case 46:
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check for erratum AAJ80
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* MISPREDICTED_BRANCH_RETIRED may be broken
|
|
Packit |
577717 |
* in which case it appears in the list of
|
|
Packit |
577717 |
* unavailable architected events
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
cpuid(0xa, &eax, &ebx, &ecx, &edx;;
|
|
Packit |
577717 |
if (ebx & INTEL_ARCH_MISP_BR_RETIRED)
|
|
Packit |
577717 |
aaj80 = 1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_wsm_detect(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
switch(cpu_model) {
|
|
Packit |
577717 |
case 37: /* Westmere */
|
|
Packit |
577717 |
case 44:
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static inline void setup_nhm_impl_unc_regs(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 20);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 21);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 22);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 23);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 24);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 25);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 26);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 27);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmds, 28);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* uncore */
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 20);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 21);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 22);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 23);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 24);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 25);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 26);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 27);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 28);
|
|
Packit |
577717 |
/* unnhm_addrop_match */
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_unc_pmcs, 29);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
fixup_mem_uncore_retired(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
size_t i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < PME_COREI7_EVENT_COUNT; i++) {
|
|
Packit |
577717 |
if (corei7_pe[i].pme_code != 0xf)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* assume model46 umasks are at the end
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
corei7_pe[i].pme_numasks = 6;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_init(void)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfm_pmu_support_t *supp;
|
|
Packit |
577717 |
int i;
|
|
Packit |
577717 |
int num_unc_cnt = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (forced_pmu != PFMLIB_NO_PMU) {
|
|
Packit |
577717 |
if (forced_pmu == PFMLIB_INTEL_NHM_PMU)
|
|
Packit |
577717 |
cpu_model = 26;
|
|
Packit |
577717 |
else
|
|
Packit |
577717 |
cpu_model = 37;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* core */
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 0);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 1);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 2);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 3);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 16);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 17);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 18);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 19);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 0);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 1);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 2);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 3);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 16);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 17);
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, 18);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* lbr */
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 30);
|
|
Packit |
577717 |
for(i=31; i < 64; i++)
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmds, i);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
switch(cpu_model) {
|
|
Packit |
577717 |
case 46:
|
|
Packit |
577717 |
num_pe = PME_COREI7_EVENT_COUNT;
|
|
Packit |
577717 |
num_unc_pe = 0;
|
|
Packit |
577717 |
pe = corei7_pe;
|
|
Packit |
577717 |
unc_pe = NULL;
|
|
Packit |
577717 |
pme_cycles = PME_COREI7_UNHALTED_CORE_CYCLES;
|
|
Packit |
577717 |
pme_instr = PME_COREI7_INSTRUCTIONS_RETIRED;
|
|
Packit |
577717 |
num_unc_cnt = 0;
|
|
Packit |
577717 |
fixup_mem_uncore_retired();
|
|
Packit |
577717 |
supp = &intel_nhm_support;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 26: /* Nehalem */
|
|
Packit |
577717 |
case 30: /* Lynnfield */
|
|
Packit |
577717 |
num_pe = PME_COREI7_EVENT_COUNT;
|
|
Packit |
577717 |
num_unc_pe = PME_COREI7_UNC_EVENT_COUNT;
|
|
Packit |
577717 |
pe = corei7_pe;
|
|
Packit |
577717 |
unc_pe = corei7_unc_pe;
|
|
Packit |
577717 |
pme_cycles = PME_COREI7_UNHALTED_CORE_CYCLES;
|
|
Packit |
577717 |
pme_instr = PME_COREI7_INSTRUCTIONS_RETIRED;
|
|
Packit |
577717 |
setup_nhm_impl_unc_regs();
|
|
Packit |
577717 |
num_unc_cnt = 9; /* one fixed + 8 generic */
|
|
Packit |
577717 |
supp = &intel_nhm_support;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 37: /* Westmere */
|
|
Packit |
577717 |
case 44:
|
|
Packit |
577717 |
num_pe = PME_WSM_EVENT_COUNT;
|
|
Packit |
577717 |
num_unc_pe = PME_WSM_UNC_EVENT_COUNT;
|
|
Packit |
577717 |
pe = wsm_pe;
|
|
Packit |
577717 |
unc_pe = intel_wsm_unc_pe;
|
|
Packit |
577717 |
pme_cycles = PME_WSM_UNHALTED_CORE_CYCLES;
|
|
Packit |
577717 |
pme_instr = PME_WSM_INSTRUCTIONS_RETIRED;
|
|
Packit |
577717 |
setup_nhm_impl_unc_regs();
|
|
Packit |
577717 |
num_unc_cnt = 9; /* one fixed + 8 generic */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* OFFCORE_RESPONSE_1 */
|
|
Packit |
577717 |
pfm_regmask_set(&nhm_impl_pmcs, 31);
|
|
Packit |
577717 |
supp = &intel_wsm_support;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
supp->pme_count = num_pe + num_unc_pe;
|
|
Packit |
577717 |
supp->num_cnt = NHM_NUM_GEN_COUNTERS
|
|
Packit |
577717 |
+ NHM_NUM_FIXED_COUNTERS
|
|
Packit |
577717 |
+ num_unc_cnt;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* propagate uncore registers to impl bitmaps
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
pfm_regmask_or(&nhm_impl_pmds, &nhm_impl_pmds, &nhm_impl_unc_pmds);
|
|
Packit |
577717 |
pfm_regmask_or(&nhm_impl_pmcs, &nhm_impl_pmcs, &nhm_impl_unc_pmcs);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* compute number of registers available
|
|
Packit |
577717 |
* not all CPUs may have uncore
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
pfm_regmask_weight(&nhm_impl_pmds, &supp->pmd_count);
|
|
Packit |
577717 |
pfm_regmask_weight(&nhm_impl_pmcs, &supp->pmc_count);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_is_fixed(pfmlib_event_t *e, unsigned int f)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pme_nhm_entry_t *ne;
|
|
Packit |
577717 |
unsigned int fl, flc, i;
|
|
Packit |
577717 |
unsigned int mask = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(e->event);
|
|
Packit |
577717 |
fl = ne->pme_flags;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* first pass: check if event as a whole supports fixed counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
switch(f) {
|
|
Packit |
577717 |
case 0:
|
|
Packit |
577717 |
mask = PFMLIB_NHM_FIXED0;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 1:
|
|
Packit |
577717 |
mask = PFMLIB_NHM_FIXED1;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 2:
|
|
Packit |
577717 |
mask = PFMLIB_NHM_FIXED2_ONLY;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
default:
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (fl & mask)
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* second pass: check if unit mask supports fixed counter
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* reject if mask not found OR if not all unit masks have
|
|
Packit |
577717 |
* same fixed counter mask
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
flc = 0;
|
|
Packit |
577717 |
for(i=0; i < e->num_masks; i++) {
|
|
Packit |
577717 |
int midx = pfm_nhm_midx2uidx(e->event, e->unit_masks[i]);
|
|
Packit |
577717 |
fl = ne->pme_umasks[midx].pme_uflags;
|
|
Packit |
577717 |
if (fl & mask)
|
|
Packit |
577717 |
flc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return flc > 0 && flc == e->num_masks ? 1 : 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Allow combination of events when cnt_mask > 0 AND unit mask codes do
|
|
Packit |
577717 |
* not overlap (otherwise, we do not know what is actually measured)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_check_cmask(pfmlib_event_t *e, pme_nhm_entry_t *ne, pfmlib_nhm_counter_t *cntr)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
unsigned int ref, ucode;
|
|
Packit |
577717 |
int i, j;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!cntr)
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cntr->cnt_mask == 0)
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < e->num_masks; i++) {
|
|
Packit |
577717 |
int midx = pfm_nhm_midx2uidx(e->event, e->unit_masks[i]);
|
|
Packit |
577717 |
ref = ne->pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
for(j=i+1; j < e->num_masks; j++) {
|
|
Packit |
577717 |
midx = pfm_nhm_midx2uidx(e->event, e->unit_masks[j]);
|
|
Packit |
577717 |
ucode = ne->pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
if (ref & ucode)
|
|
Packit |
577717 |
return -1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* IMPORTANT: the interface guarantees that pfp_pmds[] elements are returned in the order the events
|
|
Packit |
577717 |
* were submitted.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_dispatch_counters(pfmlib_input_param_t *inp, pfmlib_nhm_input_param_t *param, pfmlib_output_param_t *outp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
#define HAS_OPTIONS(x) (cntrs && (cntrs[x].flags || cntrs[x].cnt_mask))
|
|
Packit |
577717 |
#define is_fixed_pmc(a) (a == 16 || a == 17 || a == 18)
|
|
Packit |
577717 |
#define is_uncore(a) (a > 19)
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pme_nhm_entry_t *ne;
|
|
Packit |
577717 |
pfmlib_nhm_counter_t *cntrs;
|
|
Packit |
577717 |
pfm_nhm_sel_reg_t reg;
|
|
Packit |
577717 |
pfmlib_event_t *e;
|
|
Packit |
577717 |
pfmlib_reg_t *pc, *pd;
|
|
Packit |
577717 |
pfmlib_regmask_t *r_pmcs;
|
|
Packit |
577717 |
uint64_t val, unc_global_ctrl;
|
|
Packit |
577717 |
uint64_t pebs_mask, ld_mask;
|
|
Packit |
577717 |
unsigned long long fixed_ctr;
|
|
Packit |
577717 |
unsigned int plm;
|
|
Packit |
577717 |
unsigned int npc, npmc0, npmc01, nf2, nuf;
|
|
Packit |
577717 |
unsigned int i, n, k, j, umask, use_pebs = 0;
|
|
Packit |
577717 |
unsigned int assign_pc[PMU_NHM_NUM_COUNTERS];
|
|
Packit |
577717 |
unsigned int next_gen, last_gen, u_flags;
|
|
Packit |
577717 |
unsigned int next_unc_gen, last_unc_gen, lat;
|
|
Packit |
577717 |
unsigned int offcore_rsp0_value = 0;
|
|
Packit |
577717 |
unsigned int offcore_rsp1_value = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
npc = npmc01 = npmc0 = nf2 = nuf = 0;
|
|
Packit |
577717 |
unc_global_ctrl = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
e = inp->pfp_events;
|
|
Packit |
577717 |
pc = outp->pfp_pmcs;
|
|
Packit |
577717 |
pd = outp->pfp_pmds;
|
|
Packit |
577717 |
n = inp->pfp_event_count;
|
|
Packit |
577717 |
r_pmcs = &inp->pfp_unavail_pmcs;
|
|
Packit |
577717 |
cntrs = param ? param->pfp_nhm_counters : NULL;
|
|
Packit |
577717 |
pebs_mask = ld_mask = 0;
|
|
Packit |
577717 |
use_pebs = param ? param->pfp_nhm_pebs.pebs_used : 0;
|
|
Packit |
577717 |
lat = param ? param->pfp_nhm_pebs.ld_lat_thres : 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (n > PMU_NHM_NUM_COUNTERS)
|
|
Packit |
577717 |
return PFMLIB_ERR_TOOMANY;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* error checking
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* only supports two priv levels for perf counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (e[i].plm & (PFM_PLM1|PFM_PLM2))
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(e[i].event);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* check for erratum AAJ80 */
|
|
Packit |
577717 |
if (aaj80 && (ne->pme_code & 0xff) == 0xc5) {
|
|
Packit |
577717 |
DPRINT("MISPREDICTED_BRANCH_RETIRED broken on this Nehalem processor, see eeratum AAJ80\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOTSUPP;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check for valid flags
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (e[i].flags & ~PFMLIB_NHM_ALL_FLAGS)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_UMASK_NCOMBO
|
|
Packit |
577717 |
&& e[i].num_masks > 1 && pfm_nhm_check_cmask(e, ne, cntrs ? cntrs+i : NULL)) {
|
|
Packit |
577717 |
DPRINT("events does not support unit mask combination\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check event-level single register constraint for uncore fixed
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_UNC_FIXED) {
|
|
Packit |
577717 |
if (++nuf > 1) {
|
|
Packit |
577717 |
DPRINT("two events compete for a UNCORE_FIXED_CTR0\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (HAS_OPTIONS(i)) {
|
|
Packit |
577717 |
DPRINT("uncore fixed counter does not support options\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_PMC0) {
|
|
Packit |
577717 |
if (++npmc0 > 1) {
|
|
Packit |
577717 |
DPRINT("two events compete for a PMC0\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check event-level single register constraint (PMC0/1 only)
|
|
Packit |
577717 |
* fail if more than two events requested for the same counter pair
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_PMC01) {
|
|
Packit |
577717 |
if (++npmc01 > 2) {
|
|
Packit |
577717 |
DPRINT("two events compete for a PMC0\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* UNHALTED_REFERENCE_CYCLES (CPU_CLK_UNHALTED:BUS)
|
|
Packit |
577717 |
* can only be measured on FIXED_CTR2
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_FIXED2_ONLY) {
|
|
Packit |
577717 |
if (++nf2 > 1) {
|
|
Packit |
577717 |
DPRINT("two events compete for FIXED_CTR2\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (cntrs && ((cntrs[i].flags & (PFM_NHM_SEL_INV|PFM_NHM_SEL_EDGE)) || cntrs[i].cnt_mask)) {
|
|
Packit |
577717 |
DPRINT("UNHALTED_REFERENCE_CYCLES only accepts anythr filter\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* OFFCORE_RSP0 is shared, unit masks for all offcore_response events
|
|
Packit |
577717 |
* must be identical
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
umask = 0;
|
|
Packit |
577717 |
for(j=0; j < e[i].num_masks; j++) {
|
|
Packit |
577717 |
int midx = pfm_nhm_midx2uidx(e[i].event, e[i].unit_masks[j]);
|
|
Packit |
577717 |
umask |= ne->pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_OFFCORE_RSP0) {
|
|
Packit |
577717 |
if (offcore_rsp0_value && offcore_rsp0_value != umask) {
|
|
Packit |
577717 |
DPRINT("all OFFCORE_RSP0 events must have the same unit mask\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (pfm_regmask_isset(r_pmcs, 19)) {
|
|
Packit |
577717 |
DPRINT("OFFCORE_RSP0 register not available\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!((umask & 0xff) && (umask & 0xff00))) {
|
|
Packit |
577717 |
DPRINT("OFFCORE_RSP0 must have at least one request and response unit mask set\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* lock-in offcore_value */
|
|
Packit |
577717 |
offcore_rsp0_value = umask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_OFFCORE_RSP1) {
|
|
Packit |
577717 |
if (offcore_rsp1_value && offcore_rsp1_value != umask) {
|
|
Packit |
577717 |
DPRINT("all OFFCORE_RSP1 events must have the same unit mask\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (pfm_regmask_isset(r_pmcs, 31)) {
|
|
Packit |
577717 |
DPRINT("OFFCORE_RSP1 register not available\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!((umask & 0xff) && (umask & 0xff00))) {
|
|
Packit |
577717 |
DPRINT("OFFCORE_RSP1 must have at least one request and response unit mask set\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/* lock-in offcore_value */
|
|
Packit |
577717 |
offcore_rsp1_value = umask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* enforce PLM0|PLM3 for uncore events given they have no
|
|
Packit |
577717 |
* priv level filter. This is to ensure users understand what
|
|
Packit |
577717 |
* they are doing
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (ne->pme_flags & (PFMLIB_NHM_UNC|PFMLIB_NHM_UNC_FIXED)) {
|
|
Packit |
577717 |
if (inp->pfp_dfl_plm != (PFM_PLM0|PFM_PLM3)
|
|
Packit |
577717 |
&& e[i].plm != (PFM_PLM0|PFM_PLM3)) {
|
|
Packit |
577717 |
DPRINT("uncore events must have PLM0|PLM3\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* initilize to empty
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for(i=0; i < PMU_NHM_NUM_COUNTERS; i++)
|
|
Packit |
577717 |
assign_pc[i] = -1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
|
|
Packit |
577717 |
next_gen = 0; /* first generic counter */
|
|
Packit |
577717 |
last_gen = 3; /* last generic counter */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* strongest constraint: only uncore_fixed_ctr0 or PMC0 only
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (nuf || npmc0) {
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
ne = get_nhm_entry(e[i].event);
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_PMC0) {
|
|
Packit |
577717 |
if (pfm_regmask_isset(r_pmcs, 0))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
assign_pc[i] = 0;
|
|
Packit |
577717 |
next_gen = 1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_UNC_FIXED) {
|
|
Packit |
577717 |
if (pfm_regmask_isset(r_pmcs, 20))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
assign_pc[i] = 20;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* 2nd strongest constraint first: works only on PMC0 or PMC1
|
|
Packit |
577717 |
* On Nehalem, this constraint applies at the event-level
|
|
Packit |
577717 |
* (not unit mask level, fortunately)
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* PEBS works on all 4 generic counters
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* Because of sanity check above, we know we can find
|
|
Packit |
577717 |
* only up to 2 events with this constraint
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (npmc01) {
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
ne = get_nhm_entry(e[i].event);
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_PMC01) {
|
|
Packit |
577717 |
while (next_gen < 2 && pfm_regmask_isset(r_pmcs, next_gen))
|
|
Packit |
577717 |
next_gen++;
|
|
Packit |
577717 |
if (next_gen == 2)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
assign_pc[i] = next_gen++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* next constraint: fixed counters
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* We abuse the mapping here for assign_pc to make it easier
|
|
Packit |
577717 |
* to provide the correct values for pd[].
|
|
Packit |
577717 |
* We use:
|
|
Packit |
577717 |
* - 16 : fixed counter 0 (pmc16, pmd16)
|
|
Packit |
577717 |
* - 17 : fixed counter 1 (pmc16, pmd17)
|
|
Packit |
577717 |
* - 18 : fixed counter 2 (pmc16, pmd18)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
fixed_ctr = pfm_regmask_isset(r_pmcs, 16) ? 0 : 0x7;
|
|
Packit |
577717 |
if (fixed_ctr) {
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Nehalem fixed counters (as for architected perfmon v3)
|
|
Packit |
577717 |
* does support anythr filter
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (HAS_OPTIONS(i)) {
|
|
Packit |
577717 |
if (use_pebs && pfm_nhm_is_pebs(e+i))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cntrs[i].flags != PFM_NHM_SEL_ANYTHR)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if ((fixed_ctr & 0x1) && pfm_nhm_is_fixed(e+i, 0)) {
|
|
Packit |
577717 |
assign_pc[i] = 16;
|
|
Packit |
577717 |
fixed_ctr &= ~1;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if ((fixed_ctr & 0x2) && pfm_nhm_is_fixed(e+i, 1)) {
|
|
Packit |
577717 |
assign_pc[i] = 17;
|
|
Packit |
577717 |
fixed_ctr &= ~2;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if ((fixed_ctr & 0x4) && pfm_nhm_is_fixed(e+i, 2)) {
|
|
Packit |
577717 |
assign_pc[i] = 18;
|
|
Packit |
577717 |
fixed_ctr &= ~4;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* uncore events on any of the 8 counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
next_unc_gen = 21; /* first generic uncore counter config */
|
|
Packit |
577717 |
last_unc_gen = 28; /* last generic uncore counter config */
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
ne = get_nhm_entry(e[i].event);
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_UNC) {
|
|
Packit |
577717 |
for(; next_unc_gen <= last_unc_gen; next_unc_gen++) {
|
|
Packit |
577717 |
if (!pfm_regmask_isset(r_pmcs, next_unc_gen))
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (next_unc_gen <= last_unc_gen)
|
|
Packit |
577717 |
assign_pc[i] = next_unc_gen++;
|
|
Packit |
577717 |
else {
|
|
Packit |
577717 |
DPRINT("cannot assign generic uncore event\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* assign what is left of the generic events
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for(i=0; i < n; i++) {
|
|
Packit |
577717 |
if (assign_pc[i] == -1) {
|
|
Packit |
577717 |
for(; next_gen <= last_gen; next_gen++) {
|
|
Packit |
577717 |
DPRINT("i=%d next_gen=%d last=%d isset=%d\n", i, next_gen, last_gen, pfm_regmask_isset(r_pmcs, next_gen));
|
|
Packit |
577717 |
if (!pfm_regmask_isset(r_pmcs, next_gen))
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (next_gen <= last_gen) {
|
|
Packit |
577717 |
assign_pc[i] = next_gen++;
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
DPRINT("cannot assign generic event\n");
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup core fixed counters
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
reg.val = 0;
|
|
Packit |
577717 |
for (i=0; i < n ; i++ ) {
|
|
Packit |
577717 |
if (!is_fixed_pmc(assign_pc[i]))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
val = 0;
|
|
Packit |
577717 |
/* if plm is 0, then assume not specified per-event and use default */
|
|
Packit |
577717 |
plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
|
|
Packit |
577717 |
if (plm & PFM_PLM0)
|
|
Packit |
577717 |
val |= 1ULL;
|
|
Packit |
577717 |
if (plm & PFM_PLM3)
|
|
Packit |
577717 |
val |= 2ULL;
|
|
Packit |
577717 |
if (cntrs && cntrs[i].flags & PFM_NHM_SEL_ANYTHR)
|
|
Packit |
577717 |
val |= 4ULL;
|
|
Packit |
577717 |
val |= 1ULL << 3; /* force APIC int (kernel may force it anyway) */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.val |= val << ((assign_pc[i]-16)<<2);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (reg.val) {
|
|
Packit |
577717 |
pc[npc].reg_num = 16;
|
|
Packit |
577717 |
pc[npc].reg_value = reg.val;
|
|
Packit |
577717 |
pc[npc].reg_addr = 0x38D;
|
|
Packit |
577717 |
pc[npc].reg_alt_addr = 0x38D;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[FIXED_CTRL(pmc%u)=0x%"PRIx64" pmi0=1 en0=0x%"PRIx64" any0=%d pmi1=1 en1=0x%"PRIx64" any1=%d pmi2=1 en2=0x%"PRIx64" any2=%d] ",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
reg.val,
|
|
Packit |
577717 |
reg.val & 0x3ULL,
|
|
Packit |
577717 |
!!(reg.val & 0x4ULL),
|
|
Packit |
577717 |
(reg.val>>4) & 0x3ULL,
|
|
Packit |
577717 |
!!((reg.val>>4) & 0x4ULL),
|
|
Packit |
577717 |
(reg.val>>8) & 0x3ULL,
|
|
Packit |
577717 |
!!((reg.val>>8) & 0x4ULL));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if ((fixed_ctr & 0x1) == 0)
|
|
Packit |
577717 |
__pfm_vbprintf("INSTRUCTIONS_RETIRED ");
|
|
Packit |
577717 |
if ((fixed_ctr & 0x2) == 0)
|
|
Packit |
577717 |
__pfm_vbprintf("UNHALTED_CORE_CYCLES ");
|
|
Packit |
577717 |
if ((fixed_ctr & 0x4) == 0)
|
|
Packit |
577717 |
__pfm_vbprintf("UNHALTED_REFERENCE_CYCLES ");
|
|
Packit |
577717 |
__pfm_vbprintf("\n");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if ((fixed_ctr & 0x1) == 0)
|
|
Packit |
577717 |
__pfm_vbprintf("[FIXED_CTR0(pmd16)]\n");
|
|
Packit |
577717 |
if ((fixed_ctr & 0x2) == 0)
|
|
Packit |
577717 |
__pfm_vbprintf("[FIXED_CTR1(pmd17)]\n");
|
|
Packit |
577717 |
if ((fixed_ctr & 0x4) == 0)
|
|
Packit |
577717 |
__pfm_vbprintf("[FIXED_CTR2(pmd18)]\n");
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup core counter config
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (i=0; i < n ; i++ ) {
|
|
Packit |
577717 |
/* skip fixed counters */
|
|
Packit |
577717 |
if (is_fixed_pmc(assign_pc[i]) || is_uncore(assign_pc[i]))
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.val = 0; /* assume reserved bits are zeroed */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* if plm is 0, then assume not specified per-event and use default */
|
|
Packit |
577717 |
plm = e[i].plm ? e[i].plm : inp->pfp_dfl_plm;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(e[i].event);
|
|
Packit |
577717 |
val = ne->pme_code;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.sel_event = val & 0xff;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
umask = (val >> 8) & 0xff;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
u_flags = 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* for OFFCORE_RSP, the unit masks are all in the
|
|
Packit |
577717 |
* dedicated OFFCORE_RSP MSRs and event unit mask must be
|
|
Packit |
577717 |
* 0x1 (extracted from pme_code)
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (!(ne->pme_flags & (PFMLIB_NHM_OFFCORE_RSP0|PFMLIB_NHM_OFFCORE_RSP1)))
|
|
Packit |
577717 |
for(k=0; k < e[i].num_masks; k++) {
|
|
Packit |
577717 |
int midx = pfm_nhm_midx2uidx(e[i].event, e[i].unit_masks[k]);
|
|
Packit |
577717 |
umask |= ne->pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
u_flags |= ne->pme_umasks[midx].pme_uflags;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
val |= umask << 8;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.sel_umask = umask;
|
|
Packit |
577717 |
reg.sel_usr = plm & PFM_PLM3 ? 1 : 0;
|
|
Packit |
577717 |
reg.sel_os = plm & PFM_PLM0 ? 1 : 0;
|
|
Packit |
577717 |
reg.sel_en = 1; /* force enable bit to 1 */
|
|
Packit |
577717 |
reg.sel_int = 1; /* force APIC int to 1 */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.sel_cnt_mask = val >>24;
|
|
Packit |
577717 |
reg.sel_inv = val >> 23;
|
|
Packit |
577717 |
reg.sel_anythr = val >> 21;
|
|
Packit |
577717 |
reg.sel_edge = val >> 18;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cntrs) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* occupancy reset flag is for uncore counters only
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (cntrs[i].flags & PFM_NHM_SEL_OCC_RST)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!reg.sel_cnt_mask) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* counter mask is 8-bit wide, do not silently
|
|
Packit |
577717 |
* wrap-around
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (cntrs[i].cnt_mask > 255)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.sel_cnt_mask = cntrs[i].cnt_mask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!reg.sel_edge)
|
|
Packit |
577717 |
reg.sel_edge = cntrs[i].flags & PFM_NHM_SEL_EDGE ? 1 : 0;
|
|
Packit |
577717 |
if (!reg.sel_inv)
|
|
Packit |
577717 |
reg.sel_inv = cntrs[i].flags & PFM_NHM_SEL_INV ? 1 : 0;
|
|
Packit |
577717 |
if (!reg.sel_anythr)
|
|
Packit |
577717 |
reg.sel_anythr = cntrs[i].flags & PFM_NHM_SEL_ANYTHR ? 1 : 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (u_flags || (ne->pme_flags & PFMLIB_NHM_PEBS))
|
|
Packit |
577717 |
pebs_mask |= 1ULL << assign_pc[i];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check for MEM_INST_RETIRED:LATENCY_ABOVE_THRESHOLD_0 to enable load latency filtering
|
|
Packit |
577717 |
* when PEBS is used. There is only one threshold possible, yet mutliple counters may be
|
|
Packit |
577717 |
* programmed with this event/umask. That means they all share the same threshold.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (reg.sel_event == 0xb && (umask & 0x10))
|
|
Packit |
577717 |
ld_mask |= 1ULL << assign_pc[i];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pc[npc].reg_num = assign_pc[i];
|
|
Packit |
577717 |
pc[npc].reg_value = reg.val;
|
|
Packit |
577717 |
pc[npc].reg_addr = NHM_SEL_BASE+assign_pc[i];
|
|
Packit |
577717 |
pc[npc].reg_alt_addr= NHM_SEL_BASE+assign_pc[i];
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[PERFEVTSEL%u(pmc%u)=0x%"PRIx64" event_sel=0x%x umask=0x%x os=%d usr=%d anythr=%d en=%d int=%d inv=%d edge=%d cnt_mask=%d] %s\n",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
reg.val,
|
|
Packit |
577717 |
reg.sel_event,
|
|
Packit |
577717 |
reg.sel_umask,
|
|
Packit |
577717 |
reg.sel_os,
|
|
Packit |
577717 |
reg.sel_usr,
|
|
Packit |
577717 |
reg.sel_anythr,
|
|
Packit |
577717 |
reg.sel_en,
|
|
Packit |
577717 |
reg.sel_int,
|
|
Packit |
577717 |
reg.sel_inv,
|
|
Packit |
577717 |
reg.sel_edge,
|
|
Packit |
577717 |
reg.sel_cnt_mask,
|
|
Packit |
577717 |
ne->pme_name);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[PMC%u(pmd%u)]\n",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
pc[npc].reg_num);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup uncore fixed counter config
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (nuf) {
|
|
Packit |
577717 |
pc[npc].reg_num = 20;
|
|
Packit |
577717 |
pc[npc].reg_value = 0x5ULL; /* ena=1, PMI=dtermined by kernel */
|
|
Packit |
577717 |
pc[npc].reg_addr = 0x395;
|
|
Packit |
577717 |
pc[npc].reg_alt_addr = 0x395;
|
|
Packit |
577717 |
__pfm_vbprintf("[UNC_FIXED_CTRL(pmc20)=0x%"PRIx64" pmi=1 ena=1] UNC_CLK_UNHALTED\n", pc[npc].reg_value);
|
|
Packit |
577717 |
__pfm_vbprintf("[UNC_FIXED_CTR0(pmd20)]\n");
|
|
Packit |
577717 |
unc_global_ctrl |= 1ULL<< 32;
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup uncore counter config
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (i=0; i < n ; i++ ) {
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* skip core counters, uncore fixed */
|
|
Packit |
577717 |
if (!is_uncore(assign_pc[i]) || assign_pc[i] == 20)
|
|
Packit |
577717 |
continue;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.val = 0; /* assume reserved bits are zerooed */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(e[i].event);
|
|
Packit |
577717 |
val = ne->pme_code;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.usel_event = val & 0xff;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
umask = (val >> 8) & 0xff;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(k=0; k < e[i].num_masks; k++) {
|
|
Packit |
577717 |
int midx = pfm_nhm_midx2uidx(e[i].event, e[i].unit_masks[k]);
|
|
Packit |
577717 |
umask |= ne->pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
val |= umask << 8;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.usel_umask = umask;
|
|
Packit |
577717 |
reg.usel_en = 1; /* force enable bit to 1 */
|
|
Packit |
577717 |
reg.usel_int = 1; /* force APIC int to 1 */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* allow hardcoded filters in event table
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
reg.usel_cnt_mask = val >>24;
|
|
Packit |
577717 |
reg.usel_inv = val >> 23;
|
|
Packit |
577717 |
reg.usel_edge = val >> 18;
|
|
Packit |
577717 |
reg.usel_occ = val >> 17;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cntrs) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* anythread if for core counters only
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (cntrs[i].flags & PFM_NHM_SEL_ANYTHR)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!reg.usel_cnt_mask) {
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* counter mask is 8-bit wide, do not silently
|
|
Packit |
577717 |
* wrap-around
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (cntrs[i].cnt_mask > 255)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.usel_cnt_mask = cntrs[i].cnt_mask;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
if (!reg.usel_edge)
|
|
Packit |
577717 |
reg.usel_edge = cntrs[i].flags & PFM_NHM_SEL_EDGE ? 1 : 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!reg.usel_inv)
|
|
Packit |
577717 |
reg.usel_inv = cntrs[i].flags & PFM_NHM_SEL_INV ? 1 : 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (!reg.usel_occ)
|
|
Packit |
577717 |
reg.usel_occ = cntrs[i].flags & PFM_NHM_SEL_OCC_RST ? 1 : 0;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
unc_global_ctrl |= 1ULL<< (assign_pc[i] - 21);
|
|
Packit |
577717 |
pc[npc].reg_num = assign_pc[i];
|
|
Packit |
577717 |
pc[npc].reg_value = reg.val;
|
|
Packit |
577717 |
pc[npc].reg_addr = UNC_NHM_SEL_BASE+assign_pc[i] - 21;
|
|
Packit |
577717 |
pc[npc].reg_alt_addr= UNC_NHM_SEL_BASE+assign_pc[i] - 21;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[UNC_PERFEVTSEL%u(pmc%u)=0x%"PRIx64" event=0x%x umask=0x%x en=%d int=%d inv=%d edge=%d occ=%d cnt_msk=%d] %s\n",
|
|
Packit |
577717 |
pc[npc].reg_num - 21,
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
reg.val,
|
|
Packit |
577717 |
reg.usel_event,
|
|
Packit |
577717 |
reg.usel_umask,
|
|
Packit |
577717 |
reg.usel_en,
|
|
Packit |
577717 |
reg.usel_int,
|
|
Packit |
577717 |
reg.usel_inv,
|
|
Packit |
577717 |
reg.usel_edge,
|
|
Packit |
577717 |
reg.usel_occ,
|
|
Packit |
577717 |
reg.usel_cnt_mask,
|
|
Packit |
577717 |
ne->pme_name);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[UNC_PMC%u(pmd%u)]\n",
|
|
Packit |
577717 |
pc[npc].reg_num - 21,
|
|
Packit |
577717 |
pc[npc].reg_num);
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup pmds: must be in the same order as the events
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (i=0; i < n ; i++) {
|
|
Packit |
577717 |
switch (assign_pc[i]) {
|
|
Packit |
577717 |
case 0 ... 4:
|
|
Packit |
577717 |
pd[i].reg_num = assign_pc[i];
|
|
Packit |
577717 |
pd[i].reg_addr = NHM_CTR_BASE+assign_pc[i];
|
|
Packit |
577717 |
/* index to use with RDPMC */
|
|
Packit |
577717 |
pd[i].reg_alt_addr = assign_pc[i];
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 16 ... 18:
|
|
Packit |
577717 |
/* setup pd array */
|
|
Packit |
577717 |
pd[i].reg_num = assign_pc[i];
|
|
Packit |
577717 |
pd[i].reg_addr = NHM_FIXED_CTR_BASE+assign_pc[i]-16;
|
|
Packit |
577717 |
pd[i].reg_alt_addr = 0x40000000+assign_pc[i]-16;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 20:
|
|
Packit |
577717 |
pd[i].reg_num = 20;
|
|
Packit |
577717 |
pd[i].reg_addr = UNC_NHM_FIXED_CTR_BASE;
|
|
Packit |
577717 |
pd[i].reg_alt_addr = UNC_NHM_FIXED_CTR_BASE;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
case 21 ... 28:
|
|
Packit |
577717 |
pd[i].reg_num = assign_pc[i];
|
|
Packit |
577717 |
pd[i].reg_addr = UNC_NHM_CTR_BASE + assign_pc[i] - 21;
|
|
Packit |
577717 |
pd[i].reg_alt_addr = UNC_NHM_CTR_BASE + assign_pc[i] - 21;
|
|
Packit |
577717 |
break;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
outp->pfp_pmd_count = i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup PEBS_ENABLE
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (use_pebs && pebs_mask) {
|
|
Packit |
577717 |
if (!lat)
|
|
Packit |
577717 |
ld_mask = 0;
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check that PEBS_ENABLE is available
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (pfm_regmask_isset(r_pmcs, 17))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pc[npc].reg_num = 17;
|
|
Packit |
577717 |
pc[npc].reg_value = pebs_mask | (ld_mask <<32);
|
|
Packit |
577717 |
pc[npc].reg_addr = 0x3f1; /* IA32_PEBS_ENABLE */
|
|
Packit |
577717 |
pc[npc].reg_alt_addr = 0x3f1; /* IA32_PEBS_ENABLE */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[PEBS_ENABLE(pmc%u)=0x%"PRIx64" ena0=%d ena1=%d ena2=%d ena3=%d ll0=%d ll1=%d ll2=%d ll3=%d]\n",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
pc[npc].reg_value,
|
|
Packit |
577717 |
pc[npc].reg_value & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 1) & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 2) & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 3) & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 32) & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 33) & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 34) & 0x1,
|
|
Packit |
577717 |
(pc[npc].reg_value >> 35) & 0x1);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ld_mask) {
|
|
Packit |
577717 |
if (lat < 3 || lat > 0xffff) {
|
|
Packit |
577717 |
DPRINT("invalid load latency threshold %u (must be in [3:0xffff])\n", lat);
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (pfm_regmask_isset(r_pmcs, 18))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pc[npc].reg_num = 18;
|
|
Packit |
577717 |
pc[npc].reg_value = lat;
|
|
Packit |
577717 |
pc[npc].reg_addr = 0x3f1; /* IA32_PEBS_ENABLE */
|
|
Packit |
577717 |
pc[npc].reg_alt_addr = 0x3f1; /* IA32_PEBS_ENABLE */
|
|
Packit |
577717 |
__pfm_vbprintf("[LOAD_LATENCY_THRESHOLD(pmc%u)=0x%"PRIx64"]\n",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
pc[npc].reg_value);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup OFFCORE_RSP0
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (offcore_rsp0_value) {
|
|
Packit |
577717 |
pc[npc].reg_num = 19;
|
|
Packit |
577717 |
pc[npc].reg_value = offcore_rsp0_value;
|
|
Packit |
577717 |
pc[npc].reg_addr = 0x1a6;
|
|
Packit |
577717 |
pc[npc].reg_alt_addr = 0x1a6;
|
|
Packit |
577717 |
__pfm_vbprintf("[OFFCORE_RSP0(pmc%u)=0x%"PRIx64"]\n",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
pc[npc].reg_value);
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* setup OFFCORE_RSP1
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (offcore_rsp1_value) {
|
|
Packit |
577717 |
pc[npc].reg_num = 31;
|
|
Packit |
577717 |
pc[npc].reg_value = offcore_rsp1_value;
|
|
Packit |
577717 |
pc[npc].reg_addr = 0x1a7;
|
|
Packit |
577717 |
pc[npc].reg_alt_addr = 0x1a7;
|
|
Packit |
577717 |
__pfm_vbprintf("[OFFCORE_RSP1(pmc%u)=0x%"PRIx64"]\n",
|
|
Packit |
577717 |
pc[npc].reg_num,
|
|
Packit |
577717 |
pc[npc].reg_value);
|
|
Packit |
577717 |
npc++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
outp->pfp_pmc_count = npc;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_dispatch_lbr(pfmlib_input_param_t *inp, pfmlib_nhm_input_param_t *param, pfmlib_output_param_t *outp)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
static int lbr_plm_map[4]={
|
|
Packit |
577717 |
0x3, /* PLM0=0 PLM3=0 neq0=1 eq0=1 */
|
|
Packit |
577717 |
0x1, /* PLM0=0 PLM3=1 neq0=0 eq0=1 */
|
|
Packit |
577717 |
0x2, /* PLM0=1 PLM3=0 neq0=1 eq0=0 */
|
|
Packit |
577717 |
0x0 /* PLM0=1 PLM3=1 neq0=0 eq0=0 */
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
pfm_nhm_sel_reg_t reg;
|
|
Packit |
577717 |
unsigned int filter, i, c;
|
|
Packit |
577717 |
unsigned int plm;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* check LBR_SELECT is available
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (pfm_regmask_isset(&inp->pfp_unavail_pmcs, 30))
|
|
Packit |
577717 |
return PFMLIB_ERR_NOASSIGN;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
reg.val = 0; /* capture everything */
|
|
Packit |
577717 |
|
|
Packit |
577717 |
plm = param->pfp_nhm_lbr.lbr_plm;
|
|
Packit |
577717 |
if (!plm)
|
|
Packit |
577717 |
plm = inp->pfp_dfl_plm;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* LBR does not distinguish PLM1, PLM2 from PLM3
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
i = plm & PFM_PLM0 ? 0x2 : 0;
|
|
Packit |
577717 |
i |= plm & PFM_PLM3 ? 0x1 : 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (lbr_plm_map[i] & 0x1)
|
|
Packit |
577717 |
reg.lbr_select.cpl_eq0 = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (lbr_plm_map[i] & 0x2)
|
|
Packit |
577717 |
reg.lbr_select.cpl_neq0 = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
filter = param->pfp_nhm_lbr.lbr_filter;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_JCC)
|
|
Packit |
577717 |
reg.lbr_select.jcc = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_NEAR_REL_CALL)
|
|
Packit |
577717 |
reg.lbr_select.near_rel_call = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_NEAR_IND_CALL)
|
|
Packit |
577717 |
reg.lbr_select.near_ind_call = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_NEAR_RET)
|
|
Packit |
577717 |
reg.lbr_select.near_ret = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_NEAR_IND_JMP)
|
|
Packit |
577717 |
reg.lbr_select.near_ind_jmp = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_NEAR_REL_JMP)
|
|
Packit |
577717 |
reg.lbr_select.near_rel_jmp = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (filter & PFM_NHM_LBR_FAR_BRANCH)
|
|
Packit |
577717 |
reg.lbr_select.far_branch = 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[LBR_SELECT(PMC30)=0x%"PRIx64" eq0=%d neq0=%d jcc=%d rel=%d ind=%d ret=%d ind_jmp=%d rel_jmp=%d far=%d ]\n",
|
|
Packit |
577717 |
reg.val,
|
|
Packit |
577717 |
reg.lbr_select.cpl_eq0,
|
|
Packit |
577717 |
reg.lbr_select.cpl_neq0,
|
|
Packit |
577717 |
reg.lbr_select.jcc,
|
|
Packit |
577717 |
reg.lbr_select.near_rel_call,
|
|
Packit |
577717 |
reg.lbr_select.near_ind_call,
|
|
Packit |
577717 |
reg.lbr_select.near_ret,
|
|
Packit |
577717 |
reg.lbr_select.near_ind_jmp,
|
|
Packit |
577717 |
reg.lbr_select.near_rel_jmp,
|
|
Packit |
577717 |
reg.lbr_select.far_branch);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[LBR_TOS(PMD31)]\n");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
__pfm_vbprintf("[LBR_FROM-LBR_TO(PMD32..PMD63)]\n");
|
|
Packit |
577717 |
|
|
Packit |
577717 |
c = outp->pfp_pmc_count;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
outp->pfp_pmcs[c].reg_num = 30;
|
|
Packit |
577717 |
outp->pfp_pmcs[c].reg_value = reg.val;
|
|
Packit |
577717 |
outp->pfp_pmcs[c].reg_addr = 0x1c8;
|
|
Packit |
577717 |
outp->pfp_pmcs[c].reg_alt_addr = 0x1c8;
|
|
Packit |
577717 |
c++;
|
|
Packit |
577717 |
outp->pfp_pmc_count = c;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
c = outp->pfp_pmd_count;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_num = 31;
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_value = 0;
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_addr = 0x1c9;
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_alt_addr = 0x1c9;
|
|
Packit |
577717 |
c++;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for(i=0; i < 32; i++, c++) {
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_num = 32 + i;
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_value = 0;
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_addr = (i>>1) + ((i & 0x1) ? 0x6c0 : 0x680);
|
|
Packit |
577717 |
outp->pfp_pmds[c].reg_alt_addr = (i>>1) + ((i & 0x1) ? 0x6c0 : 0x680);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
outp->pfp_pmd_count = c;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_dispatch_events(pfmlib_input_param_t *inp, void *model_in, pfmlib_output_param_t *outp, void *model_out)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_nhm_input_param_t *mod_in = (pfmlib_nhm_input_param_t *)model_in;
|
|
Packit |
577717 |
int ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (inp->pfp_dfl_plm & (PFM_PLM1|PFM_PLM2)) {
|
|
Packit |
577717 |
DPRINT("invalid plm=%x\n", inp->pfp_dfl_plm);
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
ret = pfm_nhm_dispatch_counters(inp, mod_in, outp);
|
|
Packit |
577717 |
if (ret != PFMLIB_SUCCESS)
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (mod_in && mod_in->pfp_nhm_lbr.lbr_used)
|
|
Packit |
577717 |
ret = pfm_nhm_dispatch_lbr(inp, mod_in, outp);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return ret;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_get_event_code(unsigned int i, unsigned int cnt, int *code)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pfmlib_regmask_t cnts;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_get_impl_counters(&cnts);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (cnt != PFMLIB_CNT_FIRST
|
|
Packit |
577717 |
&& (cnt > MAX_COUNTERS ||
|
|
Packit |
577717 |
!pfm_regmask_isset(&cnts, cnt)))
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
*code = get_nhm_entry(i)->pme_code;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_nhm_get_event_counters(unsigned int j, pfmlib_regmask_t *counters)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pme_nhm_entry_t *ne;
|
|
Packit |
577717 |
unsigned int i;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
memset(counters, 0, sizeof(*counters));
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(j);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_UNC_FIXED) {
|
|
Packit |
577717 |
pfm_regmask_set(counters, 20);
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_UNC) {
|
|
Packit |
577717 |
pfm_regmask_set(counters, 20);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 21);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 22);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 23);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 24);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 25);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 26);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 27);
|
|
Packit |
577717 |
return;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* fixed counter events have no unit mask
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_FIXED0)
|
|
Packit |
577717 |
pfm_regmask_set(counters, 16);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_FIXED1)
|
|
Packit |
577717 |
pfm_regmask_set(counters, 17);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_FIXED2_ONLY)
|
|
Packit |
577717 |
pfm_regmask_set(counters, 18);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* extract from unit mask level
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for (i=0; i < ne->pme_numasks; i++) {
|
|
Packit |
577717 |
if (ne->pme_umasks[i].pme_uflags & PFMLIB_NHM_FIXED0)
|
|
Packit |
577717 |
pfm_regmask_set(counters, 16);
|
|
Packit |
577717 |
if (ne->pme_umasks[i].pme_uflags & PFMLIB_NHM_FIXED1)
|
|
Packit |
577717 |
pfm_regmask_set(counters, 17);
|
|
Packit |
577717 |
if (ne->pme_umasks[i].pme_uflags & PFMLIB_NHM_FIXED2_ONLY)
|
|
Packit |
577717 |
pfm_regmask_set(counters, 18);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* event on FIXED_CTR2 is exclusive CPU_CLK_UNHALTED:REF
|
|
Packit |
577717 |
* PMC0|PMC1 only on 0,1, constraint at event-level
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
if (!pfm_regmask_isset(counters, 18)) {
|
|
Packit |
577717 |
pfm_regmask_set(counters, 0);
|
|
Packit |
577717 |
if (!(ne->pme_flags & PFMLIB_NHM_PMC0))
|
|
Packit |
577717 |
pfm_regmask_set(counters, 1);
|
|
Packit |
577717 |
if (!(ne->pme_flags & (PFMLIB_NHM_PMC01|PFMLIB_NHM_PMC0))) {
|
|
Packit |
577717 |
pfm_regmask_set(counters, 2);
|
|
Packit |
577717 |
pfm_regmask_set(counters, 3);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_nhm_get_impl_pmcs(pfmlib_regmask_t *impl_pmcs)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
*impl_pmcs = nhm_impl_pmcs;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_nhm_get_impl_pmds(pfmlib_regmask_t *impl_pmds)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
*impl_pmds = nhm_impl_pmds;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_nhm_get_impl_counters(pfmlib_regmask_t *impl_counters)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/* core generic */
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 0);
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 1);
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 2);
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 3);
|
|
Packit |
577717 |
/* core fixed */
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 16);
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 17);
|
|
Packit |
577717 |
pfm_regmask_set(impl_counters, 18);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/* uncore pmd registers all counters */
|
|
Packit |
577717 |
pfm_regmask_or(impl_counters, impl_counters, &nhm_impl_unc_pmds);
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Even though, CPUID 0xa returns in eax the actual counter
|
|
Packit |
577717 |
* width, the architecture specifies that writes are limited
|
|
Packit |
577717 |
* to lower 32-bits. As such, only the lower 32-bit have full
|
|
Packit |
577717 |
* degree of freedom. That is the "useable" counter width.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
#define PMU_NHM_COUNTER_WIDTH 32
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static void
|
|
Packit |
577717 |
pfm_nhm_get_hw_counter_width(unsigned int *width)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Even though, CPUID 0xa returns in eax the actual counter
|
|
Packit |
577717 |
* width, the architecture specifies that writes are limited
|
|
Packit |
577717 |
* to lower 32-bits. As such, only the lower 31 bits have full
|
|
Packit |
577717 |
* degree of freedom. That is the "useable" counter width.
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
*width = PMU_NHM_COUNTER_WIDTH;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static char *
|
|
Packit |
577717 |
pfm_nhm_get_event_name(unsigned int i)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
return get_nhm_entry(i)->pme_name;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_get_event_description(unsigned int ev, char **str)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
char *s;
|
|
Packit |
577717 |
s = get_nhm_entry(ev)->pme_desc;
|
|
Packit |
577717 |
if (s) {
|
|
Packit |
577717 |
*str = strdup(s);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
*str = NULL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
static char *
|
|
Packit |
577717 |
pfm_nhm_get_event_mask_name(unsigned int ev, unsigned int midx)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
midx = pfm_nhm_midx2uidx(ev, midx);
|
|
Packit |
577717 |
return get_nhm_entry(ev)->pme_umasks[midx].pme_uname;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_get_event_mask_desc(unsigned int ev, unsigned int midx, char **str)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
char *s;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
midx = pfm_nhm_midx2uidx(ev, midx);
|
|
Packit |
577717 |
s = get_nhm_entry(ev)->pme_umasks[midx].pme_udesc;
|
|
Packit |
577717 |
if (s) {
|
|
Packit |
577717 |
*str = strdup(s);
|
|
Packit |
577717 |
} else {
|
|
Packit |
577717 |
*str = NULL;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static unsigned int
|
|
Packit |
577717 |
pfm_nhm_get_num_event_masks(unsigned int ev)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
int i, num = 0;
|
|
Packit |
577717 |
pme_nhm_entry_t *ne;
|
|
Packit |
577717 |
int model;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(ev);
|
|
Packit |
577717 |
|
|
Packit |
577717 |
for (i=0; i < ne->pme_numasks; i++) {
|
|
Packit |
577717 |
model = ne->pme_umasks[i].pme_umodel;
|
|
Packit |
577717 |
if (!model || model == cpu_model)
|
|
Packit |
577717 |
num++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
DPRINT("event %s numasks=%d\n", ne->pme_name, num);
|
|
Packit |
577717 |
return num;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_get_event_mask_code(unsigned int ev, unsigned int midx, unsigned int *code)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
midx = pfm_nhm_midx2uidx(ev, midx);
|
|
Packit |
577717 |
*code =get_nhm_entry(ev)->pme_umasks[midx].pme_ucode;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_get_cycle_event(pfmlib_event_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
e->event = pme_cycles;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static int
|
|
Packit |
577717 |
pfm_nhm_get_inst_retired(pfmlib_event_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
e->event = pme_instr;;
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* the following function implement the model
|
|
Packit |
577717 |
* specific API directly available to user
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Check if event and all provided unit masks support PEBS
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
* return:
|
|
Packit |
577717 |
* PFMLIB_ERR_INVAL: invalid event e
|
|
Packit |
577717 |
* 1 event supports PEBS
|
|
Packit |
577717 |
* 0 event does not support PEBS
|
|
Packit |
577717 |
*
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
pfm_nhm_is_pebs(pfmlib_event_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
pme_nhm_entry_t *ne;
|
|
Packit |
577717 |
unsigned int i, n=0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (e == NULL || e->event >= intel_nhm_support.pme_count)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
ne = get_nhm_entry(e->event);
|
|
Packit |
577717 |
if (ne->pme_flags & PFMLIB_NHM_PEBS)
|
|
Packit |
577717 |
return 1;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* ALL unit mask must support PEBS for this test to return true
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
for(i=0; i < e->num_masks; i++) {
|
|
Packit |
577717 |
int midx;
|
|
Packit |
577717 |
/* check for valid unit mask */
|
|
Packit |
577717 |
if (e->unit_masks[i] >= ne->pme_numasks)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
midx = pfm_nhm_midx2uidx(e->event, e->unit_masks[i]);
|
|
Packit |
577717 |
if (ne->pme_umasks[midx].pme_uflags & PFMLIB_NHM_PEBS)
|
|
Packit |
577717 |
n++;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
return n > 0 && n == e->num_masks;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* Check if event is uncore
|
|
Packit |
577717 |
* return:
|
|
Packit |
577717 |
* PFMLIB_ERR_INVAL: invalid event e
|
|
Packit |
577717 |
* 1 event is uncore
|
|
Packit |
577717 |
* 0 event is not uncore
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int
|
|
Packit |
577717 |
pfm_nhm_is_uncore(pfmlib_event_t *e)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (PFMLIB_INITIALIZED() == 0)
|
|
Packit |
577717 |
return 0;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
if (e == NULL || e->event >= num_pe)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return !!(get_nhm_entry(e->event)->pme_flags & (PFMLIB_NHM_UNC|PFMLIB_NHM_UNC_FIXED));
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
static const char *data_src_encodings[]={
|
|
Packit |
577717 |
/* 0 */ "unknown L3 cache miss",
|
|
Packit |
577717 |
/* 1 */ "minimal latency core cache hit. Request was satisfied by L1 data cache",
|
|
Packit |
577717 |
/* 2 */ "pending core cache HIT. Outstanding core cache miss to same cacheline address already underway",
|
|
Packit |
577717 |
/* 3 */ "data request satisfied by the L2",
|
|
Packit |
577717 |
/* 4 */ "L3 HIT. Local or remote home request that hit L3 in the uncore with no coherency actions required (snooping)",
|
|
Packit |
577717 |
/* 5 */ "L3 HIT. Local or remote home request that hit L3 and was serviced by another core with a cross core snoop where no modified copy was found (clean)",
|
|
Packit |
577717 |
/* 6 */ "L3 HIT. Local or remote home request that hit L3 and was serviced by another core with a cross core snoop where modified copies were found (HITM)",
|
|
Packit |
577717 |
/* 7 */ "reserved",
|
|
Packit |
577717 |
/* 8 */ "L3 MISS. Local homed request that missed L3 and was serviced by forwarded data following a cross package snoop where no modified copy was found (remote home requests are not counted)",
|
|
Packit |
577717 |
/* 9 */ "reserved",
|
|
Packit |
577717 |
/* 10 */ "L3 MISS. Local homed request that missed L3 and was serviced by local DRAM (go to shared state)",
|
|
Packit |
577717 |
/* 11 */ "L3 MISS. Remote homed request that missed L3 and was serviced by remote DRAM (go to shared state)",
|
|
Packit |
577717 |
/* 12 */ "L3 MISS. Local homed request that missed L3 and was serviced by local DRAM (go to exclusive state)",
|
|
Packit |
577717 |
/* 13 */ "L3 MISS. Remote homed request that missed L3 and was serviced by remote DRAM (go to exclusive state)",
|
|
Packit |
577717 |
/* 14 */ "reserved",
|
|
Packit |
577717 |
/* 15 */ "request to uncacheable memory"
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
/*
|
|
Packit |
577717 |
* return data source encoding based on index in val
|
|
Packit |
577717 |
* To be used with PEBS load latency filtering to decode
|
|
Packit |
577717 |
* source of the load miss
|
|
Packit |
577717 |
*/
|
|
Packit |
577717 |
int pfm_nhm_data_src_desc(unsigned int val, char **desc)
|
|
Packit |
577717 |
{
|
|
Packit |
577717 |
if (val > 15 || !desc)
|
|
Packit |
577717 |
return PFMLIB_ERR_INVAL;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
*desc = strdup(data_src_encodings[val]);
|
|
Packit |
577717 |
if (!*desc)
|
|
Packit |
577717 |
return PFMLIB_ERR_NOMEM;
|
|
Packit |
577717 |
|
|
Packit |
577717 |
return PFMLIB_SUCCESS;
|
|
Packit |
577717 |
}
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_pmu_support_t intel_nhm_support={
|
|
Packit |
577717 |
.pmu_name = "Intel Nehalem",
|
|
Packit |
577717 |
.pmu_type = PFMLIB_INTEL_NHM_PMU,
|
|
Packit |
577717 |
.pme_count = 0,/* patched at runtime */
|
|
Packit |
577717 |
.pmc_count = 0,/* patched at runtime */
|
|
Packit |
577717 |
.pmd_count = 0,/* patched at runtime */
|
|
Packit |
577717 |
.num_cnt = 0,/* patched at runtime */
|
|
Packit |
577717 |
.get_event_code = pfm_nhm_get_event_code,
|
|
Packit |
577717 |
.get_event_name = pfm_nhm_get_event_name,
|
|
Packit |
577717 |
.get_event_counters = pfm_nhm_get_event_counters,
|
|
Packit |
577717 |
.dispatch_events = pfm_nhm_dispatch_events,
|
|
Packit |
577717 |
.pmu_detect = pfm_nhm_detect,
|
|
Packit |
577717 |
.pmu_init = pfm_nhm_init,
|
|
Packit |
577717 |
.get_impl_pmcs = pfm_nhm_get_impl_pmcs,
|
|
Packit |
577717 |
.get_impl_pmds = pfm_nhm_get_impl_pmds,
|
|
Packit |
577717 |
.get_impl_counters = pfm_nhm_get_impl_counters,
|
|
Packit |
577717 |
.get_hw_counter_width = pfm_nhm_get_hw_counter_width,
|
|
Packit |
577717 |
.get_event_desc = pfm_nhm_get_event_description,
|
|
Packit |
577717 |
.get_num_event_masks = pfm_nhm_get_num_event_masks,
|
|
Packit |
577717 |
.get_event_mask_name = pfm_nhm_get_event_mask_name,
|
|
Packit |
577717 |
.get_event_mask_code = pfm_nhm_get_event_mask_code,
|
|
Packit |
577717 |
.get_event_mask_desc = pfm_nhm_get_event_mask_desc,
|
|
Packit |
577717 |
.get_cycle_event = pfm_nhm_get_cycle_event,
|
|
Packit |
577717 |
.get_inst_retired_event = pfm_nhm_get_inst_retired
|
|
Packit |
577717 |
};
|
|
Packit |
577717 |
|
|
Packit |
577717 |
pfm_pmu_support_t intel_wsm_support={
|
|
Packit |
577717 |
.pmu_name = "Intel Westmere",
|
|
Packit |
577717 |
.pmu_type = PFMLIB_INTEL_WSM_PMU,
|
|
Packit |
577717 |
.pme_count = 0,/* patched at runtime */
|
|
Packit |
577717 |
.pmc_count = 0,/* patched at runtime */
|
|
Packit |
577717 |
.pmd_count = 0,/* patched at runtime */
|
|
Packit |
577717 |
.num_cnt = 0,/* patched at runtime */
|
|
Packit |
577717 |
.get_event_code = pfm_nhm_get_event_code,
|
|
Packit |
577717 |
.get_event_name = pfm_nhm_get_event_name,
|
|
Packit |
577717 |
.get_event_counters = pfm_nhm_get_event_counters,
|
|
Packit |
577717 |
.dispatch_events = pfm_nhm_dispatch_events,
|
|
Packit |
577717 |
.pmu_detect = pfm_wsm_detect,
|
|
Packit |
577717 |
.pmu_init = pfm_nhm_init,
|
|
Packit |
577717 |
.get_impl_pmcs = pfm_nhm_get_impl_pmcs,
|
|
Packit |
577717 |
.get_impl_pmds = pfm_nhm_get_impl_pmds,
|
|
Packit |
577717 |
.get_impl_counters = pfm_nhm_get_impl_counters,
|
|
Packit |
577717 |
.get_hw_counter_width = pfm_nhm_get_hw_counter_width,
|
|
Packit |
577717 |
.get_event_desc = pfm_nhm_get_event_description,
|
|
Packit |
577717 |
.get_num_event_masks = pfm_nhm_get_num_event_masks,
|
|
Packit |
577717 |
.get_event_mask_name = pfm_nhm_get_event_mask_name,
|
|
Packit |
577717 |
.get_event_mask_code = pfm_nhm_get_event_mask_code,
|
|
Packit |
577717 |
.get_event_mask_desc = pfm_nhm_get_event_mask_desc,
|
|
Packit |
577717 |
.get_cycle_event = pfm_nhm_get_cycle_event,
|
|
Packit |
577717 |
.get_inst_retired_event = pfm_nhm_get_inst_retired
|
|
Packit |
577717 |
};
|