Commit 0e45818e authored by Kan Liang's avatar Kan Liang Committed by Peter Zijlstra
Browse files

perf/x86/intel: Support RDPMC metrics clear mode



The new RDPMC enhancement, metrics clear mode, is to clear the
PERF_METRICS-related resources as well as the fixed-function performance
monitoring counter 3 after the read is performed. It is available for
ring 3. The feature is enumerated by the
IA32_PERF_CAPABILITIES.RDPMC_CLEAR_METRICS[bit 19]. To enable the
feature, the IA32_FIXED_CTR_CTRL.METRICS_CLEAR_EN[bit 14] must be set.

Two ways were considered to enable the feature.
- Expose a knob in the sysfs globally. One user may affect the
  measurement of other users when changing the knob. The solution is
  dropped.
- Introduce a new event format, metrics_clear, for the slots event to
  disable/enable the feature only for the current process. Users can
  utilize the feature as needed.
The latter solution is implemented in the patch.

The current KVM doesn't support the perf metrics yet. For
virtualization, the feature can be enabled later separately.

Suggested-by: default avatarAndi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarKan Liang <kan.liang@linux.intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarAndi Kleen <ak@linux.intel.com>
Reviewed-by: default avatarIan Rogers <irogers@google.com>
Link: https://lkml.kernel.org/r/20241211160318.235056-1-kan.liang@linux.intel.com
parent 02c56362
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -2816,6 +2816,9 @@ static void intel_pmu_enable_fixed(struct perf_event *event)
			return;

		idx = INTEL_PMC_IDX_FIXED_SLOTS;

		if (event->attr.config1 & INTEL_TD_CFG_METRIC_CLEAR)
			bits |= INTEL_FIXED_3_METRICS_CLEAR;
	}

	intel_set_masks(event, idx);
@@ -4071,7 +4074,12 @@ static int intel_pmu_hw_config(struct perf_event *event)
	 * is used in a metrics group, it too cannot support sampling.
	 */
	if (intel_pmu_has_cap(event, PERF_CAP_METRICS_IDX) && is_topdown_event(event)) {
		if (event->attr.config1 || event->attr.config2)
		/* The metrics_clear can only be set for the slots event */
		if (event->attr.config1 &&
		    (!is_slots_event(event) || (event->attr.config1 & ~INTEL_TD_CFG_METRIC_CLEAR)))
			return -EINVAL;

		if (event->attr.config2)
			return -EINVAL;

		/*
@@ -4680,6 +4688,8 @@ PMU_FORMAT_ATTR(in_tx, "config:32" );
PMU_FORMAT_ATTR(in_tx_cp, "config:33"	);
PMU_FORMAT_ATTR(eq,	"config:36"	); /* v6 + */

PMU_FORMAT_ATTR(metrics_clear,	"config1:0"); /* PERF_CAPABILITIES.RDPMC_METRICS_CLEAR */

static ssize_t umask2_show(struct device *dev,
			   struct device_attribute *attr,
			   char *page)
@@ -4699,6 +4709,7 @@ static struct device_attribute format_attr_umask2 =
static struct attribute *format_evtsel_ext_attrs[] = {
	&format_attr_umask2.attr,
	&format_attr_eq.attr,
	&format_attr_metrics_clear.attr,
	NULL
};

@@ -4723,6 +4734,13 @@ evtsel_ext_is_visible(struct kobject *kobj, struct attribute *attr, int i)
	if (i == 1)
		return (mask & ARCH_PERFMON_EVENTSEL_EQ) ? attr->mode : 0;

	/* PERF_CAPABILITIES.RDPMC_METRICS_CLEAR */
	if (i == 2) {
		union perf_capabilities intel_cap = hybrid(dev_get_drvdata(dev), intel_cap);

		return intel_cap.rdpmc_metrics_clear ? attr->mode : 0;
	}

	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -624,6 +624,7 @@ union perf_capabilities {
		u64	pebs_output_pt_available:1;
		u64	pebs_timing_info:1;
		u64	anythread_deprecated:1;
		u64	rdpmc_metrics_clear:1;
	};
	u64	capabilities;
};
+4 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#define INTEL_FIXED_0_USER				(1ULL << 1)
#define INTEL_FIXED_0_ANYTHREAD			(1ULL << 2)
#define INTEL_FIXED_0_ENABLE_PMI			(1ULL << 3)
#define INTEL_FIXED_3_METRICS_CLEAR			(1ULL << 2)

#define HSW_IN_TX					(1ULL << 32)
#define HSW_IN_TX_CHECKPOINTED				(1ULL << 33)
@@ -372,6 +373,9 @@ static inline bool use_fixed_pseudo_encoding(u64 code)
#define INTEL_TD_METRIC_MAX			INTEL_TD_METRIC_MEM_BOUND
#define INTEL_TD_METRIC_NUM			8

#define INTEL_TD_CFG_METRIC_CLEAR_BIT		0
#define INTEL_TD_CFG_METRIC_CLEAR		BIT_ULL(INTEL_TD_CFG_METRIC_CLEAR_BIT)

static inline bool is_metric_idx(int idx)
{
	return (unsigned)(idx - INTEL_PMC_IDX_METRIC_BASE) < INTEL_TD_METRIC_NUM;