Skip to content

Commit a7e3ed1

Browse files
Andi KleenIngo Molnar
authored andcommitted
perf: Add support for supplementary event registers
Change logs against Andi's original version: - Extends perf_event_attr:config to config{,1,2} (Peter Zijlstra) - Fixed a major event scheduling issue. There cannot be a ref++ on an event that has already done ref++ once and without calling put_constraint() in between. (Stephane Eranian) - Use thread_cpumask for percore allocation. (Lin Ming) - Use MSR names in the extra reg lists. (Lin Ming) - Remove redundant "c = NULL" in intel_percore_constraints - Fix comment of perf_event_attr::config1 Intel Nehalem/Westmere have a special OFFCORE_RESPONSE event that can be used to monitor any offcore accesses from a core. This is a very useful event for various tunings, and it's also needed to implement the generic LLC-* events correctly. Unfortunately this event requires programming a mask in a separate register. And worse this separate register is per core, not per CPU thread. This patch: - Teaches perf_events that OFFCORE_RESPONSE needs extra parameters. The extra parameters are passed by user space in the perf_event_attr::config1 field. - Adds support to the Intel perf_event core to schedule per core resources. This adds fairly generic infrastructure that can be also used for other per core resources. The basic code has is patterned after the similar AMD northbridge constraints code. Thanks to Stephane Eranian who pointed out some problems in the original version and suggested improvements. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1299119690-13991-2-git-send-email-ming.m.lin@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
1 parent 17e3162 commit a7e3ed1

File tree

4 files changed

+276
-2
lines changed

4 files changed

+276
-2
lines changed

arch/x86/include/asm/msr-index.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
#define MSR_IA32_MCG_STATUS 0x0000017a
4848
#define MSR_IA32_MCG_CTL 0x0000017b
4949

50+
#define MSR_OFFCORE_RSP_0 0x000001a6
51+
#define MSR_OFFCORE_RSP_1 0x000001a7
52+
5053
#define MSR_IA32_PEBS_ENABLE 0x000003f1
5154
#define MSR_IA32_DS_AREA 0x00000600
5255
#define MSR_IA32_PERF_CAPABILITIES 0x00000345

arch/x86/kernel/cpu/perf_event.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ struct amd_nb {
9393
struct event_constraint event_constraints[X86_PMC_IDX_MAX];
9494
};
9595

96+
struct intel_percore;
97+
9698
#define MAX_LBR_ENTRIES 16
9799

98100
struct cpu_hw_events {
@@ -127,6 +129,13 @@ struct cpu_hw_events {
127129
struct perf_branch_stack lbr_stack;
128130
struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES];
129131

132+
/*
133+
* Intel percore register state.
134+
* Coordinate shared resources between HT threads.
135+
*/
136+
int percore_used; /* Used by this CPU? */
137+
struct intel_percore *per_core;
138+
130139
/*
131140
* AMD specific bits
132141
*/
@@ -177,6 +186,28 @@ struct cpu_hw_events {
177186
#define for_each_event_constraint(e, c) \
178187
for ((e) = (c); (e)->weight; (e)++)
179188

189+
/*
190+
* Extra registers for specific events.
191+
* Some events need large masks and require external MSRs.
192+
* Define a mapping to these extra registers.
193+
*/
194+
struct extra_reg {
195+
unsigned int event;
196+
unsigned int msr;
197+
u64 config_mask;
198+
u64 valid_mask;
199+
};
200+
201+
#define EVENT_EXTRA_REG(e, ms, m, vm) { \
202+
.event = (e), \
203+
.msr = (ms), \
204+
.config_mask = (m), \
205+
.valid_mask = (vm), \
206+
}
207+
#define INTEL_EVENT_EXTRA_REG(event, msr, vm) \
208+
EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm)
209+
#define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0)
210+
180211
union perf_capabilities {
181212
struct {
182213
u64 lbr_format : 6;
@@ -221,6 +252,7 @@ struct x86_pmu {
221252
void (*put_event_constraints)(struct cpu_hw_events *cpuc,
222253
struct perf_event *event);
223254
struct event_constraint *event_constraints;
255+
struct event_constraint *percore_constraints;
224256
void (*quirks)(void);
225257
int perfctr_second_write;
226258

@@ -249,6 +281,11 @@ struct x86_pmu {
249281
*/
250282
unsigned long lbr_tos, lbr_from, lbr_to; /* MSR base regs */
251283
int lbr_nr; /* hardware stack size */
284+
285+
/*
286+
* Extra registers for events
287+
*/
288+
struct extra_reg *extra_regs;
252289
};
253290

254291
static struct x86_pmu x86_pmu __read_mostly;
@@ -341,6 +378,31 @@ static inline unsigned int x86_pmu_event_addr(int index)
341378
return x86_pmu.perfctr + x86_pmu_addr_offset(index);
342379
}
343380

381+
/*
382+
* Find and validate any extra registers to set up.
383+
*/
384+
static int x86_pmu_extra_regs(u64 config, struct perf_event *event)
385+
{
386+
struct extra_reg *er;
387+
388+
event->hw.extra_reg = 0;
389+
event->hw.extra_config = 0;
390+
391+
if (!x86_pmu.extra_regs)
392+
return 0;
393+
394+
for (er = x86_pmu.extra_regs; er->msr; er++) {
395+
if (er->event != (config & er->config_mask))
396+
continue;
397+
if (event->attr.config1 & ~er->valid_mask)
398+
return -EINVAL;
399+
event->hw.extra_reg = er->msr;
400+
event->hw.extra_config = event->attr.config1;
401+
break;
402+
}
403+
return 0;
404+
}
405+
344406
static atomic_t active_events;
345407
static DEFINE_MUTEX(pmc_reserve_mutex);
346408

@@ -665,6 +727,8 @@ static void x86_pmu_disable(struct pmu *pmu)
665727
static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
666728
u64 enable_mask)
667729
{
730+
if (hwc->extra_reg)
731+
wrmsrl(hwc->extra_reg, hwc->extra_config);
668732
wrmsrl(hwc->config_base, hwc->config | enable_mask);
669733
}
670734

0 commit comments

Comments
 (0)