[PATCH v1 2/2] x86/perf: Export some PMU attributes in caps

2017-08-22 Thread Andi Kleen
From: Andi Kleen 

It can be difficult to figure out for user programs what features
the x86 cpu pmu driver actually supports. Currently it requires
grepping in dmesg, but dmesg is not always available.

This adds a caps directory to /sys/devices/cpu, similar
to the caps already used on intel_pt, which can be used
to discover the available capabilities cleanly.

Currently three capabilities are defined:

- pmu_name
Underlying CPU name known to the driver
- max_precise
Max precise level supported
- branches
Known depth of LBR.

Example:

% grep . /sys/devices/cpu/caps/*
/sys/devices/cpu/caps/branches:32
/sys/devices/cpu/caps/max_precise:3
/sys/devices/cpu/caps/pmu_name:skylake
%

Signed-off-by: Andi Kleen 
---
 arch/x86/events/core.c   | 34 +++
 arch/x86/events/intel/core.c | 66 +++-
 arch/x86/events/perf_event.h |  3 ++
 3 files changed, 91 insertions(+), 12 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index af12e294caed..d5f98095a155 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -487,22 +487,28 @@ static inline int precise_br_compat(struct perf_event 
*event)
return m == b;
 }
 
-int x86_pmu_hw_config(struct perf_event *event)
+int x86_pmu_max_precise(void)
 {
-   if (event->attr.precise_ip) {
-   int precise = 0;
+   int precise = 0;
+
+   /* Support for constant skid */
+   if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
+   precise++;
 
-   /* Support for constant skid */
-   if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
+   /* Support for IP fixup */
+   if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
precise++;
 
-   /* Support for IP fixup */
-   if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 
2)
-   precise++;
+   if (x86_pmu.pebs_prec_dist)
+   precise++;
+   }
+   return precise;
+}
 
-   if (x86_pmu.pebs_prec_dist)
-   precise++;
-   }
+int x86_pmu_hw_config(struct perf_event *event)
+{
+   if (event->attr.precise_ip) {
+   int precise = x86_pmu_max_precise();
 
if (event->attr.precise_ip > precise)
return -EOPNOTSUPP;
@@ -1752,6 +1758,10 @@ ssize_t x86_event_sysfs_show(char *page, u64 config, u64 
event)
 
 static struct attribute_group x86_pmu_attr_group;
 
+static struct attribute_group x86_pmu_caps_group = {
+   .name = "caps",
+};
+
 static int __init init_hw_perf_events(void)
 {
struct x86_pmu_quirk *quirk;
@@ -1798,6 +1808,7 @@ static int __init init_hw_perf_events(void)
   0, x86_pmu.num_counters, 0, 0);
 
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
+   x86_pmu_caps_group.attrs = x86_pmu.caps_attrs;
 
if (x86_pmu.event_attrs)
x86_pmu_events_group.attrs = x86_pmu.event_attrs;
@@ -2217,6 +2228,7 @@ static const struct attribute_group 
*x86_pmu_attr_groups[] = {
_pmu_attr_group,
_pmu_format_group,
_pmu_events_group,
+   _pmu_caps_group,
NULL,
 };
 
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 82faeed30135..a46bf78c0105 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3795,6 +3795,46 @@ static ssize_t freeze_on_smi_store(struct device *cdev,
 
 static DEVICE_ATTR_RW(freeze_on_smi);
 
+static ssize_t branches_show(struct device *cdev,
+struct device_attribute *attr,
+char *buf)
+{
+   return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu.lbr_nr);
+}
+
+static DEVICE_ATTR_RO(branches);
+
+static struct attribute *lbr_attrs[] = {
+   _attr_branches.attr,
+   NULL
+};
+
+static char pmu_name_str[30];
+
+static ssize_t pmu_name_show(struct device *cdev,
+struct device_attribute *attr,
+char *buf)
+{
+   return snprintf(buf, PAGE_SIZE, "%s\n", pmu_name_str);
+}
+
+static DEVICE_ATTR_RO(pmu_name);
+
+static ssize_t max_precise_show(struct device *cdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+   return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu_max_precise());
+}
+
+static DEVICE_ATTR_RO(max_precise);
+
+static struct attribute *intel_pmu_caps_attrs[] = {
+   _attr_pmu_name.attr,
+   _attr_max_precise.attr,
+   NULL
+};
+
 static struct attribute *intel_pmu_attrs[] = {
_attr_freeze_on_smi.attr,
NULL,
@@ -3810,6 +3850,7 @@ __init int intel_pmu_init(void)
struct extra_reg *er;
int version, i;
struct attribute **extra_attr = NULL;
+   char *name;
 

[PATCH v1 2/2] x86/perf: Export some PMU attributes in caps

2017-08-22 Thread Andi Kleen
From: Andi Kleen 

It can be difficult to figure out for user programs what features
the x86 cpu pmu driver actually supports. Currently it requires
grepping in dmesg, but dmesg is not always available.

This adds a caps directory to /sys/devices/cpu, similar
to the caps already used on intel_pt, which can be used
to discover the available capabilities cleanly.

Currently three capabilities are defined:

- pmu_name
Underlying CPU name known to the driver
- max_precise
Max precise level supported
- branches
Known depth of LBR.

Example:

% grep . /sys/devices/cpu/caps/*
/sys/devices/cpu/caps/branches:32
/sys/devices/cpu/caps/max_precise:3
/sys/devices/cpu/caps/pmu_name:skylake
%

Signed-off-by: Andi Kleen 
---
 arch/x86/events/core.c   | 34 +++
 arch/x86/events/intel/core.c | 66 +++-
 arch/x86/events/perf_event.h |  3 ++
 3 files changed, 91 insertions(+), 12 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index af12e294caed..d5f98095a155 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -487,22 +487,28 @@ static inline int precise_br_compat(struct perf_event 
*event)
return m == b;
 }
 
-int x86_pmu_hw_config(struct perf_event *event)
+int x86_pmu_max_precise(void)
 {
-   if (event->attr.precise_ip) {
-   int precise = 0;
+   int precise = 0;
+
+   /* Support for constant skid */
+   if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
+   precise++;
 
-   /* Support for constant skid */
-   if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
+   /* Support for IP fixup */
+   if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
precise++;
 
-   /* Support for IP fixup */
-   if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 
2)
-   precise++;
+   if (x86_pmu.pebs_prec_dist)
+   precise++;
+   }
+   return precise;
+}
 
