[PATCH 27/31] perf, x86: Report the arch perfmon events in sysfs

From: Andi Kleen
Date: Tue Oct 02 2012 - 19:51:03 EST


From: Andi Kleen <ak@xxxxxxxxxxxxxxx>

Report all the supported arch perfmon events as event aliases in
/sys/devices/cpu/...

This is needed to use the TSX intx,intx_cp attributes with
symbolic events, at least for these basic events.

Currently cpu/instructions/ doesn't work because instructions
is also a generic event. It works for all events which are not
the same as generic events though.

Probably needs to be fixed in the perf events parser.

Signed-off-by: Andi Kleen <ak@xxxxxxxxxxxxxxx>
---
arch/x86/kernel/cpu/perf_event.c | 7 ++++
arch/x86/kernel/cpu/perf_event.h | 1 +
arch/x86/kernel/cpu/perf_event_intel.c | 56 ++++++++++++++++++++++++++++++++
3 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b0f4edd..a5a5bef 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1309,6 +1309,11 @@ static struct attribute_group x86_pmu_format_group = {
.attrs = NULL,
};

+static struct attribute_group x86_pmu_events_group = {
+ .name = "events",
+ .attrs = NULL,
+};
+
static int __init init_hw_perf_events(void)
{
struct x86_pmu_quirk *quirk;
@@ -1354,6 +1359,7 @@ static int __init init_hw_perf_events(void)

x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
+ x86_pmu_events_group.attrs = x86_pmu.events_attrs;

pr_info("... version: %d\n", x86_pmu.version);
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
@@ -1646,6 +1652,7 @@ static struct attribute_group x86_pmu_attr_group = {
static const struct attribute_group *x86_pmu_attr_groups[] = {
&x86_pmu_attr_group,
&x86_pmu_format_group,
+ &x86_pmu_events_group,
NULL,
};

diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 002ecc9..9b71b34 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -358,6 +358,7 @@ struct x86_pmu {
*/
int attr_rdpmc;
struct attribute **format_attrs;
+ struct attribute **events_attrs;

/*
* CPU Hotplug hooks
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 8b8bb61..4639aad 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -34,6 +34,18 @@ static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
[PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding */
};

+static const char *intel_perfmon_names[PERF_COUNT_HW_MAX] __read_mostly =
+{
+ [PERF_COUNT_HW_CPU_CYCLES] = "cycles",
+ [PERF_COUNT_HW_INSTRUCTIONS] = "instructions",
+ [PERF_COUNT_HW_CACHE_REFERENCES] = "cache-references",
+ [PERF_COUNT_HW_CACHE_MISSES] = "cache-misses",
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = "branches",
+ [PERF_COUNT_HW_BRANCH_MISSES] = "branch-misses",
+ [PERF_COUNT_HW_BUS_CYCLES] = "bus-cycles",
+ [PERF_COUNT_HW_REF_CPU_CYCLES] = "ref-cycles"
+};
+
static struct event_constraint intel_core_event_constraints[] __read_mostly =
{
INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
@@ -1987,6 +1999,48 @@ static __init void intel_nehalem_quirk(void)
}
}

+static struct attribute *intel_arch_events[PERF_COUNT_HW_MAX + 1] __read_mostly;
+
+struct event_attribute {
+ struct device_attribute attr;
+ u64 config;
+};
+
+static struct event_attribute intel_arch_event_attr[PERF_COUNT_HW_MAX];
+
+static ssize_t show_event(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ struct event_attribute *e = container_of(attr, struct event_attribute, attr);
+
+ return sprintf(page, "event=%#llx,umask=%#llx",
+ e->config & 0xff,
+ (e->config >> 8) & 0xff);
+}
+
+static __init void intel_gen_arch_events(void)
+{
+ int j, i;
+
+ j = 0;
+ for_each_clear_bit(i, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) {
+ struct event_attribute *e = intel_arch_event_attr + j;
+ struct device_attribute *d = &e->attr;
+ struct attribute *a = &d->attr;
+ int id = intel_arch_events_map[i].id;
+
+ e->config = intel_perfmon_event_map[id];
+ intel_arch_events[j] = a;
+ a->name = intel_perfmon_names[id];
+ a->mode = 0444;
+ d->show = show_event;
+ j++;
+ }
+ intel_arch_events[j] = NULL;
+ x86_pmu.events_attrs = intel_arch_events;
+}
+
__init int intel_pmu_init(void)
{
union cpuid10_edx edx;
@@ -2030,6 +2084,8 @@ __init int intel_pmu_init(void)

x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters);

+ intel_gen_arch_events();
+
/*
* Quirk: v2 perfmon does not report fixed-purpose events, so
* assume at least 3 events:
--
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/