Commit a193cc75 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'perf-core-2023-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf events updates from Ingo Molnar:

 - Rework & fix the event forwarding logic by extending the core
   interface.

   This fixes AMD PMU events that have to be forwarded from the
   core PMU to the IBS PMU.

 - Add self-tests to test AMD IBS invocation via core PMU events

 - Clean up Intel FixCntrCtl MSR encoding & handling

* tag 'perf-core-2023-06-27' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf: Re-instate the linear PMU search
  perf/x86/intel: Define bit macros for FixCntrCtl MSR
  perf test: Add selftest to test IBS invocation via core pmu events
  perf/core: Remove pmu linear searching code
  perf/ibs: Fix interface via core pmu events
  perf/core: Rework forwarding of {task|cpu}-clock events
parents bc6cb4d5 228020b4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -374,7 +374,7 @@ static int amd_pmu_hw_config(struct perf_event *event)

	/* pass precise event sampling to ibs: */
	if (event->attr.precise_ip && get_ibs_caps())
		return -ENOENT;
		return forward_event_to_ibs(event);

	if (has_branch_stack(event) && !x86_pmu.lbr_nr)
		return -EOPNOTSUPP;
+26 −27
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ static struct perf_ibs *get_ibs_pmu(int type)
}

/*
 * Use IBS for precise event sampling:
 * core pmu config -> IBS config
 *
 *  perf record -a -e cpu-cycles:p ...    # use ibs op counting cycle count
 *  perf record -a -e r076:p ...          # same as -e cpu-cycles:p
@@ -199,25 +199,9 @@ static struct perf_ibs *get_ibs_pmu(int type)
 * IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl,
 * MSRC001_1033) is used to select either cycle or micro-ops counting
 * mode.
 *
 * The rip of IBS samples has skid 0. Thus, IBS supports precise
 * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
 * rip is invalid when IBS was not able to record the rip correctly.
 * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
 *
 */
