提交 b4cdc5c2 编写于 作者: P Peter Zijlstra 提交者: Ingo Molnar

perf, x86: Fix up the ANY flag stuff

Stephane noticed that the ANY flag was in generic arch code, and Cyrill
reported that it broke the P4 code.

Solve this by merging x86_pmu::raw_event into x86_pmu::hw_config and
provide intel_pmu and amd_pmu specific versions of this callback.

The intel_pmu one deals with the ANY flag, the amd_pmu adds the few extra
event bits AMD64 has.
Reported-by: NStephane Eranian <eranian@google.com>
Reported-by: NCyrill Gorcunov <gorcunov@gmail.com>
Acked-by: NRobert Richter <robert.richter@amd.com>
Acked-by: NCyrill Gorcunov <gorcunov@gmail.com>
Acked-by: NStephane Eranian <eranian@google.com>
Signed-off-by: NPeter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1269968113.5258.442.camel@laptop>
Signed-off-by: NIngo Molnar <mingo@elte.hu>
上级 a098f448
...@@ -196,12 +196,11 @@ struct x86_pmu { ...@@ -196,12 +196,11 @@ struct x86_pmu {
void (*enable_all)(int added); void (*enable_all)(int added);
void (*enable)(struct perf_event *); void (*enable)(struct perf_event *);
void (*disable)(struct perf_event *); void (*disable)(struct perf_event *);
int (*hw_config)(struct perf_event_attr *attr, struct hw_perf_event *hwc); int (*hw_config)(struct perf_event *event);
int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign); int (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
unsigned eventsel; unsigned eventsel;
unsigned perfctr; unsigned perfctr;
u64 (*event_map)(int); u64 (*event_map)(int);
u64 (*raw_event)(u64);
int max_events; int max_events;
int num_counters; int num_counters;
int num_counters_fixed; int num_counters_fixed;
...@@ -426,28 +425,26 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr) ...@@ -426,28 +425,26 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
return 0; return 0;
} }
static int x86_hw_config(struct perf_event_attr *attr, struct hw_perf_event *hwc) static int x86_pmu_hw_config(struct perf_event *event)
{ {
/* /*
* Generate PMC IRQs: * Generate PMC IRQs:
* (keep 'enabled' bit clear for now) * (keep 'enabled' bit clear for now)
*/ */
hwc->config = ARCH_PERFMON_EVENTSEL_INT; event->hw.config = ARCH_PERFMON_EVENTSEL_INT;
/* /*
* Count user and OS events unless requested not to * Count user and OS events unless requested not to
*/ */
if (!attr->exclude_user) if (!event->attr.exclude_user)
hwc->config |= ARCH_PERFMON_EVENTSEL_USR; event->hw.config |= ARCH_PERFMON_EVENTSEL_USR;
if (!attr->exclude_kernel) if (!event->attr.exclude_kernel)
hwc->config |= ARCH_PERFMON_EVENTSEL_OS; event->hw.config |= ARCH_PERFMON_EVENTSEL_OS;
return 0; if (event->attr.type == PERF_TYPE_RAW)
} event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
static u64 x86_pmu_raw_event(u64 hw_event) return 0;
{
return hw_event & X86_RAW_EVENT_MASK;
} }
/* /*
...@@ -489,7 +486,7 @@ static int __hw_perf_event_init(struct perf_event *event) ...@@ -489,7 +486,7 @@ static int __hw_perf_event_init(struct perf_event *event)
hwc->last_tag = ~0ULL; hwc->last_tag = ~0ULL;
/* Processor specifics */ /* Processor specifics */
err = x86_pmu.hw_config(attr, hwc); err = x86_pmu.hw_config(event);
if (err) if (err)
return err; return err;
...@@ -508,16 +505,8 @@ static int __hw_perf_event_init(struct perf_event *event) ...@@ -508,16 +505,8 @@ static int __hw_perf_event_init(struct perf_event *event)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
/* if (attr->type == PERF_TYPE_RAW)
* Raw hw_event type provide the config in the hw_event structure
*/
if (attr->type == PERF_TYPE_RAW) {
hwc->config |= x86_pmu.raw_event(attr->config);
if ((hwc->config & ARCH_PERFMON_EVENTSEL_ANY) &&
perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
return -EACCES;
return 0; return 0;
}
if (attr->type == PERF_TYPE_HW_CACHE) if (attr->type == PERF_TYPE_HW_CACHE)
return set_ext_hw_attr(hwc, attr); return set_ext_hw_attr(hwc, attr);
......
...@@ -111,9 +111,19 @@ static u64 amd_pmu_event_map(int hw_event) ...@@ -111,9 +111,19 @@ static u64 amd_pmu_event_map(int hw_event)
return amd_perfmon_event_map[hw_event]; return amd_perfmon_event_map[hw_event];
} }
static u64 amd_pmu_raw_event(u64 hw_event) static int amd_pmu_hw_config(struct perf_event *event)
{ {
return hw_event & AMD64_RAW_EVENT_MASK; int ret = x86_pmu_hw_config(event);
if (ret)
return ret;
if (event->attr.type != PERF_TYPE_RAW)
return 0;
event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
return 0;
} }
/* /*
...@@ -365,12 +375,11 @@ static __initconst struct x86_pmu amd_pmu = { ...@@ -365,12 +375,11 @@ static __initconst struct x86_pmu amd_pmu = {
.enable_all = x86_pmu_enable_all, .enable_all = x86_pmu_enable_all,
.enable = x86_pmu_enable_event, .enable = x86_pmu_enable_event,
.disable = x86_pmu_disable_event, .disable = x86_pmu_disable_event,
.hw_config = x86_hw_config, .hw_config = amd_pmu_hw_config,
.schedule_events = x86_schedule_events, .schedule_events = x86_schedule_events,
.eventsel = MSR_K7_EVNTSEL0, .eventsel = MSR_K7_EVNTSEL0,
.perfctr = MSR_K7_PERFCTR0, .perfctr = MSR_K7_PERFCTR0,
.event_map = amd_pmu_event_map, .event_map = amd_pmu_event_map,
.raw_event = amd_pmu_raw_event,
.max_events = ARRAY_SIZE(amd_perfmon_event_map), .max_events = ARRAY_SIZE(amd_perfmon_event_map),
.num_counters = 4, .num_counters = 4,
.cntval_bits = 48, .cntval_bits = 48,
......
...@@ -758,6 +758,30 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event ...@@ -758,6 +758,30 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event
return x86_get_event_constraints(cpuc, event); return x86_get_event_constraints(cpuc, event);
} }
static int intel_pmu_hw_config(struct perf_event *event)
{
int ret = x86_pmu_hw_config(event);
if (ret)
return ret;
if (event->attr.type != PERF_TYPE_RAW)
return 0;
if (!(event->attr.config & ARCH_PERFMON_EVENTSEL_ANY))
return 0;
if (x86_pmu.version < 3)
return -EINVAL;
if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
return -EACCES;
event->hw.config |= ARCH_PERFMON_EVENTSEL_ANY;
return 0;
}
static __initconst struct x86_pmu core_pmu = { static __initconst struct x86_pmu core_pmu = {
.name = "core", .name = "core",
.handle_irq = x86_pmu_handle_irq, .handle_irq = x86_pmu_handle_irq,
...@@ -765,12 +789,11 @@ static __initconst struct x86_pmu core_pmu = { ...@@ -765,12 +789,11 @@ static __initconst struct x86_pmu core_pmu = {
.enable_all = x86_pmu_enable_all, .enable_all = x86_pmu_enable_all,
.enable = x86_pmu_enable_event, .enable = x86_pmu_enable_event,
.disable = x86_pmu_disable_event, .disable = x86_pmu_disable_event,
.hw_config = x86_hw_config, .hw_config = x86_pmu_hw_config,
.schedule_events = x86_schedule_events, .schedule_events = x86_schedule_events,
.eventsel = MSR_ARCH_PERFMON_EVENTSEL0, .eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
.perfctr = MSR_ARCH_PERFMON_PERFCTR0, .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
.event_map = intel_pmu_event_map, .event_map = intel_pmu_event_map,
.raw_event = x86_pmu_raw_event,
.max_events = ARRAY_SIZE(intel_perfmon_event_map), .max_events = ARRAY_SIZE(intel_perfmon_event_map),
.apic = 1, .apic = 1,
/* /*
...@@ -804,12 +827,11 @@ static __initconst struct x86_pmu intel_pmu = { ...@@ -804,12 +827,11 @@ static __initconst struct x86_pmu intel_pmu = {
.enable_all = intel_pmu_enable_all, .enable_all = intel_pmu_enable_all,
.enable = intel_pmu_enable_event, .enable = intel_pmu_enable_event,
.disable = intel_pmu_disable_event, .disable = intel_pmu_disable_event,
.hw_config = x86_hw_config, .hw_config = intel_pmu_hw_config,
.schedule_events = x86_schedule_events, .schedule_events = x86_schedule_events,
.eventsel = MSR_ARCH_PERFMON_EVENTSEL0, .eventsel = MSR_ARCH_PERFMON_EVENTSEL0,
.perfctr = MSR_ARCH_PERFMON_PERFCTR0, .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
.event_map = intel_pmu_event_map, .event_map = intel_pmu_event_map,
.raw_event = x86_pmu_raw_event,
.max_events = ARRAY_SIZE(intel_perfmon_event_map), .max_events = ARRAY_SIZE(intel_perfmon_event_map),
.apic = 1, .apic = 1,
/* /*
......
...@@ -419,20 +419,7 @@ static u64 p4_pmu_event_map(int hw_event) ...@@ -419,20 +419,7 @@ static u64 p4_pmu_event_map(int hw_event)
return config; return config;
} }
/* static int p4_hw_config(struct perf_event *event)
* We don't control raw events so it's up to the caller
* to pass sane values (and we don't count the thread number
* on HT machine but allow HT-compatible specifics to be
* passed on)
*/
static u64 p4_pmu_raw_event(u64 hw_event)
{
return hw_event &
(p4_config_pack_escr(P4_ESCR_MASK_HT) |
p4_config_pack_cccr(P4_CCCR_MASK_HT));
}
static int p4_hw_config(struct perf_event_attr *attr, struct hw_perf_event *hwc)
{ {
int cpu = raw_smp_processor_id(); int cpu = raw_smp_processor_id();
u32 escr, cccr; u32 escr, cccr;
...@@ -444,11 +431,29 @@ static int p4_hw_config(struct perf_event_attr *attr, struct hw_perf_event *hwc) ...@@ -444,11 +431,29 @@ static int p4_hw_config(struct perf_event_attr *attr, struct hw_perf_event *hwc)
*/ */
cccr = p4_default_cccr_conf(cpu); cccr = p4_default_cccr_conf(cpu);
escr = p4_default_escr_conf(cpu, attr->exclude_kernel, attr->exclude_user); escr = p4_default_escr_conf(cpu, event->attr.exclude_kernel,
hwc->config = p4_config_pack_escr(escr) | p4_config_pack_cccr(cccr); event->attr.exclude_user);
event->hw.config = p4_config_pack_escr(escr) |
p4_config_pack_cccr(cccr);
if (p4_ht_active() && p4_ht_thread(cpu)) if (p4_ht_active() && p4_ht_thread(cpu))
hwc->config = p4_set_ht_bit(hwc->config); event->hw.config = p4_set_ht_bit(event->hw.config);
if (event->attr.type != PERF_TYPE_RAW)
return 0;
/*
* We don't control raw events so it's up to the caller
* to pass sane values (and we don't count the thread number
* on HT machine but allow HT-compatible specifics to be
* passed on)
*
* XXX: HT wide things should check perf_paranoid_cpu() &&
* CAP_SYS_ADMIN
*/
event->hw.config |= event->attr.config &
(p4_config_pack_escr(P4_ESCR_MASK_HT) |
p4_config_pack_cccr(P4_CCCR_MASK_HT));
return 0; return 0;
} }
...@@ -785,7 +790,6 @@ static __initconst struct x86_pmu p4_pmu = { ...@@ -785,7 +790,6 @@ static __initconst struct x86_pmu p4_pmu = {
.eventsel = MSR_P4_BPU_CCCR0, .eventsel = MSR_P4_BPU_CCCR0,
.perfctr = MSR_P4_BPU_PERFCTR0, .perfctr = MSR_P4_BPU_PERFCTR0,
.event_map = p4_pmu_event_map, .event_map = p4_pmu_event_map,
.raw_event = p4_pmu_raw_event,
.max_events = ARRAY_SIZE(p4_general_events), .max_events = ARRAY_SIZE(p4_general_events),
.get_event_constraints = x86_get_event_constraints, .get_event_constraints = x86_get_event_constraints,
/* /*
......
...@@ -91,12 +91,11 @@ static __initconst struct x86_pmu p6_pmu = { ...@@ -91,12 +91,11 @@ static __initconst struct x86_pmu p6_pmu = {
.enable_all = p6_pmu_enable_all, .enable_all = p6_pmu_enable_all,
.enable = p6_pmu_enable_event, .enable = p6_pmu_enable_event,
.disable = p6_pmu_disable_event, .disable = p6_pmu_disable_event,
.hw_config = x86_hw_config, .hw_config = x86_pmu_hw_config,
.schedule_events = x86_schedule_events, .schedule_events = x86_schedule_events,
.eventsel = MSR_P6_EVNTSEL0, .eventsel = MSR_P6_EVNTSEL0,
.perfctr = MSR_P6_PERFCTR0, .perfctr = MSR_P6_PERFCTR0,
.event_map = p6_pmu_event_map, .event_map = p6_pmu_event_map,
.raw_event = x86_pmu_raw_event,
.max_events = ARRAY_SIZE(p6_perfmon_event_map), .max_events = ARRAY_SIZE(p6_perfmon_event_map),
.apic = 1, .apic = 1,
.max_period = (1ULL << 31) - 1, .max_period = (1ULL << 31) - 1,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册