[PATCH 08/23] perf/x86: Export available PMU counters to sysfs

Zide Chen <[email protected]>
Newsgroups org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
With PMU partitioning support, the set of PMU counters available to a
PMU can vary from the architectural maximum. While this information is
available through CPUID, it is not easily consumable from scripts.

Add two new sysfs ABI files, gp_counters and fixed_counters, under the
PMU caps group to export the available counters. The fixed_counters
file is omitted when the PMU does not support fixed-function counters.

  $ grep . /sys/devices/cpu/caps/*_counters
  /sys/devices/cpu/caps/fixed_counters:0-3
  /sys/devices/cpu/caps/gp_counters:0-7

Suggested-by: Andi Kleen <[email protected]>
Signed-off-by: Zide Chen <[email protected]>
---
 .../sysfs-bus-event_source-devices-caps       |  5 +++
 arch/x86/events/core.c                        | 37 +++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps b/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps
index a5f506f7d481..385ad7a23dd6 100644
--- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps
@@ -22,3 +22,8 @@ Description:
 		of PERF_SAMPLE_BRANCH_COUNTERS, while the "branch_counter_width"
 		exposes the width of each counter. Both of them can be used by
 		the perf tool to parse the logged counters in each branch.
+
+		The "gp_counters" and "fixed_counters" attributes expose the
+		available general-purpose and fixed-function PMU counters as
+		a range list, e.g. "0-7". The "fixed_counters" attribute is
+		omitted if the PMU does not support fixed-function counters.
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index 76af9cfaf0ad..282170f7c1e1 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2814,14 +2814,51 @@ static ssize_t max_precise_show(struct device *cdev,
 
 static DEVICE_ATTR_RO(max_precise);
 
+static ssize_t gp_counters_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct pmu *pmu = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "%*pbl\n", INTEL_PMC_MAX_GENERIC,
+			  hybrid(pmu, cntr_mask));
+}
+
+static ssize_t fixed_counters_show(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct pmu *pmu = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "%*pbl\n", INTEL_PMC_MAX_FIXED,
+			  hybrid(pmu, fixed_cntr_mask));
+}
+
+static DEVICE_ATTR_RO(gp_counters);
+static DEVICE_ATTR_RO(fixed_counters);
+
+static umode_t x86_pmu_caps_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct pmu *pmu = dev_get_drvdata(dev);
+
+	if (attr == &dev_attr_fixed_counters.attr &&
+	    !hybrid(pmu, fixed_cntr_mask64))
+		return 0;
+
+	return attr->mode;
+}
+
 static struct attribute *x86_pmu_caps_attrs[] = {
 	&dev_attr_max_precise.attr,
+	&dev_attr_gp_counters.attr,
+	&dev_attr_fixed_counters.attr,
 	NULL
 };
 
 static struct attribute_group x86_pmu_caps_group __ro_after_init = {
 	.name = "caps",
 	.attrs = x86_pmu_caps_attrs,
+	.is_visible = x86_pmu_caps_is_visible,
 };
 
 static const struct attribute_group *x86_pmu_attr_groups[] = {
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.