static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
static int core_pmu_ibs_config(struct perf_event *event, u64 *config)
{
	switch (event->attr.precise_ip) {
	case 0:
		return -ENOENT;
	case 1:
	case 2:
		break;
	default:
		return -EOPNOTSUPP;
	}

	switch (event->attr.type) {
	case PERF_TYPE_HARDWARE:
		switch (event->attr.config) {
@@ -243,22 +227,37 @@ static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
	return -EOPNOTSUPP;
}

/*
 * The rip of IBS samples has skid 0. Thus, IBS supports precise
 * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
 * rip is invalid when IBS was not able to record the rip correctly.
 * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
 */
int forward_event_to_ibs(struct perf_event *event)
{
	u64 config = 0;

	if (!event->attr.precise_ip || event->attr.precise_ip > 2)
		return -EOPNOTSUPP;

	if (!core_pmu_ibs_config(event, &config)) {
		event->attr.type = perf_ibs_op.pmu.type;
		event->attr.config = config;
	}
	return -ENOENT;
}

static int perf_ibs_init(struct perf_event *event)
{
	struct hw_perf_event *hwc = &event->hw;
	struct perf_ibs *perf_ibs;
	u64 max_cnt, config;
	int ret;

	perf_ibs = get_ibs_pmu(event->attr.type);
	if (perf_ibs) {
	if (!perf_ibs)
		return -ENOENT;

	config = event->attr.config;
	} else {
		perf_ibs = &perf_ibs_op;
		ret = perf_ibs_precise_event(event, &config);
		if (ret)
			return ret;
	}

	if (event->pmu != &perf_ibs->pmu)
		return -ENOENT;
+9 −9
Original line number Diff line number Diff line
@@ -2461,7 +2461,7 @@ static void intel_pmu_disable_fixed(struct perf_event *event)

	intel_clear_masks(event, idx);

	mask = 0xfULL << ((idx - INTEL_PMC_IDX_FIXED) * 4);
	mask = intel_fixed_bits_by_idx(idx - INTEL_PMC_IDX_FIXED, INTEL_FIXED_BITS_MASK);
	cpuc->fixed_ctrl_val &= ~mask;
}

@@ -2760,25 +2760,25 @@ static void intel_pmu_enable_fixed(struct perf_event *event)
	 * if requested:
	 */
	if (!event->attr.precise_ip)
		bits |= 0x8;
		bits |= INTEL_FIXED_0_ENABLE_PMI;
	if (hwc->config & ARCH_PERFMON_EVENTSEL_USR)
		bits |= 0x2;
		bits |= INTEL_FIXED_0_USER;
	if (hwc->config & ARCH_PERFMON_EVENTSEL_OS)
		bits |= 0x1;
		bits |= INTEL_FIXED_0_KERNEL;

	/*
	 * ANY bit is supported in v3 and up
	 */
	if (x86_pmu.version > 2 && hwc->config & ARCH_PERFMON_EVENTSEL_ANY)
		bits |= 0x4;
		bits |= INTEL_FIXED_0_ANYTHREAD;

	idx -= INTEL_PMC_IDX_FIXED;
	bits <<= (idx * 4);
	mask = 0xfULL << (idx * 4);
	bits = intel_fixed_bits_by_idx(idx, bits);
	mask = intel_fixed_bits_by_idx(idx, INTEL_FIXED_BITS_MASK);

	if (x86_pmu.intel_cap.pebs_baseline && event->attr.precise_ip) {
		bits |= ICL_FIXED_0_ADAPTIVE << (idx * 4);
		mask |= ICL_FIXED_0_ADAPTIVE << (idx * 4);
		bits |= intel_fixed_bits_by_idx(idx, ICL_FIXED_0_ADAPTIVE);
		mask |= intel_fixed_bits_by_idx(idx, ICL_FIXED_0_ADAPTIVE);
	}

	cpuc->fixed_ctrl_val &= ~mask;
+12 −0
Original line number Diff line number Diff line
@@ -32,11 +32,21 @@
#define ARCH_PERFMON_EVENTSEL_INV			(1ULL << 23)
#define ARCH_PERFMON_EVENTSEL_CMASK			0xFF000000ULL

#define INTEL_FIXED_BITS_MASK				0xFULL
#define INTEL_FIXED_BITS_STRIDE			4
#define INTEL_FIXED_0_KERNEL				(1ULL << 0)
#define INTEL_FIXED_0_USER				(1ULL << 1)
#define INTEL_FIXED_0_ANYTHREAD			(1ULL << 2)
#define INTEL_FIXED_0_ENABLE_PMI			(1ULL << 3)

#define HSW_IN_TX					(1ULL << 32)
#define HSW_IN_TX_CHECKPOINTED				(1ULL << 33)
#define ICL_EVENTSEL_ADAPTIVE				(1ULL << 34)
#define ICL_FIXED_0_ADAPTIVE				(1ULL << 32)

#define intel_fixed_bits_by_idx(_idx, _bits)			\
	((_bits) << ((_idx) * INTEL_FIXED_BITS_STRIDE))

#define AMD64_EVENTSEL_INT_CORE_ENABLE			(1ULL << 36)
#define AMD64_EVENTSEL_GUESTONLY			(1ULL << 40)
#define AMD64_EVENTSEL_HOSTONLY				(1ULL << 41)
@@ -478,8 +488,10 @@ struct pebs_xmm {

#ifdef CONFIG_X86_LOCAL_APIC
extern u32 get_ibs_caps(void);
extern int forward_event_to_ibs(struct perf_event *event);
#else
static inline u32 get_ibs_caps(void) { return 0; }
static inline int forward_event_to_ibs(struct perf_event *event) { return -ENOENT; }
#endif

#ifdef CONFIG_PERF_EVENTS
+10 −0
Original line number Diff line number Diff line
@@ -295,6 +295,8 @@ struct perf_event_pmu_context;

struct perf_output_handle;

#define PMU_NULL_DEV	((void *)(~0UL))

/**
 * struct pmu - generic performance monitoring unit
 */
@@ -827,6 +829,14 @@ struct perf_event {
	void *security;
#endif
	struct list_head		sb_list;

	/*
	 * Certain events gets forwarded to another pmu internally by over-
	 * writing kernel copy of event->attr.type without user being aware
	 * of it. event->orig_type contains original 'type' requested by
	 * user.
	 */
	__u32				orig_type;
#endif /* CONFIG_PERF_EVENTS */
};

Loading