-   if (x86_pmu.pebs_prec_dist)
-   precise++;
-   }
+int x86_pmu_hw_config(struct perf_event *event)
+{
+   if (event->attr.precise_ip) {
+   int precise = x86_pmu_max_precise();
 
if (event->attr.precise_ip > precise)
return -EOPNOTSUPP;
@@ -1752,6 +1758,10 @@ ssize_t x86_event_sysfs_show(char *page, u64 config, u64 
event)
 
 static struct attribute_group x86_pmu_attr_group;
 
+static struct attribute_group x86_pmu_caps_group = {
+   .name = "caps",
+};
+
 static int __init init_hw_perf_events(void)
 {
struct x86_pmu_quirk *quirk;
@@ -1798,6 +1808,7 @@ static int __init init_hw_perf_events(void)
   0, x86_pmu.num_counters, 0, 0);
 
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
+   x86_pmu_caps_group.attrs = x86_pmu.caps_attrs;
 
if (x86_pmu.event_attrs)
x86_pmu_events_group.attrs = x86_pmu.event_attrs;
@@ -2217,6 +2228,7 @@ static const struct attribute_group 
*x86_pmu_attr_groups[] = {
_pmu_attr_group,
_pmu_format_group,
_pmu_events_group,
+   _pmu_caps_group,
NULL,
 };
 
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 82faeed30135..a46bf78c0105 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3795,6 +3795,46 @@ static ssize_t freeze_on_smi_store(struct device *cdev,
 
 static DEVICE_ATTR_RW(freeze_on_smi);
 
+static ssize_t branches_show(struct device *cdev,
+struct device_attribute *attr,
+char *buf)
+{
+   return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu.lbr_nr);
+}
+
+static DEVICE_ATTR_RO(branches);
+
+static struct attribute *lbr_attrs[] = {
+   _attr_branches.attr,
+   NULL
+};
+
+static char pmu_name_str[30];
+
+static ssize_t pmu_name_show(struct device *cdev,
+struct device_attribute *attr,
+char *buf)
+{
+   return snprintf(buf, PAGE_SIZE, "%s\n", pmu_name_str);
+}
+
+static DEVICE_ATTR_RO(pmu_name);
+
+static ssize_t max_precise_show(struct device *cdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+   return snprintf(buf, PAGE_SIZE, "%d\n", x86_pmu_max_precise());
+}
+
+static DEVICE_ATTR_RO(max_precise);
+
+static struct attribute *intel_pmu_caps_attrs[] = {
+   _attr_pmu_name.attr,
+   _attr_max_precise.attr,
+   NULL
+};
+
 static struct attribute *intel_pmu_attrs[] = {
_attr_freeze_on_smi.attr,
NULL,
@@ -3810,6 +3850,7 @@ __init int intel_pmu_init(void)
struct extra_reg *er;
int version, i;
struct attribute **extra_attr = NULL;
+   char *name;
 
if (!cpu_has(_cpu_data,